Closed WolfDan closed 6 years ago
The matcher on the implementations is _
on all of your implementations (in the post that was just a placeholder meaning 'put whatever you need to match on here'), meaning they all overlap, thus whatever gets called will be pretty random. I'm actually quite surprised you are not getting a compile-time warning about this, can you put this on github with a link to it so I can see why it's not causing a warning?
Either way, the matcher should be unique for each implementation (just like with normal Elixir Protocols), so for example instead of defimplEx Map, _, ...
you'd want to do defimplEx Map, x when x in ["walk_to"], ...
and instead of things like defimplEx Chat, _, ...
you'd want to do something like defimplEx Chat, x when x in ["say", "whisper"], ...
, and so forth that you would do for every implementation.
However that does mean there is duplication, which I don't like, that is why I have an undocumented feature in ProtocolEx specifically for use-cases like this, but it is undocumented because it has a couple of caveats, first an example, the Map
implementation would be written like this instead:
import ProtocolEx
defimplEx Map, _, for: Visionire.Network.Packet, inline: [parse: 3] do
def parse(
"walk_to",
%{"walk_to" => [x, y]},
%Visionire.Network.State.ClientState{connection_state: :logged_in} = state
) do
now = Visionire.Network.Utils.stamp_ms(:os.timestamp())
# implementation
{:ok, state}
end
end
The only difference is that it is given an inline
option, which takes a list of name: arity
mappings of what to 'inline'. What this means is that the matcher will be ignored on the defimpl_ex
itself and it will instead delegate it entirely to the defined functions itself, I.E. it is like copy/pasting the entire function into the protocol itself. Now the caveat means that the function has to be ENTIRELY self-contained. It cannot reference other local functions, it cannot reference aliases or imports outside of it, nothing. All function calls have to be completely and fully written out unless it is a local call to the protocol itself, not the implementation.
Consequently, this method is not suggested and instead only exists for micro-optimizations, which is definitely not the case here, so I'd recommend writing out the matchers properly. :-)
Just remember, the matchers on the defimpl_ex
line itself generally must be unique or it falls back to priority ordering, and if that is unspecified then it falls back to alphanumeric ordering. :-)
Regardless though, if any further issues, try to reduce the problem to a reproduceable test-case that is either copy/pasteable into the shell or a link to a minimal git repo. :-)
On a secondary design issue, it looks like you are just extracting some random first key as per message_id = Map.keys(data) |> List.first()
on the message then dispatching based on that, what if there are multiple entires on the map? Why is a map used at all if some random key is chosen to dispatch on? This should probably be a 2-tuple, not a map. :-)
Thank you @OvermindDL1 !
Actually I fixed it by passing the message struct as a matcher like this:
defimplEx ChatSay, %{"say" => text} when is_binary(text), for: Visionire.Network.Packet do
alias Visionire.Network.{Client, Server}
alias Visionire.Network.State.ClientState
def parse_message(
%{"say" => text},
%ClientState{connection_state: :logged_in} = state
) do
Server.broadcast_except(%{person_said: [state.player.user_id, text]})
Client.send(%{result: "ok"})
{:ok, state}
end
end
It works as expected now :D thank you for this amazing library ^^/
Actually I fixed it by passing the message struct as a matcher like this:
Yep, that's the way to do it especially if only one thing to match on, quite efficient. :-)
Hello ^^
I'm having an issue with the library, I don't know if I'm doing it in the wrong way, I just follow the code posted here, I'm implementing a protocol for a client that sends json messages, here my implementation:
Packet
Login
Map
Chat
Misc
And I dispatch it like this:
The client is sending this message
"{"client":{"login":["sif","wolf"]}}"
and I'm getting this error:As you can see it always match the Misc parser, is it a bug of the library or I miss something in the implementation?
Greetings 0/