95 lines
3.2 KiB
Python
95 lines
3.2 KiB
Python
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}
|