]> git.tdb.fi Git - libs/net.git/commitdiff
Add a dynamic receiver class for more flexible packet handling master
authorMikko Rasa <tdb@tdb.fi>
Thu, 1 Jun 2023 07:31:43 +0000 (10:31 +0300)
committerMikko Rasa <tdb@tdb.fi>
Thu, 1 Jun 2023 07:31:43 +0000 (10:31 +0300)
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.

source/net/protocol.cpp
source/net/protocol.h
source/net/receiver.cpp [new file with mode: 0644]
source/net/receiver.h

index 7fde8fe673d4dbba927b7cadec3c449470248539..5e82a80d7daaf17fb130752fd870380e2b78c329 100644 (file)
@@ -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);
        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<DynamicReceiver *>(&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;
 }
 
        return ptr-buf;
 }
 
index e766733cb6a6373839ecefd32c8e95dd9eb24d52..5051338f3911558c8e2ee19fe2d0665c0e10eec3 100644 (file)
@@ -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 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;
        };
 
                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;
                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;
        };
 
                const char *dispatch(ReceiverBase &, const char *, const char *) const override;
        };
 
@@ -431,6 +433,15 @@ const char *Protocol::PacketTypeDef<P>::deserialize(P &pkt, const char *buf, con
        return serializer->deserialize(pkt, buf, end);
 }
 
        return serializer->deserialize(pkt, buf, end);
 }
 
+template<typename P>
+const char *Protocol::PacketTypeDef<P>::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<typename P>
 const char *Protocol::PacketTypeDef<P>::dispatch(ReceiverBase &rcv, const char *buf, const char *end) const
 {
 template<typename P>
 const char *Protocol::PacketTypeDef<P>::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 (file)
index 0000000..46c12f3
--- /dev/null
@@ -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
index 9af1bb7154af65a226d96836c43fe48d9bc18fa3..a0a9f2913d0ed0e48fb6a47aa5793f04aa76ac99 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef MSP_NET_RECEIVER_H_
 #define MSP_NET_RECEIVER_H_
 
 #ifndef MSP_NET_RECEIVER_H_
 #define MSP_NET_RECEIVER_H_
 
+#include <vector>
+#include <msp/core/algorithm.h>
+#include <msp/core/maputils.h>
+#include <msp/core/variant.h>
 #include "mspnet_api.h"
 
 namespace Msp {
 #include "mspnet_api.h"
 
 namespace Msp {
@@ -14,6 +18,7 @@ public:
        virtual ~ReceiverBase() = default;
 };
 
        virtual ~ReceiverBase() = default;
 };
 
+
 template<typename P>
 class PacketReceiver: public virtual ReceiverBase
 {
 template<typename P>
 class PacketReceiver: public virtual ReceiverBase
 {
@@ -23,6 +28,54 @@ public:
        virtual void receive(const P &) = 0;
 };
 
        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<Target> targets;
+
+public:
+       template<typename P>
+       void add_receiver(unsigned, PacketReceiver<P> &);
+
+       void receive(unsigned, const Variant &) override;
+};
+
+
+template<typename P>
+void DynamicDispatcher::add_receiver(unsigned packet_id, PacketReceiver<P> &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<PacketReceiver<P> &>(receiver).receive(packet.value<P>());
+       };
+
+       targets.emplace(i, packet_id, r, +dispatch);
+}
+
 } // namespace Net
 } // namespace Msp
 
 } // namespace Net
 } // namespace Msp