ayyaruq / zanarkand

Network capture library for realtime FFXIV Frame and FFXIV Message reading from a TCP/IP stream
MIT License
20 stars 8 forks source link

Improve Frame and Subscriber connection metadata #5

Closed ayyaruq closed 4 years ago

ayyaruq commented 4 years ago

To allow users to more easily filter opcodes, improve the Frame and Subscriber interfaces. The main changes here would be as follows:

One option is to have Subscriber take callbacks for sent/received frames instead of changing the structure. Additionally, Frame could be implemented as a custom gopacket layer decoder, but I have no idea how that works with tcpassembly. We could also just wrap the FrameHeader straight up into the various Message types.

If we used callbacks like Machina, we could have a function per direction and just track the connection type field from the Frame. It would still be up to the user how to get data out of it so I'm not sure if this is actually useful though. As an example of Subscriber using callbacks, the sig could be updated like this:

func (g *GameEventSubscriber) Subscribe(
  s *Sniffer,
  recv func(c uint16, p []byte),
  send func(c uint16, p []byte)
)

GameEvent and Keepalive messages currently have subscribers, but not the other types, this would be the session and encryption initialisation. I'm a bit hesitant for the latter since I don't want to enable usage for botting, and there's no real value in session parsing.

ayyaruq commented 4 years ago

Another option I'm thinking of is to have directional channels. This would break API though. Rather than subscriber.Events, we have subscriber.IngressEvents and subscriber.EgressEvents. This allows the user to handle them, however the concern if only one direction is wanted is that the buffer would fill up and block the frame reader. With callbacks, the user has to explicitly define the function even if all it does is discard.

ayyaruq commented 4 years ago

For now, implementing with a channel for each direction. It feels more idiomatic and I think callback functions are more complicated for users. It also makes looping input more annoying to manage flow control on, so sticking with channels seems like the correct move.