mirror of
				https://github.com/django/daphne.git
				synced 2025-10-31 07:47:25 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			73 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			73 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import time
 | |
| 
 | |
| import asyncio
 | |
| from autobahn.asyncio.websocket import (
 | |
|     WebSocketServerFactory, WebSocketServerProtocol,
 | |
| )
 | |
| 
 | |
| from .websocket_autobahn import get_factory, get_protocol
 | |
| 
 | |
| 
 | |
| class WebsocketAsyncioInterface(object):
 | |
|     """
 | |
|     Easy API to run a WebSocket interface server using Twisted.
 | |
|     Integrates the channel backend by running it in a separate thread, using
 | |
|     the always-compatible polling style.
 | |
|     """
 | |
| 
 | |
|     def __init__(self, channel_backend, port=9000):
 | |
|         self.channel_backend = channel_backend
 | |
|         self.port = port
 | |
| 
 | |
|     def run(self):
 | |
|         self.factory = get_factory(WebSocketServerFactory)(debug=False)
 | |
|         self.factory.protocol = get_protocol(WebSocketServerProtocol)
 | |
|         self.loop = asyncio.get_event_loop()
 | |
|         coro = self.loop.create_server(self.factory, '0.0.0.0', self.port)
 | |
|         server = self.loop.run_until_complete(coro)
 | |
|         self.loop.run_in_executor(None, self.backend_reader)
 | |
|         self.loop.call_later(1, self.keepalive_sender)
 | |
|         try:
 | |
|             self.loop.run_forever()
 | |
|         except KeyboardInterrupt:
 | |
|             pass
 | |
|         finally:
 | |
|             server.close()
 | |
|             self.loop.close()
 | |
| 
 | |
|     def backend_reader(self):
 | |
|         """
 | |
|         Run in a separate thread; reads messages from the backend.
 | |
|         """
 | |
|         # Wait for main loop to start
 | |
|         time.sleep(0.5)
 | |
|         while True:
 | |
|             channels = self.factory.reply_channels()
 | |
|             # Quit if reactor is stopping
 | |
|             if not self.loop.is_running():
 | |
|                 return
 | |
|             # Don't do anything if there's no channels to listen on
 | |
|             if channels:
 | |
|                 channel, message = self.channel_backend.receive_many(channels)
 | |
|             else:
 | |
|                 time.sleep(0.1)
 | |
|                 continue
 | |
|             # Wait around if there's nothing received
 | |
|             if channel is None:
 | |
|                 time.sleep(0.05)
 | |
|                 continue
 | |
|             # Deal with the message
 | |
|             self.factory.dispatch_send(channel, message)
 | |
| 
 | |
|     def keepalive_sender(self):
 | |
|         """
 | |
|         Sends keepalive messages for open WebSockets every
 | |
|         (channel_backend expiry / 2) seconds.
 | |
|         """
 | |
|         expiry_window = int(self.channel_backend.expiry / 2)
 | |
|         for protocol in self.factory.reply_protocols.values():
 | |
|             if time.time() - protocol.last_keepalive > expiry_window:
 | |
|                 protocol.sendKeepalive()
 | |
|         if self.loop.is_running():
 | |
|             self.loop.call_later(1, self.keepalive_sender)
 |