1 # proxy between arduino switch and websockets
2 # it listens on 0.0.0.0, UDP port 1312, "websocket" port 8765
11 from nonstop.app_settings import app_settings
14 logger = logging.getLogger('switch-proxy')
17 class PanikSwitchProtocol(asyncio.DatagramProtocol):
22 self.currently_active = 0
23 self.update_with_http()
24 self.websocket_connections = set()
26 def datagram_received(self, data, addr):
27 logger.debug('Datagram received: %s', data)
28 new_active = json.loads(data)['active']
29 if new_active != self.currently_active:
30 logger.info('UDP update, %s -> %s', self.currently_active, new_active)
31 self.currently_active = json.loads(data)['active']
33 async def websocket_handler(self, websocket, path):
34 self.websocket_connections.add(websocket)
37 if self.currently_active != latest_active:
38 latest_active = self.currently_active
40 for ws in self.websocket_connections:
42 await ws.send(json.dumps({'active': self.currently_active}))
43 except websockets.exceptions.ConnectionClosed:
46 self.websocket_connections.remove(ws)
47 await asyncio.sleep(0.1)
49 def update_with_http(self):
51 resp = requests.get(app_settings.ON_AIR_SWITCH_URL, timeout=2)
53 new_active = resp.json().get('active')
54 if new_active != self.currently_active:
55 logger.info('HTTP-only update, %s -> %s', self.currently_active, new_active)
56 self.currently_active = resp.json().get('active')
57 except (OSError, requests.exceptions.RequestException):
62 loop = asyncio.get_running_loop()
63 proto = PanikSwitchProtocol()
64 await websockets.serve(proto.websocket_handler, '0.0.0.0', 8765)
65 transport, protocol = await loop.create_datagram_endpoint(lambda: proto, local_addr=('0.0.0.0', 1312))
68 await asyncio.sleep(300)
69 proto.update_with_http()