Package: magic-foundation
magic_foundationMinimalistic library that simplifies the adoption ofasync/await(asyncio) programming style in a multithreaded application.Define 2 services and run in the same runloop (single thread)importloggingfrommagic_foundationimportService,ServiceStatus,ServiceContext,MainclassTestService(Service):def__init__(self,name:str):self.name=nameasyncdefinitialize(self,ctx:ServiceContext):log.info(f"[{self.name}] initialize")asyncdefrun(self,ctx:ServiceContext):index=0whileself.statusisServiceStatus.running:log.info(f"[{self.name}] run{index}")index+=1awaitasyncio.sleep(1.0)asyncdefterminate(self,ctx:ServiceContext):log.info(f"[{self.name}] terminate")if__name__=="__main__":log=logging.getLogger(__name__)logging.basicConfig(level=logging.INFO)logging.getLogger("magic_foundation").setLevel(logging.DEBUG)main=Main.instance()main.service_pools={'main':[TestService(name="Service_1"),TestService(name="Service_2")],}main.run()If you want running the 2 services in different threads just define the service_pools as following:...main=Main.instance()main.service_pools={'th1':[TestService(name="Service_1")],'th2':[TestService(name="Service_2")],}main.run()CommunicationThe communication between Services mimics thepublish/subscribe paradigmSubscribeasyncdefcoro(data):log.info(f"[{self.name}] coro data:{data}")awaitctx.subscribe(queue_name="q://my_queue",handler=coro)Pubblishdata={"a":"A","b":1234}awaitctx.publish(queue_name="q://my_queue",data=data)It is possible to subscribe to the same queue from different services and each service will receive the messageWebSocket ServiceAs an additionan component the library provides a built-in websocket service.frommagic_foundationimportContainer,Service,ServiceStatus,ServiceContext,Mainfrommagic_foundation.websocket_serviceimportWebSocketService...classTestService(Service):...asyncdefrun(self,ctx:ServiceContext):log.info(f"[{self.name}] run")asyncdefhandler(data):log.info(f"[{self.name}] handler inbound data:{data}")req=json.loads(data)res=json.dumps({"status":"OK","timestamp":req["timestamp"]})awaitctx.publish(queue_name="ws://outbound/client",data=res)awaitctx.subscribe(queue_name="ws://inbound/client",handler=handler)...asyncdefterminate(self,ctx:ServiceContext):log.info(f"[{self.name}] terminate")...if__name__=="__main__":main=Main.instance()main.service_pools={"main":[WebSocketService(host="localhost",port=8765),TestService(name="Consumer"),]}main.run()The prefixesws://inbound/andws://outbound/refer to the WS endpoint (WebSocketService) andmust be considered reserved.The complete example is contained in the examples folder.To trying it run in a shell the command:python examples/websocket.pyand in a browser open the filewebsocket.html.LimitationsRight now only the requestedpathis use as discriminant, so messages from different clients with the same path are routed to the same handler and vice versa one outbound message is sent to all clients connected to the samepath.Simple Logging ServiceThe included logging service is a simpple way to dump json maggase to a local file.frommagic_foundationimportContainer,Service,ServiceStatus,ServiceContext,Mainfrommagic_foundation.logging_serviceimportLoggingService...file_path="logging_out.log"classTestService(Service):...asyncdefrun(self,ctx:ServiceContext):log.info(f"[{self.name}] run")...asyncdefterminate(self,ctx:ServiceContext):log.info(f"[{self.name}] terminate")index=0;whileself.status==ServiceStatus.running:index+=1data={"cmd":"log","index":index}awaitctx.publish(queue_name=f"log://{file_path}",data=data)awaitasyncio.sleep(1.0)...if__name__=="__main__":main=Main.instance()main.service_pools={"backgound":[LoggingService(file_path=file_path,flush_interval_sec=4.0)],"main":[TestService(name="Producer")]}main.run()The prefixeslog://refers to the simple logging service (LoggingService) andmust be considered reserved.The complete example is contained in the examples folder.To trying it run in a shell the command:python examples/dump_to_file.py. In the root of the project a file calledlogging_out.logwill be created and every 4 seconds the logging service will flush the collected messages.