0

I am trying to develop an application consisting of a Server and a bunch of Clients that should work like this:

  • each Client itself will listen to an independent websocket consisting of some information
  • they will then process this information and redirect the processed message to the Server
  • the Server will do some processing (send some information trhough another websocket and wait for response)
  • once the Server gets the response, it will redirect it to the Client

Since it consists of asynchronous responses and communication between classes my first idea was to use the combo RxPy + asyncio. Here is a toy model of my problema that I tryied to develop:

Here is the Server:

import reactivex as rx
import random

import reactivex.operators as ops

class Server:
    def __init__(self, clients):
        self.clients = clients
        self.stream = rx.Subject()
        
    def info(self, msg):
        print(msg)
    
    async def start(self, loop):
        
        done = asyncio.Future()
        
        def on_completed():
            done.set_result(True)
        
        async def react(item):
            msg = {'alias': 'server', 'action': 'received', 'from': item['alias'], 'request': item['request']}
            self.info(msg)
            
            await asyncio.sleep(random.randint(1,3))
            
            response = {'alias': 'server', 'action': 'send', 'request': msg['request'] ** 2}
            self.info(response)
            self.stream.on_next(response)
        
        client_listener = rx.empty()
        for client in self.clients:
            client_listener= rx.merge(client_listener, client.stream(self.stream, loop))
            
        client_listener.subscribe(
            on_next = lambda x: react(x),
            on_error = print,
            on_completed = print('completed server')
        )
        
        await done

Here is the Client:

import reactivex.operators as ops

class Client:
    def __init__(self, alias):
        self.alias = alias
    
    def info(self, msg):
        print(msg)
    
    def stream(self, controller, loop):        
        
        def on_subscribe(observer, scheduler):
            
            for i in range(10):
                msg = {'alias': self.alias, 'action': 'send', 'request': i}
                self.info(msg)
                observer.on_next(msg)
            loop.call_soon(observer.on_completed())
            
        controller.subscribe(
            on_next = lambda msg: self.info({'alias': self.alias, 'action': 'received', 'from': msg['alias'], 'request': msg['request']})
        )
        
        return rx.create(on_subscribe)

And here is how I am trying to run it:

import asyncio

loop = asyncio.get_event_loop()

client_1 = Client('client_1')
client_2 = Client('client_2')

loop.run_until_complete(Server([client_1, client_2]).start(loop=loop))
loop.close()

When I try executing the above code I get the followin:

RuntimeError                              Traceback (most recent call last)
Cell In[3], line 8
      5 client_1 = Client('client_1')
      6 client_2 = Client('client_2')
----> 8 loop.run_until_complete(Server([client_1, client_2]).start(loop=loop))
      9 loop.close()

File ~\Anaconda3\envs\nfs_hom\lib\asyncio\base_events.py:625, in BaseEventLoop.run_until_complete(self, future)
    614 """Run until the Future is done.
    615 
    616 If the argument is a coroutine, it is wrapped in a Task.
   (...)
    622 Return the Future's result, or raise its exception.
    623 """
    624 self._check_closed()
--> 625 self._check_running()
    627 new_task = not futures.isfuture(future)
    628 future = tasks.ensure_future(future, loop=self)

File ~\Anaconda3\envs\nfs_hom\lib\asyncio\base_events.py:584, in BaseEventLoop._check_running(self)
    582 def _check_running(self):
    583     if self.is_running():
--> 584         raise RuntimeError('This event loop is already running')
    585     if events._get_running_loop() is not None:
    586         raise RuntimeError(
    587             'Cannot run the event loop while another loop is running')

RuntimeError: This event loop is already running

Could you help me understand where I am getting it wrong and/or where I should change my approach for the problem?

0 Answers0