I am writing an application that reads incoming packets and I’d like to decode them and route them to the appropriate handler.
The header of each packet is what defines its type.
So for example a user login packet may look like this:
<<
header::integer-little-8,
ulen::unsigned-little-integer-32,
user::binary-size(ulen),
plen::unsigned-little-integer-32,
pass::binary-size(plen)
>>
I’d like to be able to do something like this in my receive function:
<<
header::integer-little-8,
data::bytes
>> = received
{:ok, packet} = Packet.parse(header, data)
:ok = packet.run()
Where Packet.parse/2 is defined at compile time.
defmodule Packet do
defmacro __using__(header) do
# track __CALLER__ and header?
@behaviour Packet
end
@callback parse(BitString) :: {:ok, Map}
@callback def run() :: :ok | {:error, reason}
# Generate these at compile time
def parse(1, data), do: Packets.Login.parse(data)
def parse(2, data), do: Packets.Chat.parse(data)
end
defmodule Packets.Login do
use Packet, header: 1
defstruct :username, :password
def parse(packet_data), do: # decode packet
def run, do: # run code to handle packet
end
Is there a way to do this using macros or a better way that wouldn’t require macros?