leaf.py
This commit is contained in:
87
leaf.py
Normal file
87
leaf.py
Normal file
@@ -0,0 +1,87 @@
|
||||
import time
|
||||
import asyncio
|
||||
from asyncio.protocols import DatagramProtocol
|
||||
|
||||
import websockets
|
||||
|
||||
TX_HOST = '127.0.0.1'
|
||||
TX_PORT = '80'
|
||||
TX_ROUTE = '/'
|
||||
RX_HOST = '0.0.0.0'
|
||||
RX_PORT = 5005
|
||||
|
||||
class MyProto(DatagramProtocol):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def connection_made(self, transport):
|
||||
self.transport = transport
|
||||
self.tunnels = {}
|
||||
self.last_packet_time = {}
|
||||
|
||||
async def ws_to_udp_loop(self, first_packet, addr):
|
||||
try:
|
||||
ws = await websockets.connect("ws://"+TX_HOST+':'+TX_PORT+TX_ROUTE)
|
||||
self.tunnels[addr] = ws
|
||||
print("WebSocket for", addr, "created")
|
||||
except Exception as e:
|
||||
print("Unable to connect, check if remote server is available. Exception text:", e)
|
||||
return
|
||||
|
||||
try:
|
||||
while True:
|
||||
await ws.send(first_packet)
|
||||
async for message in ws:
|
||||
self.transport.sendto(message, addr)
|
||||
self.last_packet_time[addr] = time.time()
|
||||
except Exception as e:
|
||||
print("Received exception on WebSocket for", addr,"-", e)
|
||||
finally:
|
||||
print("WebSocket for", addr, "closed")
|
||||
self.tunnels.pop(addr, None)
|
||||
self.last_packet_time.pop(addr, None)
|
||||
await ws.close()
|
||||
|
||||
|
||||
def datagram_received(self, data, addr):
|
||||
loop = asyncio.get_running_loop()
|
||||
ws = self.tunnels.get(addr, None)
|
||||
|
||||
if ws is None:
|
||||
loop.create_task(self.ws_to_udp_loop(data, addr))
|
||||
else:
|
||||
loop.create_task(ws.send(data))
|
||||
self.last_packet_time[addr] = time.time()
|
||||
|
||||
async def cleanup(self):
|
||||
connections_for_removal = []
|
||||
for addr in self.last_packet_time.keys():
|
||||
time_passed = time.time() - self.last_packet_time[addr]
|
||||
if time_passed > 3600:
|
||||
print(f"Closing connection for {addr} (inactive for: {int(time_passed)} seconds)")
|
||||
connections_for_removal.append(addr)
|
||||
|
||||
for addr in connections_for_removal:
|
||||
await self.tunnels[addr].close()
|
||||
|
||||
|
||||
|
||||
async def main():
|
||||
addr = RX_HOST
|
||||
proto = MyProto()
|
||||
transport, protocol = await asyncio.get_event_loop().create_datagram_endpoint(
|
||||
lambda: proto,
|
||||
local_addr=(addr, RX_PORT)
|
||||
)
|
||||
|
||||
print(f'Serving on {addr}:{RX_PORT}')
|
||||
|
||||
try:
|
||||
while True:
|
||||
await asyncio.sleep(3600)
|
||||
await proto.cleanup()
|
||||
|
||||
finally:
|
||||
transport.close()
|
||||
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user