Package: eventhive
EventHiveNetwork PubSub and Async Message Passing for HumansWhat is that thing?eventhiveis a Python package that enables Python code to communicate using
Publisher/Subscriber model uniformly, be it in the same process or in different hosts!Supports external PubSub backends (like Redis), Service Discovery (usingpython-zeroconf) and application level Message Signing and Encryption (usingPython Native AES).What does it do?Leverages Python reflection magic and the excelent API created by@dzervasinhookerfor event-based programming and expands it to network level event-passing, effectively creating a PubSub-based RPC (Remote Procedure Calling) framework.It can be used in IoT Development, to Games, to Kubernetes and microservices!How to UseWorkerCreate a minimaleventhiveYAML configuration for the Worker:connectors:my-hive:pubsub_type:fastapiinput_channel:'worker'init:host:127.0.0.1port:8085endpoint:/pubsubRegister aneventhiveevent:eventhive.EVENTS.append("worker/action")Create a function with a single argument and annotate it with theeventhiveevent:@eventhive.hook("worker/action")defwork(arg):print("Working with:%s"arg)Starteventhiveeventhive.init()QueenCreate aneventhiveYAML configuration for the Queen. Also add a PubSub server in the mix:connectors:my-hive:pubsub_type:fastapiinput_channel:'queen'init:host:127.0.0.1port:8085endpoint:/pubsubservers:my-hive:pubsub_type:fastapicreate:alwaysbroadcast:falseinit:host:0.0.0.0port:8085endpoint:/pubsubRegister aneventhiveevent implemented by the worker:eventhive.EVENTS.append("my-hive/worker/action")Starteventhiveeventhive.init()Call the registered event with adicteventhive.EVENTS.call("my-hive/worker/action",{"param1":1,"param2":2})The Worker will print:Working with: {'param1':1, 'param2':2}What with the/in the Event names?A convention exists ineventhiveso it can be used as a PubSub for event-based programming
and network message passing engine at the same time. This convention is based onEventnames.TheEventsare split in 3 categories following a naming convention:Strictly Local EventsLikebee_stuffin the single-process example. These Events cannot be called from the network.
They have to be defined (eventhive.append("bee_stuff")), implemented (@eventhive.hook("bee_stuff")) and
called (eventhive.EVENTS["bee_stuff"]("arg")) in the same process.Network Accessible EventsLike Worker Bee'sworker-bee/work. These Events have to be defined and implemented by the same process,
but they can be called either from the same process (eventhive.EVENTS["worker-bee/work"]({"random":"dict"})), or
by any othereventhiveprocess in the network as aRemote Event.Remote EventsLike Queen Bee'smy-beehive/worker-bee/work. These Events are not implemented in the process they are
defined (eventhive.append("my-beehive/worker-bee/work")). Calling these Events
(eventhive.EVENTS["my-beehive/worker-bee/work"]({"random":"dict"})) informseventhivethat they
have to travel overmy-beehivenetwork and get published to themy-beehive/worker-bee/workchannel.Othereventhiveprocesses that are connected tomy-beehiveand haveinput_channel: worker-beein their configuration, pick up these Events, ditch theNetwork Name(my-beehive/worker-bee/workbecomesworker-bee/work) and consume them likeLocal Events.Message Exampleseventhiveevents are simple JSON messages that can have metadata attached or not.
In the examples below metadata will be available under the key__eventhive__. Disabling metadata or changing the key name
can be configured through theYAML configuration.Nosecretset - plaintext messageseventhive.EVENTS.call("my-hive/worker/action",{"param1":1,"param2":2}){"param1":1,"param2":2,"__eventhive__":{"time":1680610165.4884348,"version":"0.3.2","event":"my-hive/worker/action","id":"d891d47f-64a4-4ecc-88ab-69249da31154"}}eventhivemetadata can be used from a hooked function for accessing event creation time, version checking and duplicate message checking.
Yet, it is planned to move some of these functionalities to the library.Turning off metadata (i.eeventhive.remove_metadata: true) can save bandwidth, e.g in very limited IoT networks.WithsecretsetSetting asecretin aconnectorin the YAML configuration automatically enables AES Encryption and Message Signing.This is totally transparent to the hooked function, which will continue to accept events like the one described above.
Yet, the messages travelling through the network will look as below:{"iv":"2SH5S8J75afKxr76osauow==","ciphertext":"JFJvaixp9/8oiYaxrCS+yA6TkCKlX85g0qG0GlZa8eaQTuXf1Ot33yiIIr7Y+fsFTzL7kzOtFbaq1uO6QH54N9oyeWUi7rDelQi2HNZGYRJCqwtwAbFX4+D8IgBGqYkYGPKuiUZCLRvPArPmaMh8PpMrq4/nEOGf0ivyS9hKEVb9KSrm4+VedAfBMQfpxP3Z/cm/jpj2sKDb9rfcjWATEcQToQ/U4PP40mUGeDpKbmyTAxGLdGAp3jDcghkAM76nDAXmTpuP0PN7YpSp/3cRAiweXxuBszIdeLuoUBOa"}Theciphertextencapsulates messages like the one shown above, plus the__sign__key, which is used to verify the plaintext content and is stripped from the final message.In case decryption or signature verification fails, the event gets dropped and does not arrive to the hooked functions.Finally, ifsecretis set for a connector, it is impossible to accept non-encrypted, non-signed messages.The CLI ToolA CLI tool is part of theeventhivepackage to make it possible to test YAML configurations, without writing application code (and adding moving parts to the test).The output of the tool is the lasteventhivemessage that was received in JSON, or{"no":"output"}if no message is received.It uses YAML configuration and also can template YAML files, using the similar named arguments provided through CLI, as shown below:eventhive-cli--networkmy-hive--receiverworker--secretm1s3cr3t--configfastapi-template.yamlfastapi-template.yaml:connectors:{network}:pubsub_type:fastapiinput_channel:'{receiver}'secret:'{secret}'init:host:127.0.0.1port:8085endpoint:/pubsubCLI Usage$eventhive-cli-h
usage:eventhive-cli[-h][--networkNETWORK][--receiverRECEIVER][--eventEVENT][--json-dataJSON_DATA][--target-eventTARGET_EVENT][--json-fallbackJSON_FALLBACK][--configCONFIG][--timeoutTIMEOUT][--secretSECRET][--debug][--verbose]TheSwiss-ArmyknifeforEventhive

optionalarguments:-h,--helpshowthishelpmessageandexit--networkNETWORKTheEventhiveNetworkofEvents(<here>/*/*)(default:eventhive)--receiverRECEIVERTheEventhiveChannelofEvents(*/<here>/*)(default:cli)--eventEVENTTheEventhiveEventName(*/*/<here>)(default:do)--json-dataJSON_DATAIfset-theJSONwillbesentto"<network>/<receiver>/<event>"(default:False)--target-eventTARGET_EVENTIfset-theJSONdefinedin"--json-data"willbepublishedonitinsteadof"<network>/<receiver>/<event>"(default:None)--json-fallbackJSON_FALLBACKTheJSONtoprinttoSTDOUTifnodataisreceivedin"<network>/<receiver>/<event>"(default:{"no":"output"})--configCONFIGTheConfigurationfiletobeusedbyEventhive(canincludeformatting)(default:.eventhive-config.yaml)--timeoutTIMEOUTTimetorunbeforeexitingandprintingtoSTDOUT(default:6)--secretSECRETAsecretstringusedforsigningandencryptionofmessages(default:None)--debug,-dWhenset-fullDEBUGlogswillbeprinted(default:30)--verbose,-vWhenset-INFOlogswillbeprinted(default:None)