super dupper system update (it runs)
This commit is contained in:
122
wip/SNIP/client/chatServer.py
Normal file
122
wip/SNIP/client/chatServer.py
Normal file
@@ -0,0 +1,122 @@
|
||||
import asyncio
|
||||
import struct
|
||||
import ipaddress
|
||||
import websockets
|
||||
import time
|
||||
|
||||
SERVER = "wss://ip.astronand.dev"
|
||||
SERVER_NAME = "alpha"
|
||||
|
||||
OP_IP_REQUEST = 0x01
|
||||
OP_IP_ASSIGN = 0x02
|
||||
OP_DATA = 0x10
|
||||
ASSIGN_OK = 0x00
|
||||
|
||||
DATA_HEADER = "!4s4sI"
|
||||
HEADER_SIZE = struct.calcsize(DATA_HEADER)
|
||||
|
||||
clients = {} # ip -> username
|
||||
rooms = {} # room -> set(ip)
|
||||
federated_servers = set()
|
||||
|
||||
def encode(src, dst, payload: bytes):
|
||||
return (
|
||||
bytes([OP_DATA]) +
|
||||
struct.pack(DATA_HEADER, src, dst, len(payload)) +
|
||||
payload
|
||||
)
|
||||
|
||||
def chat(tp, room, user, data=""):
|
||||
return f"CHAT|{tp}|{room}|{user}|{data}".encode()
|
||||
|
||||
async def main():
|
||||
async with websockets.connect(SERVER, max_size=2**20) as ws:
|
||||
# DHCP
|
||||
await ws.send(b"\x01\x00")
|
||||
reply = await ws.recv()
|
||||
my_ip = reply[2:6]
|
||||
|
||||
print("🖥️ Chat server IP:", ipaddress.IPv4Address(my_ip))
|
||||
|
||||
async def announce():
|
||||
while True:
|
||||
await ws.send(
|
||||
encode(my_ip, my_ip,
|
||||
chat("SERVER_HELLO", "*", "server", SERVER_NAME)
|
||||
)
|
||||
)
|
||||
await asyncio.sleep(5)
|
||||
|
||||
async def handler():
|
||||
async for msg in ws:
|
||||
if not isinstance(msg, bytes) or msg[0] != OP_DATA:
|
||||
continue
|
||||
|
||||
src, _, length = struct.unpack(
|
||||
DATA_HEADER, msg[1:1+HEADER_SIZE]
|
||||
)
|
||||
payload = msg[1+HEADER_SIZE:]
|
||||
if len(payload) != length:
|
||||
continue
|
||||
|
||||
try:
|
||||
text = payload.decode()
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
|
||||
if not text.startswith("CHAT|"):
|
||||
continue
|
||||
|
||||
_, tp, room, user, data = text.split("|", 4)
|
||||
|
||||
# ---- discovery / federation ----
|
||||
if tp == "SERVER_HELLO" and src != my_ip:
|
||||
federated_servers.add(src)
|
||||
print(f"🔗 Federated with {data} @ {ipaddress.IPv4Address(src)}")
|
||||
|
||||
elif tp == "HELLO":
|
||||
clients[src] = user
|
||||
print(f"👤 {user} connected")
|
||||
|
||||
elif tp == "ROOM_LIST":
|
||||
await ws.send(encode(
|
||||
my_ip, src,
|
||||
chat("ROOM_LIST", "*", "server", ",".join(rooms.keys()))
|
||||
))
|
||||
|
||||
# ---- room management ----
|
||||
elif tp == "JOIN":
|
||||
rooms.setdefault(room, set()).add(src)
|
||||
for ip in rooms[room]:
|
||||
await ws.send(encode(
|
||||
my_ip, ip,
|
||||
chat("INFO", room, "server", f"{user} joined")
|
||||
))
|
||||
|
||||
elif tp == "LEAVE":
|
||||
rooms.get(room, set()).discard(src)
|
||||
|
||||
# ---- messaging ----
|
||||
elif tp == "MSG":
|
||||
for ip in rooms.get(room, []):
|
||||
await ws.send(encode(
|
||||
my_ip, ip,
|
||||
chat("MSG", room, user, data)
|
||||
))
|
||||
|
||||
for srv in federated_servers:
|
||||
await ws.send(encode(
|
||||
my_ip, srv,
|
||||
chat("FED_MSG", room, user, data)
|
||||
))
|
||||
|
||||
elif tp == "FED_MSG":
|
||||
for ip in rooms.get(room, []):
|
||||
await ws.send(encode(
|
||||
my_ip, ip,
|
||||
chat("MSG", room, user, data)
|
||||
))
|
||||
|
||||
await asyncio.gather(announce(), handler())
|
||||
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user