From: Mikko Rasa Date: Thu, 1 Jun 2023 07:31:43 +0000 (+0300) Subject: Add a dynamic receiver class for more flexible packet handling X-Git-Url: http://git.tdb.fi/?p=libs%2Fnet.git;a=commitdiff_plain;h=HEAD;ds=sidebyside Add a dynamic receiver class for more flexible packet handling It's useful for middleware libraries which may not know all packet types at compile time, or if different packets need to be routed to different receivers. --- diff --git a/source/net/protocol.cpp b/source/net/protocol.cpp index 7fde8fe..5e82a80 100644 --- a/source/net/protocol.cpp +++ b/source/net/protocol.cpp @@ -57,7 +57,14 @@ size_t Protocol::dispatch(ReceiverBase &rcv, const char *buf, size_t size, unsig if(header.length>size) throw bad_packet("truncated"); const PacketDefBase &pdef = get_packet_by_id(header.type-base_id); - ptr = pdef.dispatch(rcv, ptr, ptr+header.length); + if(DynamicReceiver *drcv = dynamic_cast(&rcv)) + { + Variant pkt; + ptr = pdef.deserialize(pkt, ptr, ptr+header.length); + drcv->receive(pdef.get_id(), pkt); + } + else + ptr = pdef.dispatch(rcv, ptr, ptr+header.length); return ptr-buf; } diff --git a/source/net/protocol.h b/source/net/protocol.h index e766733..5051338 100644 --- a/source/net/protocol.h +++ b/source/net/protocol.h @@ -147,6 +147,7 @@ private: virtual unsigned get_class_id() const = 0; unsigned get_id() const { return id; } virtual std::uint64_t get_hash() const = 0; + virtual const char *deserialize(Variant &, const char *, const char *) const = 0; virtual const char *dispatch(ReceiverBase &, const char *, const char *) const = 0; }; @@ -169,6 +170,7 @@ private: std::uint64_t get_hash() const override { return serializer->get_hash(); } char *serialize(const P &, char *, char *) const; const char *deserialize(P &, const char *, const char *) const; + const char *deserialize(Variant &, const char *, const char *) const override; const char *dispatch(ReceiverBase &, const char *, const char *) const override; }; @@ -431,6 +433,15 @@ const char *Protocol::PacketTypeDef

::deserialize(P &pkt, const char *buf, con return serializer->deserialize(pkt, buf, end); } +template +const char *Protocol::PacketTypeDef

::deserialize(Variant &var_pkt, const char *buf, const char *end) const +{ + P pkt; + const char *ptr = serializer->deserialize(pkt, buf, end); + var_pkt = std::move(pkt); + return ptr; +} + template const char *Protocol::PacketTypeDef

::dispatch(ReceiverBase &rcv, const char *buf, const char *end) const { diff --git a/source/net/receiver.cpp b/source/net/receiver.cpp new file mode 100644 index 0000000..46c12f3 --- /dev/null +++ b/source/net/receiver.cpp @@ -0,0 +1,16 @@ +#include "receiver.h" + +namespace Msp { +namespace Net { + +void DynamicDispatcher::receive(unsigned packet_id, const Variant &packet) +{ + auto i = lower_bound_member(targets, packet_id, &Target::packet_id); + if(i==targets.end() || i->packet_id!=packet_id) + throw key_error(packet_id); + + i->func(*i->receiver, packet); +} + +} // namespace Net +} // namespace Msp diff --git a/source/net/receiver.h b/source/net/receiver.h index 9af1bb7..a0a9f29 100644 --- a/source/net/receiver.h +++ b/source/net/receiver.h @@ -1,6 +1,10 @@ #ifndef MSP_NET_RECEIVER_H_ #define MSP_NET_RECEIVER_H_ +#include +#include +#include +#include #include "mspnet_api.h" namespace Msp { @@ -14,6 +18,7 @@ public: virtual ~ReceiverBase() = default; }; + template class PacketReceiver: public virtual ReceiverBase { @@ -23,6 +28,54 @@ public: virtual void receive(const P &) = 0; }; + +class MSPNET_API DynamicReceiver: public ReceiverBase +{ +protected: + DynamicReceiver() = default; +public: + virtual void receive(unsigned, const Variant &) = 0; +}; + + +class MSPNET_API DynamicDispatcher: public DynamicReceiver +{ +private: + using DispatchFunc = void(ReceiverBase &, const Variant &); + + struct Target + { + unsigned packet_id; + ReceiverBase *receiver; + DispatchFunc *func; + + Target(unsigned i, ReceiverBase &r, DispatchFunc *f): packet_id(i), receiver(&r), func(f) { } + }; + + std::vector targets; + +public: + template + void add_receiver(unsigned, PacketReceiver

&); + + void receive(unsigned, const Variant &) override; +}; + + +template +void DynamicDispatcher::add_receiver(unsigned packet_id, PacketReceiver

&r) +{ + auto i = lower_bound_member(targets, packet_id, &Target::packet_id); + if(i!=targets.end() && i->packet_id==packet_id) + throw key_error(packet_id); + + auto dispatch = [](ReceiverBase &receiver, const Variant &packet){ + dynamic_cast &>(receiver).receive(packet.value

()); + }; + + targets.emplace(i, packet_id, r, +dispatch); +} + } // namespace Net } // namespace Msp