Skip to content

Commit

Permalink
Make member cache updates work like user cache updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Th3-M4jor committed Jun 23, 2024
1 parent 38b9437 commit 6f86805
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 7 deletions.
13 changes: 11 additions & 2 deletions lib/nostrum/cache/member_cache/ets.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ defmodule Nostrum.Cache.MemberCache.ETS do
@table_name :nostrum_guild_members

alias Nostrum.Cache.MemberCache
alias Nostrum.Snowflake
alias Nostrum.Struct.Guild
alias Nostrum.Struct.Guild.Member
alias Nostrum.Util
Expand Down Expand Up @@ -76,14 +77,22 @@ defmodule Nostrum.Cache.MemberCache.ETS do
@impl MemberCache
@spec update(Guild.id(), map()) :: {Guild.id(), Member.t() | nil, Member.t()}
def update(guild_id, payload) do
new_member = Util.cast(payload, {:struct, Member})
# Force keys to be atoms before casting just to simplify finding the user_id
# because of the atom/string ambiguity issues from the gateway that Discord
# won't fix.

case :ets.lookup(@table_name, {guild_id, new_member.user_id}) do
member_payload = Map.new(payload, fn {k, v} -> {Util.maybe_to_atom(k), v} end)

member_id = Util.cast(member_payload[:user][:id], Snowflake)

case :ets.lookup(@table_name, {guild_id, member_id}) do
[{key, old_member}] ->
new_member = Member.to_struct(member_payload, old_member)
true = :ets.update_element(@table_name, key, {2, new_member})
{guild_id, old_member, new_member}

[] ->
new_member = Util.cast(member_payload, {:struct, Member})
{guild_id, nil, new_member}
end
end
Expand Down
21 changes: 16 additions & 5 deletions lib/nostrum/cache/member_cache/mnesia.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ if Code.ensure_loaded?(:mnesia) do
@behaviour Nostrum.Cache.MemberCache

alias Nostrum.Cache.MemberCache
alias Nostrum.Snowflake
alias Nostrum.Struct.Guild
alias Nostrum.Struct.Guild.Member
alias Nostrum.Util
Expand Down Expand Up @@ -76,18 +77,28 @@ if Code.ensure_loaded?(:mnesia) do
@doc "Update the given member for the given guild in the cache."
@spec update(Guild.id(), map()) :: {Guild.id(), Member.t() | nil, Member.t()}
def update(guild_id, payload) do
new_member = Util.cast(payload, {:struct, Member})
key = {guild_id, new_member.user_id}
# Force keys to be atoms before casting just to simplify finding the user_id
# because of the atom/string ambiguity issues from the gateway that Discord
# won't fix.

old_member =
member_payload = Map.new(payload, fn {k, v} -> {Util.maybe_to_atom(k), v} end)

member_id = Util.cast(member_payload[:user][:id], Snowflake)

key = {guild_id, member_id}

{old_member, new_member} =
:mnesia.activity(:sync_transaction, fn ->
case :mnesia.read(@table_name, key, :write) do
[{_tag, _key, _guild_id, _user_id, old_member} = entry] ->
new_member = Member.to_struct(member_payload, old_member)

:mnesia.write(put_elem(entry, 4, new_member))
old_member
{old_member, new_member}

[] ->
nil
new_member = Member.to_struct(member_payload)
{nil, new_member}
end
end)

Expand Down
17 changes: 17 additions & 0 deletions lib/nostrum/struct/guild/member.ex
Original file line number Diff line number Diff line change
Expand Up @@ -308,4 +308,21 @@ defmodule Nostrum.Struct.Guild.Member do

struct(__MODULE__, new)
end

@doc false
@spec to_struct(map(), nil | __MODULE__.t()) :: __MODULE__.t()
def to_struct(map, nil), do: to_struct(map)

def to_struct(map, old_user) do
new =
map
|> Map.new(fn {k, v} -> {Util.maybe_to_atom(k), v} end)
|> Util.map_update_if_present(:roles, &Util.cast(&1, {:list, Snowflake}))
|> Util.map_update_if_present(:communication_disabled_until, &Util.maybe_to_datetime/1)
|> Util.map_update_if_present(:premium_since, &Util.maybe_to_datetime/1)
|> Util.map_update_if_present(:joined_at, &Util.maybe_to_unixtime/1)
|> Map.put(:user_id, Util.cast(map[:user][:id], Snowflake))

struct(old_user, new)
end
end

0 comments on commit 6f86805

Please # to comment.