Many windows compatibility tweaks, new source and updated logger

This commit is contained in:
Thastertyn 2025-02-07 13:30:23 +01:00
parent 756d6d3dd4
commit 1cfc561301
8 changed files with 93 additions and 47 deletions

View File

@ -18,3 +18,7 @@
- [SqlAlchemy session generator](https://stackoverflow.com/a/71053353)
- [Error handling decorator](https://chatgpt.com/share/67a46109-d38c-8005-ac36-677e6511ddcd)
### Platform specific problems
- [Windows sends partial data](https://stackoverflow.com/a/31754798)

View File

@ -46,8 +46,6 @@ class BankNode():
# Handle windows related signals
if sys.platform == "win32":
signal.signal(signal.CTRL_C_EVENT, self.gracefully_exit)
signal.signal(signal.CTRL_BREAK_EVENT, self.gracefully_exit)
signal.signal(signal.SIGBREAK, self.gracefully_exit)
def start(self):
@ -78,6 +76,7 @@ class BankNode():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as socket_server:
socket_server.bind((self.config.ip, port))
socket_server.listen()
socket_server.setblocking(True)
self.socket_server = socket_server
self.logger.info("Listening on %s:%s", self.config.ip, port)

View File

@ -8,21 +8,20 @@ import sys
from bank_protocol.command_handler import CommandHandler
from core import Request, Response, BankNodeConfig
from core.exceptions import BankNodeError
from utils.logger import setup_logger
class BankWorker(multiprocessing.Process):
def __init__(self, client_socket: socket.socket, client_address: Tuple, config: BankNodeConfig):
super().__init__()
self.logger = logging.getLogger(__name__)
self.client_socket = client_socket
self.client_socket.settimeout(config.client_idle_timeout)
self.client_address = client_address
self.command_handler = CommandHandler(config)
self.config = config
self.logger = None
self.command_handler = None
def __setup_signals(self):
self.logger.debug("Setting up exit signal hooks for worker")
@ -32,27 +31,60 @@ class BankWorker(multiprocessing.Process):
# Handle windows related signals
if sys.platform == "win32":
signal.signal(signal.CTRL_C_EVENT, self.gracefully_exit_worker)
signal.signal(signal.CTRL_BREAK_EVENT, self.gracefully_exit_worker)
signal.signal(signal.SIGBREAK, self.gracefully_exit_worker)
def run(self):
# Logging behaves weirdly with processes on windows
# and loses its configuration by default
# -> Set it up again in the fresh process
if sys.platform == "win32":
setup_logger(self.config.verbosity)
self.logger = logging.getLogger(__name__)
self.command_handler = CommandHandler(self.config)
self.client_socket.settimeout(self.config.client_idle_timeout)
self.client_socket.setblocking(True)
self.__setup_signals()
with self.client_socket:
self.serve_client()
self.logger.debug("Closing process for %s", self.client_address[0])
def serve_client(self):
buffer = ""
while True:
try:
raw_request = self.client_socket.recv(1024).decode("utf-8")
data = self.client_socket.recv(1024).decode("utf-8")
if not raw_request:
if not data:
self.logger.debug("%s disconnected", self.client_address[0])
break
request = Request(raw_request)
self.logger.debug("Received request from %s - %s", self.client_address[0], request)
buffer += data
self.logger.debug("Buffer updated: %r", buffer)
response: Response = self.command_handler.execute(request) + "\n\r"
if "\r\n" in buffer:
self.logger.debug("CRLF detected")
request_data, buffer = buffer.split("\r\n", 1)
elif "\n" in buffer:
self.logger.debug("LF detected")
request_data, buffer = buffer.split("\n", 1)
elif "\r" in buffer:
self.logger.debug("CR detected")
request_data, buffer = buffer.split("\r", 1)
else:
continue
self.logger.debug("Processing request: %r", request_data)
request = Request(request_data)
response: Response = self.command_handler.execute(request) + "\r\n"
self.client_socket.sendall(response.encode("utf-8"))
self.logger.debug("Response sent to %s", self.client_address[0])
except socket.timeout:
self.logger.debug("Client was idle for too long. Ending connection")
@ -74,8 +106,6 @@ class BankWorker(multiprocessing.Process):
response = "ER Internal server error\n\r"
break
self.logger.debug("Closing process for %s", self.client_address[0])
def gracefully_exit_worker(self, signum, _):
"""Log the signal caught and exit with status 0"""

View File

@ -3,18 +3,22 @@ import socket
import threading
import logging
class BankScanner():
from core.peer import Peer
class BankScanner(threading.Thread):
def __init__(self, host: str, port_start: int, port_end: int):
self.logger = logging.getLogger(__name__)
self.host = host
self.port_start = port_start
self.port_end = port_end
self.peer = Peer()
def scan(self) -> Optional[socket]:
threads = []
for port in range(self.port_start, self.port_end + 1):
t = threading.Thread(target=self.__probe_for_open_ports, args=(self.host, port,), name=f"ScannerThread-{self.host}:{port}")
t = threading.Thread(target=self.__probe_for_open_ports, args=(self.host, port,), name=f"BankScannerThread-{self.host}:{port}")
threads.append(t)
def __probe_for_open_ports(self, host: str, port: int) -> Optional[socket]:

View File

@ -36,6 +36,8 @@ class CommandHandler:
self.logger.warning("Unknown command %s", request.command_code)
raise BankNodeError(f"Unknown command {request.command_code}")
self.logger.debug("Serving %s", request.command_code)
command = self.registered_commands[request.command_code]
try:
response = command(request, self.config)

View File

@ -0,0 +1,2 @@
class Peer():
pass

View File

@ -1,15 +1,20 @@
import re
from bank_protocol.exceptions import InvalidRequest
import logging
class Request():
def __init__(self, raw_request: str):
logger = logging.getLogger(__name__)
if re.match(r"^[A-Z]{2}$", raw_request):
logger.debug("Found 2 char command")
self.command_code = raw_request[0:2] # Still take the first 2 characters, because of lingering crlf
self.body = None
elif re.match(r"^[A-Z]{2} .+", raw_request):
logger.debug("Found command with arguments")
command_code: str = raw_request[0:2]
body: str = raw_request[3:-1] or ""

View File

@ -4,7 +4,7 @@ import logging
def setup_logger(verbosity: str):
if verbosity == "DEBUG":
log_format = "[ %(levelname)s / %(processName)s ] - %(name)s:%(lineno)d - %(message)s"
log_format = "[ %(levelname)s / %(processName)s ] - %(module)s/%(filename)s:%(lineno)d - %(message)s"
else:
log_format = "[ %(levelname)s ] - %(message)s"