Compare commits
10 Commits
c0cacfad2d
...
d5985cf594
| Author | SHA1 | Date | |
|---|---|---|---|
|
d5985cf594
|
|||
|
b9fd84d08f
|
|||
|
f7f6f19808
|
|||
|
ac7799213c
|
|||
|
54512d8393
|
|||
|
c0ad91b22f
|
|||
|
b9a7c2bdaf
|
|||
|
ac66ce1999
|
|||
|
2ecd32decc
|
|||
|
1c96390f3c
|
@@ -3,15 +3,22 @@
|
|||||||
import logging as lg
|
import logging as lg
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from judas_server.web.web_server import JudasWebServer
|
|
||||||
from judas_server.backend import BackendServer
|
from judas_server.backend import BackendServer
|
||||||
|
from judas_server.web.web_server import JudasWebServer
|
||||||
|
from judas_server.gaga import LADY_GAGA
|
||||||
|
|
||||||
lg.basicConfig(
|
lg.basicConfig(
|
||||||
level=lg.DEBUG,
|
level=lg.DEBUG,
|
||||||
format="%(asctime)s : [%(levelname)s] : %(threadName)s : %(name)s :: %(message)s",
|
format="%(asctime)s : [%(levelname)s] : %(threadName)s : %(name)s :: %(message)s",
|
||||||
)
|
)
|
||||||
|
|
||||||
backend_server: BackendServer = BackendServer()
|
ladygaga_logger = lg.getLogger(f"{__name__}.LAGA_DYGA")
|
||||||
|
ladygaga_logger.info(LADY_GAGA)
|
||||||
|
|
||||||
|
backend_server: BackendServer = BackendServer(
|
||||||
|
host="0.0.0.0",
|
||||||
|
port=3692,
|
||||||
|
)
|
||||||
backend_server.run()
|
backend_server.run()
|
||||||
|
|
||||||
web_server: JudasWebServer = JudasWebServer(
|
web_server: JudasWebServer = JudasWebServer(
|
||||||
|
|||||||
@@ -73,9 +73,19 @@ class BackendServer:
|
|||||||
# wait for hello message to get mac_id
|
# wait for hello message to get mac_id
|
||||||
|
|
||||||
conn.settimeout(5)
|
conn.settimeout(5)
|
||||||
message = conn.recv(1024)
|
try:
|
||||||
|
message = conn.recv(1024)
|
||||||
|
if not message:
|
||||||
|
self.logger.error(f"[-] No data received from {addr}")
|
||||||
|
conn.close()
|
||||||
|
return
|
||||||
|
except socket.timeout:
|
||||||
|
self.logger.error(f"[-] Timeout waiting for hello from {addr}")
|
||||||
|
conn.close()
|
||||||
|
return
|
||||||
conn.settimeout(None)
|
conn.settimeout(None)
|
||||||
|
|
||||||
|
message = message.split(b"\n")[0] # get first line only
|
||||||
message = Message.from_bytes(message)
|
message = Message.from_bytes(message)
|
||||||
|
|
||||||
mac_id = message.payload.get("mac", None)
|
mac_id = message.payload.get("mac", None)
|
||||||
@@ -135,6 +145,8 @@ class BackendServer:
|
|||||||
self.logger.debug(f"[>] Sending ACK to {client}")
|
self.logger.debug(f"[>] Sending ACK to {client}")
|
||||||
client.outbound += ack
|
client.outbound += ack
|
||||||
|
|
||||||
|
# set last seen
|
||||||
|
client.last_seen = time.time()
|
||||||
else:
|
else:
|
||||||
self._disconnect(client)
|
self._disconnect(client)
|
||||||
|
|
||||||
@@ -146,6 +158,7 @@ class BackendServer:
|
|||||||
sent = sock.send(client.outbound)
|
sent = sock.send(client.outbound)
|
||||||
|
|
||||||
client.outbound = client.outbound[sent:]
|
client.outbound = client.outbound[sent:]
|
||||||
|
# TODO: wait for ACK from client
|
||||||
except ConnectionResetError as e:
|
except ConnectionResetError as e:
|
||||||
self.logger.error(f"Connection reset by {client}, disconnect: {e}")
|
self.logger.error(f"Connection reset by {client}, disconnect: {e}")
|
||||||
self._disconnect(client)
|
self._disconnect(client)
|
||||||
@@ -176,7 +189,14 @@ class BackendServer:
|
|||||||
self.server_socket.close()
|
self.server_socket.close()
|
||||||
self.logger.info("Server has stopped.")
|
self.logger.info("Server has stopped.")
|
||||||
|
|
||||||
# def get_client_data(
|
def get_client_data(self, client_id: str) -> dict[str, Any] | None:
|
||||||
# self, client_id: str
|
client: Client | None = self.clients.get(client_id, None)
|
||||||
# ) -> dict[str, dict[str, Any]] | None:
|
if client is None:
|
||||||
# return self.clients.get(client_id, None)
|
self.logger.warning(f"Client {client_id} not found")
|
||||||
|
return None
|
||||||
|
return {
|
||||||
|
"id": client.id,
|
||||||
|
"addr": client.addr,
|
||||||
|
"last_seen": client.last_seen,
|
||||||
|
"status": client.status,
|
||||||
|
}
|
||||||
|
|||||||
58
src/judas_server/backend/client.py
Normal file
58
src/judas_server/backend/client.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Client representation."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging as lg
|
||||||
|
import socket
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class ClientStatus(str, Enum):
|
||||||
|
CONNECTED = "connected"
|
||||||
|
DISCONNECTED = "disconnected"
|
||||||
|
|
||||||
|
|
||||||
|
class Client:
|
||||||
|
"""Represents a client."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, id_: str, addr: tuple[str, int], socket: socket.socket
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the client.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id_ (str): The unique identifier for the client.
|
||||||
|
addr (tuple[str, int]): The (IP, port) address of the client.
|
||||||
|
socket (socket.socket): The socket object for communication.
|
||||||
|
"""
|
||||||
|
self.logger: lg.Logger = lg.getLogger(
|
||||||
|
f"{__name__}.{self.__class__.__name__}"
|
||||||
|
)
|
||||||
|
self.logger.debug(f"Initializing Client {addr}...")
|
||||||
|
|
||||||
|
self.id: str = id_
|
||||||
|
self.last_seen: float = 0.0 # unix timestanp of last inbound message
|
||||||
|
self.status: ClientStatus = ClientStatus.CONNECTED
|
||||||
|
|
||||||
|
self.socket: socket.socket = socket
|
||||||
|
self.addr: tuple[str, int] = addr
|
||||||
|
self.inbound: bytes = b""
|
||||||
|
self.outbound: bytes = b""
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"Client({self.id} ({self.addr[0]}:{self.addr[1]}))"
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"Client({self.id}, {self.addr})"
|
||||||
|
|
||||||
|
def disconnect(self) -> None:
|
||||||
|
"""Disconnect the client and close the socket."""
|
||||||
|
self.logger.debug(f"Disconnecting Client {self}...")
|
||||||
|
try:
|
||||||
|
self.socket.close()
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error closing socket for Client {self}: {e}")
|
||||||
|
self.status = ClientStatus.DISCONNECTED
|
||||||
|
self.logger.info(f"Client {self} disconnected.")
|
||||||
43
src/judas_server/gaga.py
Normal file
43
src/judas_server/gaga.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""ASCII art of Lady Gaga's Born This Way album cover."""
|
||||||
|
|
||||||
|
from judas_server import __version__
|
||||||
|
|
||||||
|
LADY_GAGA: str = """
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢔⢑⠔⡁⡂⢅⠢⠃⢆⢊⠜⡩⠳⣕⣙⡪⡪⡢⣫⢺⢔⢵⢱⢕⢮⢮⢺⡢⢕⠕⡽⣘⢜⠳⣌⢢⠀⠀⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⢰⣶⣆⢰⠰⡄⢢⣶⣶⢐⠂⡑⡐⢆⢊⠔⠌⢌⢂⠢⠡⢂⠅⢍⢲⣉⡙⢜⡘⢎⣗⢵⢕⡕⡧⡳⡹⣮⣫⢺⢼⡪⣮⡳⡜⡮⡙⠤⠄⢂⠀⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠈⠉⢽⡫⠉⡏⡏⠉⠍⡏⡉⢋⡍⣇⢕⢨⡈⡔⡠⠁⠕⡀⡈⠄⠠⡀⠍⠜⠜⡪⣚⡎⢏⢯⢞⡽⣺⡺⡮⡷⣝⣗⢽⢽⣽⢽⢶⢦⡨⠌⢔⠀⠀⠀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⠀⡠⠨⡪⡹⡸⡑⡕⡑⢄⠕⠄⠔⡈⠜⡈⡂⡂⢅⠁⢂⢅⡪⡨⠒⡜⡾⣘⡪⡣⡻⣷⡻⣯⢿⡺⣗⡿⣽⢽⡽⣞⡽⡫⢷⣆⠑⡄⢀⠀⠀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠀⡀⠄⡕⣪⢞⢜⠌⡎⢜⠔⡡⢊⢰⢌⠎⡐⢄⢎⢢⡁⣂⠥⣌⢪⢪⡱⡹⡵⣎⢮⢯⡸⢝⣾⡽⣞⣿⠺⢝⣯⣿⢯⡳⡝⣄⠊⠻⢬⡢⣑⡀⠀⠀
|
||||||
|
⠀⠀⠀⠀⠀⠀⠠⡐⣼⣪⢯⢽⠢⡃⢊⠊⠜⢬⡢⣟⢮⡣⣕⢵⣱⢵⢵⣳⢯⡷⣯⣞⣞⡮⡯⣗⡯⡪⡫⣎⢷⣻⣿⣺⡿⣼⡿⣝⢽⡷⣝⢆⠁⠀⠈⠝⣖⢦⠀⠀
|
||||||
|
⠀⠀⠀⠀⢀⠨⠰⡱⡵⣯⢿⡝⢌⢐⠀⠂⠨⡠⢹⣺⡵⣳⢕⣯⢾⣻⡯⣿⣻⣿⣽⣾⣟⣿⣯⢿⡽⣳⢵⢕⡯⡿⣾⡮⣿⡿⣮⡫⣷⡻⣟⣧⡑⡐⢀⠐⡸⣕⡇⠠
|
||||||
|
⠀⠀⡀⠐⠄⠅⢕⢝⣽⣻⣯⡇⢅⠢⣁⡊⠆⢜⣮⡺⡽⣺⢽⣞⣿⣽⣟⣯⣿⣾⢿⣾⣿⣽⣾⣿⡽⣯⢿⢽⣯⣻⡽⣿⣟⣿⡸⡹⣷⣯⣟⣯⣷⡄⡂⠀⡍⡖⡷⠀
|
||||||
|
⠐⠀⠀⠨⠀⡘⡌⡇⡗⣟⡾⡊⢔⠅⡆⡌⡪⡘⣮⣞⢿⢽⢽⣺⡿⣾⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⣿⡽⣯⣟⡾⣜⣿⣿⢽⣺⣇⠢⡙⣽⣾⣟⣿⣟⣆⠢⡸⡵⢼⣂
|
||||||
|
⠀⠀⢀⠠⠁⢜⠌⢌⠪⢪⡫⣎⢆⢇⢧⠪⡐⡘⡮⡿⡽⠹⡙⢕⣛⢿⣻⣿⢿⣻⣽⣿⣿⢿⣿⠿⣟⣿⢵⣷⣻⣪⣾⣟⡿⣯⣷⢑⢸⢸⡽⣿⣜⡿⣟⣞⠁⣳⢽⢯
|
||||||
|
⠀⠀⠀⠠⢨⢪⢈⠄⡑⡑⣕⢇⢇⢇⢧⢣⡓⣌⠊⡁⠀⠀⡈⢄⠀⠛⡾⡽⣻⣿⣻⣻⣺⠋⠁⠁⠀⠀⢏⢺⣾⣼⡏⡾⣿⣽⣾⢯⡢⡱⡱⣻⣧⢻⣿⣿⡜⣜⢿⡧
|
||||||
|
⠀⠀⡈⡌⡌⡂⡢⢐⢈⠆⡣⢪⢮⢣⡣⢇⢯⡪⡲⣐⠐⠝⡌⣎⠾⠦⠭⡎⣗⣷⡃⢧⠥⠺⠪⢅⠝⠂⢹⣨⣷⣿⣳⢝⣽⣿⣽⣯⣗⣗⢕⢯⣿⡸⣿⣿⢿⣇⣻⣇
|
||||||
|
⢠⢧⣫⢵⢕⢗⡊⢆⠢⡊⠔⣹⢪⣳⢱⢩⢇⢯⡳⣝⢽⣳⣖⣶⢽⡯⣗⢕⣗⣟⡮⡪⣺⣻⣷⣶⢶⡿⣽⣳⣿⣿⣧⣛⣾⣿⣷⣟⣷⣯⣳⡺⣿⡥⢼⣿⣿⣷⢸⣷
|
||||||
|
⢯⢿⢽⣝⢵⢱⣱⠵⡑⡌⢎⡞⡕⡵⡱⡑⡭⡳⡹⡮⣳⢳⣟⣾⣿⣯⡟⡮⣞⣯⣿⢜⠮⣷⣿⣾⣿⣿⣿⣯⣿⡿⣿⣶⢫⣿⣿⣽⣿⣷⣗⢿⣿⡗⡒⣿⣿⣻⣿⣿
|
||||||
|
⣻⡫⣳⢕⡷⡝⡎⡮⡪⡊⢢⠱⡱⢱⢱⠱⡸⡸⣕⢝⢮⡳⣻⣿⣷⣿⢽⡺⣻⡿⣟⢷⢽⣽⣿⣷⣿⠿⣽⣾⢿⣿⣯⣿⡯⣿⣿⢿⣿⣿⣿⣟⣿⣷⡐⡼⣿⡯⣿⣿
|
||||||
|
⡒⡕⡇⡯⡪⡎⡭⡪⡒⢌⠂⢕⠸⡨⡣⢣⠱⡱⡱⡳⣹⡪⣳⣿⣿⣻⡯⣟⣶⣿⣿⣽⣟⣾⣿⣿⣿⢿⣿⢯⣻⣿⣿⣿⣿⣻⣿⣯⢿⣿⣿⣿⣿⣿⣷⢏⢿⣿⢿⣿
|
||||||
|
⡈⡖⡝⣼⢝⢜⡸⡸⡨⡠⡑⡅⢇⠎⣊⢪⢊⢎⢪⢺⢸⢜⢮⢿⣯⡯⠏⡣⡑⡥⠣⠐⡨⠘⢾⢿⣿⣟⡿⣯⣻⣿⣿⢿⣯⣿⣿⣯⢯⢿⣿⣻⣿⡷⣿⣗⢽⢽⢿⣿
|
||||||
|
⠌⣮⡾⡳⡕⢝⡔⣕⢎⣪⢪⢪⢢⢃⢎⢎⡮⡺⣨⢳⣹⢸⢸⡻⣗⡏⠌⣶⣶⣾⣿⣿⡷⡕⠸⣟⣯⣿⣿⣳⢯⣿⣿⡿⣿⢷⣻⣿⣝⢝⣽⣿⣿⣟⡽⣾⡕⠝⡯⣿
|
||||||
|
⡨⡮⡳⡩⡸⡲⣹⣵⣟⡮⡺⢸⡰⡫⣸⢜⢮⢺⡸⡸⡜⡌⢎⢎⢗⠕⡨⢒⢜⢭⢗⢕⡰⡜⢼⢿⣿⣻⡾⣽⣎⣿⣿⣿⣽⢿⣗⢿⣽⡮⡪⣾⣟⡷⡍⢿⣣⢘⢮⡿
|
||||||
|
⠹⡜⡑⡬⡲⡽⣯⣷⢟⢔⢜⡴⡵⢏⢇⣣⢗⡇⢇⠎⡎⡎⡎⡜⢬⡣⠀⣧⣷⣽⣮⣯⡦⡩⣸⡿⣽⣯⢿⠕⢜⣽⣿⣽⡾⡯⣿⡞⣞⡯⡷⡿⣽⣟⠌⣞⣿⢨⢑⣿
|
||||||
|
⠮⡱⡱⣱⢽⣽⢿⢕⣯⠢⡃⡣⢑⣔⣗⠯⢓⠨⢢⢣⠣⡓⣝⢮⡘⣞⢄⠄⣽⠚⡙⠡⡈⣢⣷⢿⣻⡽⠃⢹⢔⠼⣾⢿⣿⡹⡵⣿⢺⡪⢪⡻⡮⣗⠧⡱⣿⡄⣫⡗
|
||||||
|
⢽⢸⡹⣕⣟⡞⣕⢯⣯⡇⡂⡢⢓⠌⡢⢨⢂⢕⠕⢅⠣⡊⢎⢗⢳⢸⣝⣗⣷⣶⣶⣷⣿⣟⣿⣻⢝⡮⡅⢂⠯⡪⣯⣿⢿⣎⢺⣽⣯⣻⣜⢜⢜⢜⣱⢱⣯⣏⢷⡯
|
||||||
|
⣏⢮⡪⡞⣃⢂⢪⢽⡾⣯⢂⢊⠢⡑⢅⠇⡊⠢⡑⢅⠇⢊⠔⣕⡕⡏⣿⡽⣿⣿⣿⣿⣟⣿⢝⡮⣷⢙⢌⠢⡩⡯⣷⣻⣿⣿⣔⢵⣿⡺⣟⣜⢮⢪⢎⡮⣾⣇⢽⡣
|
||||||
|
⢾⡫⡫⡊⡖⡜⡎⣕⢏⠯⣇⠪⡪⡂⡅⢂⠂⢕⠱⡑⡁⠅⡗⢱⣝⣾⡳⣹⢻⡯⡷⢿⢻⢱⣝⣞⢝⢴⡱⠀⢈⢹⣳⢽⢾⣻⣷⢕⢽⣿⢽⣞⢽⢺⢜⢮⣻⢮⢺⡸
|
||||||
|
⣣⣣⡳⣵⢽⣺⢽⣳⢱⡩⡪⡪⣐⠹⡸⡲⡸⡨⠬⠨⢰⢰⡱⡵⢻⢺⡺⣵⢻⣜⢮⡳⣽⢵⡣⣇⠣⡵⣫⡂⠰⠨⡷⣻⢽⣻⡾⣿⡸⣿⡽⣗⡝⡧⡳⡱⣻⢯⡣⣗
|
||||||
|
⣾⣺⡽⡯⣿⣝⡽⡪⡪⡂⢊⠪⡢⢣⠨⡂⣕⣔⡬⠮⠫⠓⠉⣐⢨⠚⡙⡎⡷⣕⣗⢯⡳⣝⢕⢕⣕⢯⠃⠈⡬⡨⡏⡽⣝⢷⣻⣽⣟⡾⣻⣽⣎⢯⡲⡸⣽⢗⣇⠧
|
||||||
|
⣳⢿⢽⢭⢺⣺⡪⡇⡗⡈⠢⡨⡨⡸⡸⣚⠮⡲⠭⠳⠒⠘⠉⠀⠀⠁⠀⡀⠱⣳⢽⣹⢹⢜⢕⢝⣜⠊⡀⠐⠀⢪⢻⡜⣝⢽⢽⣾⣻⣿⣽⡷⣗⢷⠱⡕⡽⢧⡳⣝
|
||||||
|
⡽⡽⡱⢱⢽⢮⣻⢊⢮⠠⠄⡀⠈⠀⠀⠀⠀⠈⠨⠀⠀⡀⠀⠀⠀⠀⠂⠀⠈⢘⢓⠕⠕⠡⠁⠁⠂⠀⠀⠀⠀⠀⢏⢷⡸⡜⡜⣷⡯⣷⣿⣽⣯⠫⠣⡯⣣⡣⡯⣞
|
||||||
|
⡎⠣⣝⣮⣟⣯⢷⡱⡑⠄⠀⠀⠑⠂⠆⢄⠀⠀⠀⠀⠀⠀⠄⢀⠀⠀⠀⠀⠉⠀⠠⠀⠂⠡⠀⠀⠀⠀⠀⠀⠀⠀⠨⢝⢷⡱⡱⢽⣻⢽⡾⣗⣯⢝⢌⡽⣧⠾⡽⣞
|
||||||
|
⠀⠈⢚⣞⡾⡯⡳⡕⡹⣆⠀⠄⡀⠀⠀⠀⠈⠑⠀⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⡀⠂⠯⣷⢝⢎⡯⡗⣿⣻⢽⠍⠭⠚⢽⡕⣰⢝
|
||||||
|
"""
|
||||||
|
|
||||||
|
# add centered subtitle
|
||||||
|
width: int = LADY_GAGA.index("\n", 1)
|
||||||
|
subtitle: str = f"judas_server {__version__}"
|
||||||
|
padding: int = (width - len(subtitle)) // 2
|
||||||
|
LADY_GAGA += " " * padding + subtitle + "\n"
|
||||||
@@ -52,7 +52,8 @@ def emit_polled_data(app, socketio):
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
for client_id, data in backend.clients.items():
|
for client_id in backend.clients.keys():
|
||||||
|
data = backend.get_client_data(client_id)
|
||||||
socketio.emit("update_data", {client_id: data})
|
socketio.emit("update_data", {client_id: data})
|
||||||
|
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|||||||
Reference in New Issue
Block a user