Many windows compatibility tweaks, new source and updated logger
This commit is contained in:
parent
756d6d3dd4
commit
1cfc561301
@ -18,3 +18,7 @@
|
|||||||
|
|
||||||
- [SqlAlchemy session generator](https://stackoverflow.com/a/71053353)
|
- [SqlAlchemy session generator](https://stackoverflow.com/a/71053353)
|
||||||
- [Error handling decorator](https://chatgpt.com/share/67a46109-d38c-8005-ac36-677e6511ddcd)
|
- [Error handling decorator](https://chatgpt.com/share/67a46109-d38c-8005-ac36-677e6511ddcd)
|
||||||
|
|
||||||
|
### Platform specific problems
|
||||||
|
|
||||||
|
- [Windows sends partial data](https://stackoverflow.com/a/31754798)
|
@ -46,8 +46,6 @@ class BankNode():
|
|||||||
|
|
||||||
# Handle windows related signals
|
# Handle windows related signals
|
||||||
if sys.platform == "win32":
|
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)
|
signal.signal(signal.SIGBREAK, self.gracefully_exit)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
@ -78,6 +76,7 @@ class BankNode():
|
|||||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as socket_server:
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as socket_server:
|
||||||
socket_server.bind((self.config.ip, port))
|
socket_server.bind((self.config.ip, port))
|
||||||
socket_server.listen()
|
socket_server.listen()
|
||||||
|
socket_server.setblocking(True)
|
||||||
self.socket_server = socket_server
|
self.socket_server = socket_server
|
||||||
self.logger.info("Listening on %s:%s", self.config.ip, port)
|
self.logger.info("Listening on %s:%s", self.config.ip, port)
|
||||||
|
|
||||||
|
@ -8,21 +8,20 @@ import sys
|
|||||||
from bank_protocol.command_handler import CommandHandler
|
from bank_protocol.command_handler import CommandHandler
|
||||||
from core import Request, Response, BankNodeConfig
|
from core import Request, Response, BankNodeConfig
|
||||||
from core.exceptions import BankNodeError
|
from core.exceptions import BankNodeError
|
||||||
|
from utils.logger import setup_logger
|
||||||
|
|
||||||
|
|
||||||
class BankWorker(multiprocessing.Process):
|
class BankWorker(multiprocessing.Process):
|
||||||
def __init__(self, client_socket: socket.socket, client_address: Tuple, config: BankNodeConfig):
|
def __init__(self, client_socket: socket.socket, client_address: Tuple, config: BankNodeConfig):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
self.client_socket = client_socket
|
self.client_socket = client_socket
|
||||||
self.client_socket.settimeout(config.client_idle_timeout)
|
|
||||||
self.client_address = client_address
|
self.client_address = client_address
|
||||||
|
|
||||||
self.command_handler = CommandHandler(config)
|
|
||||||
self.config = config
|
self.config = config
|
||||||
|
|
||||||
|
self.logger = None
|
||||||
|
self.command_handler = None
|
||||||
|
|
||||||
def __setup_signals(self):
|
def __setup_signals(self):
|
||||||
self.logger.debug("Setting up exit signal hooks for worker")
|
self.logger.debug("Setting up exit signal hooks for worker")
|
||||||
|
|
||||||
@ -32,50 +31,81 @@ class BankWorker(multiprocessing.Process):
|
|||||||
|
|
||||||
# Handle windows related signals
|
# Handle windows related signals
|
||||||
if sys.platform == "win32":
|
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)
|
signal.signal(signal.SIGBREAK, self.gracefully_exit_worker)
|
||||||
|
|
||||||
def run(self):
|
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()
|
self.__setup_signals()
|
||||||
|
|
||||||
with self.client_socket:
|
with self.client_socket:
|
||||||
while True:
|
self.serve_client()
|
||||||
try:
|
|
||||||
raw_request = self.client_socket.recv(1024).decode("utf-8")
|
|
||||||
|
|
||||||
if not raw_request:
|
|
||||||
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)
|
|
||||||
|
|
||||||
response: Response = self.command_handler.execute(request) + "\n\r"
|
|
||||||
|
|
||||||
self.client_socket.sendall(response.encode("utf-8"))
|
|
||||||
|
|
||||||
except socket.timeout:
|
|
||||||
self.logger.debug("Client was idle for too long. Ending connection")
|
|
||||||
response = "ER Idle too long\n\r"
|
|
||||||
self.client_socket.sendall(response.encode("utf-8"))
|
|
||||||
self.client_socket.shutdown(socket.SHUT_RDWR)
|
|
||||||
self.client_socket.close()
|
|
||||||
break
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
self.logger.warning("Received a non utf-8 message")
|
|
||||||
response = "ER Not utf-8 message"
|
|
||||||
self.client_socket.sendall(response.encode("utf-8"))
|
|
||||||
break
|
|
||||||
except BankNodeError as e:
|
|
||||||
response = "ER " + e.message + "\n\r"
|
|
||||||
self.client_socket.sendall(response.encode("utf-8"))
|
|
||||||
except socket.error as e:
|
|
||||||
self.logger.error(e)
|
|
||||||
response = "ER Internal server error\n\r"
|
|
||||||
break
|
|
||||||
|
|
||||||
self.logger.debug("Closing process for %s", self.client_address[0])
|
self.logger.debug("Closing process for %s", self.client_address[0])
|
||||||
|
|
||||||
|
def serve_client(self):
|
||||||
|
buffer = ""
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
data = self.client_socket.recv(1024).decode("utf-8")
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
self.logger.debug("%s disconnected", self.client_address[0])
|
||||||
|
break
|
||||||
|
|
||||||
|
buffer += data
|
||||||
|
self.logger.debug("Buffer updated: %r", buffer)
|
||||||
|
|
||||||
|
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")
|
||||||
|
response = "ER Idle too long\n\r"
|
||||||
|
self.client_socket.sendall(response.encode("utf-8"))
|
||||||
|
self.client_socket.shutdown(socket.SHUT_RDWR)
|
||||||
|
self.client_socket.close()
|
||||||
|
break
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
self.logger.warning("Received a non utf-8 message")
|
||||||
|
response = "ER Not utf-8 message"
|
||||||
|
self.client_socket.sendall(response.encode("utf-8"))
|
||||||
|
break
|
||||||
|
except BankNodeError as e:
|
||||||
|
response = "ER " + e.message + "\n\r"
|
||||||
|
self.client_socket.sendall(response.encode("utf-8"))
|
||||||
|
except socket.error as e:
|
||||||
|
self.logger.error(e)
|
||||||
|
response = "ER Internal server error\n\r"
|
||||||
|
break
|
||||||
|
|
||||||
def gracefully_exit_worker(self, signum, _):
|
def gracefully_exit_worker(self, signum, _):
|
||||||
"""Log the signal caught and exit with status 0"""
|
"""Log the signal caught and exit with status 0"""
|
||||||
|
|
||||||
|
@ -3,18 +3,22 @@ import socket
|
|||||||
import threading
|
import threading
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
class BankScanner():
|
from core.peer import Peer
|
||||||
|
|
||||||
|
|
||||||
|
class BankScanner(threading.Thread):
|
||||||
def __init__(self, host: str, port_start: int, port_end: int):
|
def __init__(self, host: str, port_start: int, port_end: int):
|
||||||
self.logger = logging.getLogger(__name__)
|
self.logger = logging.getLogger(__name__)
|
||||||
self.host = host
|
self.host = host
|
||||||
self.port_start = port_start
|
self.port_start = port_start
|
||||||
self.port_end = port_end
|
self.port_end = port_end
|
||||||
|
self.peer = Peer()
|
||||||
|
|
||||||
def scan(self) -> Optional[socket]:
|
def scan(self) -> Optional[socket]:
|
||||||
threads = []
|
threads = []
|
||||||
|
|
||||||
for port in range(self.port_start, self.port_end + 1):
|
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)
|
threads.append(t)
|
||||||
|
|
||||||
def __probe_for_open_ports(self, host: str, port: int) -> Optional[socket]:
|
def __probe_for_open_ports(self, host: str, port: int) -> Optional[socket]:
|
||||||
|
@ -36,6 +36,8 @@ class CommandHandler:
|
|||||||
self.logger.warning("Unknown command %s", request.command_code)
|
self.logger.warning("Unknown command %s", request.command_code)
|
||||||
raise BankNodeError(f"Unknown command {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]
|
command = self.registered_commands[request.command_code]
|
||||||
try:
|
try:
|
||||||
response = command(request, self.config)
|
response = command(request, self.config)
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
class Peer():
|
||||||
|
pass
|
@ -1,15 +1,20 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from bank_protocol.exceptions import InvalidRequest
|
from bank_protocol.exceptions import InvalidRequest
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
class Request():
|
class Request():
|
||||||
|
|
||||||
def __init__(self, raw_request: str):
|
def __init__(self, raw_request: str):
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
if re.match(r"^[A-Z]{2}$", raw_request):
|
if re.match(r"^[A-Z]{2}$", raw_request):
|
||||||
self.command_code = raw_request[0:2] # Still take the first 2 characters, because of lingering crlf
|
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
|
self.body = None
|
||||||
elif re.match(r"^[A-Z]{2} .+", raw_request):
|
elif re.match(r"^[A-Z]{2} .+", raw_request):
|
||||||
|
logger.debug("Found command with arguments")
|
||||||
command_code: str = raw_request[0:2]
|
command_code: str = raw_request[0:2]
|
||||||
body: str = raw_request[3:-1] or ""
|
body: str = raw_request[3:-1] or ""
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import logging
|
|||||||
|
|
||||||
def setup_logger(verbosity: str):
|
def setup_logger(verbosity: str):
|
||||||
if verbosity == "DEBUG":
|
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:
|
else:
|
||||||
log_format = "[ %(levelname)s ] - %(message)s"
|
log_format = "[ %(levelname)s ] - %(message)s"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user