import threading import time import flask from werkzeug.serving import make_server import logging class Server: """ This server does NOT use Flask's built-in development server. Instead, it uses Werkzeug's make_server to create a WSGI server. This server is thread-safe and can be stopped by setting the stop_event. This server works as a chat server by polling, not by using websockets (to keep it simple). """ def __init__(self, host: str, port: int, stop_event: threading.Event): self.host = host self.port = port self.stop_event = stop_event # Flask definition self.flask = flask.Flask(__name__) self.flask.add_url_rule('/status', methods=['POST'], view_func=self.status) self.flask.add_url_rule('/send_message', methods=['POST'], view_func=self.send_message) self.flask.add_url_rule('/get_messages', methods=['POST'], view_func=self.get_messages) self.server = make_server(self.host, self.port, self.flask) self.watcher_thread = threading.Thread(target=self.__watcher) self.server_thread = threading.Thread(target=self.server.serve_forever) self.server_thread.start() self.watcher_thread.start() log = logging.getLogger('werkzeug') log.setLevel(logging.ERROR) self.flask.logger.setLevel(logging.ERROR) # Message initialization self.message_id = 0 self.messages = self.__init_messages() def __watcher(self): while not self.stop_event.is_set(): time.sleep(1) self.shutdown() def shutdown(self): self.__persist_messages() self.server.shutdown() def __init_messages(self): messages = [] try: with open('chat_server/messages.txt', 'r') as f: for line in f: parts = line.strip().split('|') messages.append({ 'id': int(parts[0]), 'sender': parts[1], 'content': parts[2] }) self.message_id = messages[-1]['id'] if messages else 0 except FileNotFoundError: with open('chat_server/messages.txt', 'w+') as f: pass return messages def __persist_messages(self): with open('chat_server/messages.txt', 'w') as f: for message in self.messages: f.write(f"{message['id']}|{message['sender']}|{message['content']}\n") def status(self): return 'OK' def send_message(self): sender = flask.request.json['sender'] content = flask.request.json['content'] self.message_id += 1 message = { 'id': self.message_id, 'sender': sender, 'content': content } self.messages.append(message) return {'id': self.message_id} def get_messages(self): try: last_id = flask.request.json.get('last_id') # last_id is a mandatory parameter except AttributeError: return flask.Response('Last ID not specified', status=400) new_messages = [msg for msg in self.messages if msg['id'] > last_id] return {'messages': new_messages}