import ssl import json import sqlite3 import threading from flask import Flask from socketserver import ThreadingMixIn from urllib.parse import urlparse, parse_qs, unquote from consts import SSL_CERT_PATH, SSL_KEY_PATH, HOST, PORT from http.server import HTTPServer, BaseHTTPRequestHandler from server.scheduler import UpdateScheduler from server.consts import LAKE_RELATIONS_PATH from map_handler.add_new_lake import cut_map_handler from map_handler.get_lake_relation import get_map_data_handler from data_processing.input_new_data import input_new_Lidar_data from data_processing.add_new_lidar_measurement import add_new_lidar_measurement from map_handler.update_measurements import update_measurements_handler, add_test_data app = Flask(__name__) terminate_server = 0 class IceHTTPServer(ThreadingMixIn, HTTPServer): def __init__(self, server_address, handler_class, cursor): super().__init__(server_address, handler_class) self.cursor = cursor def get_request(self): request, client_address = super().get_request() return request, client_address # Custom HTTP class class IceHTTP(BaseHTTPRequestHandler): def __init__(self, request, client_address, server): self.cursor = server.cursor super().__init__(request, client_address, server) def do_GET(self): # Root path if self.path == '/': # NB: temporary root path behavior self.send_response(200) self.send_header("Content-type", "text/plain") self.end_headers() self.wfile.write(b"Root path hit!") elif self.path == '/get_lake_names': try: with open(LAKE_RELATIONS_PATH + 'all_lake_names.json', 'r') as file: lake_names = json.load(file) # Disable ensure_ascii to keep 'ΓΈ' json_data = json.dumps(lake_names, ensure_ascii=False) self.send_response(200) self.send_header('Content-type', 'application/json') self.end_headers() self.wfile.write(json_data.encode('iso-8859-1')) # Special character encoding except Exception as e: print(f"Failed to fetch lake list: {e}") self.send_response(500) self.send_header('Content-type', 'application/json') self.end_headers() elif self.path.startswith('/update_map'): parsed_path = urlparse(self.path) query_params = parse_qs(parsed_path.query) lake_name_param = query_params.get('lake', [''])[0] lake_name = unquote(lake_name_param) # Decode url param if lake_name_param: get_map_data_handler(self, lake_name, True) # Get all measurements for selected lake else: self.send_response(400) self.send_header('Content-type', 'application/json') self.end_headers() elif self.path.startswith('/update_measurements'): parsed_path = urlparse(self.path) query_params = parse_qs(parsed_path.query) lake_name_param = query_params.get('lake', [''])[0] lake_name = unquote(lake_name_param) # Decode url param if lake_name_param: update_measurements_handler(self, lake_name) else: self.send_response(400) self.send_header('Content-type', 'application/json') self.end_headers() elif self.path.startswith('/get_relation'): parsed_path = urlparse(self.path) query_params = parse_qs(parsed_path.query) lake_name_param = query_params.get('lake', [''])[0] lake_name = unquote(lake_name_param) # Decode url param get_map_data_handler(self, lake_name, False) elif self.path.startswith('/add_new_lake'): parsed_path = urlparse(self.path) query_params = parse_qs(parsed_path.query) lake_name = query_params.get('lake', [None])[0] if lake_name is not None: cell_size = query_params.get('cell_size', [''])[0] cell_size_param = unquote(cell_size) # Decode url param if cell_size_param: # Check if cell_size_param is not an empty string try: # Try to convert the value to a float and the map cell_size_float = float(cell_size_param) cut_map_handler(self, cursor, lake_name, cell_size_float) except ValueError: print("Error: cell_size_param is not a valid float") else: cut_map_handler(self, cursor, lake_name) else: self.send_response(400) self.send_header('Content-type', 'application/json') self.end_headers() elif self.path.startswith('/add_test_data'): parsed_path = urlparse(self.path) query_params = parse_qs(parsed_path.query) lake_name_param = query_params.get('lake', [''])[0] lake_name = unquote(lake_name_param) # Decode url param add_test_data(self, lake_name) def do_POST(self): if self.path.startswith('/new_lidar_data'): parsed_path = urlparse(self.path) query_params = parse_qs(parsed_path.query) lake_name_param = query_params.get('lake', [''])[0] lake_name = unquote(lake_name_param) # Decode url param if lake_name: input_new_Lidar_data(self.cursor, 1, lake_name) # hardcoded body of water must change later else: self.send_response(400) self.send_header('Content-type', 'application/json') self.end_headers() elif self.path.startswith('/add_measurement_position'): parsed_path = urlparse(self.path) query_params = parse_qs(parsed_path.query) lake_name_param = query_params.get('lake', [''])[0] lake_name = unquote(lake_name_param) # Decode url param lake_lat_param = query_params.get('latitude', [''])[0] lake_lon_param = query_params.get('longitude', [''])[0] try: lake_lat = unquote(lake_lat_param) # Decode url param lake_lon = unquote(lake_lon_param) # Decode url param except ValueError: self.send_response(400, 'Invalid Latitude or Longitude') if lake_name: add_new_lidar_measurement(lake_name, lake_lat, lake_lon) # hardcoded body of water must change later else: self.send_response(400) self.send_header('Content-type', 'application/json') self.end_headers() if __name__ == "__main__": """Start a server on port 8443 using self defined HTTP class""" try: # Run the automatic updating of measurement data in a dedicated thread #scheduler = UpdateScheduler() #scheduler_thread = threading.Thread(target=scheduler.start) #scheduler_thread.start() # Initialize database connection conn = sqlite3.connect('server/database/icedb') cursor = conn.cursor() # Load SSL certificate and private key ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) ssl_context.load_cert_chain(SSL_CERT_PATH, SSL_KEY_PATH) # Create HTTP server with SSL support server = IceHTTPServer((HOST, PORT), IceHTTP, cursor) server.socket = ssl_context.wrap_socket(server.socket, server_side=True) print("Server running on port ", PORT) # Run server indefinitely server.serve_forever() except Exception as e: print(f"Server terminated: {PORT}: {e}")