diff --git a/__main__.py b/__main__.py index 348693e..96f0475 100644 --- a/__main__.py +++ b/__main__.py @@ -8,7 +8,7 @@ if __name__ == "__main__": try: asyncio.run(obj_server.start_server()) - except asyncio.exceptions.CancelledError: - pass + except KeyboardInterrupt: + logging.warning("Server wurde manuell beendet") except Exception as e: logging.critical(f"Global error: {e}") \ No newline at end of file diff --git a/app/cfg/settings.yaml b/app/cfg/settings.yaml index 8b55122..c56e9f5 100644 --- a/app/cfg/settings.yaml +++ b/app/cfg/settings.yaml @@ -2,7 +2,7 @@ log_file: "server.log" log_level: DEBUG log_rotation: time path_file: "media_path.yaml" -server_ip: "127.0.0.1" +server_ip: "0.0.0.0" server_port: 8000 task_max: 1 autostart: true diff --git a/app/class_file_convert.py b/app/class_file_convert.py index 9d5c7d3..419f3f9 100644 --- a/app/class_file_convert.py +++ b/app/class_file_convert.py @@ -39,7 +39,7 @@ class Convert: """Startet die Videokonvertierung asynchron.""" obj_process = Process(self.obj_websocket) - obj_stat = Stat(obj) + obj_stat = Stat() obj.convert_start = time.time() command = self.convert_cmd(obj) @@ -79,7 +79,7 @@ class Convert: self.active_process.discard(obj) self.active_tasks.discard(obj) self.obj_path.save_paths() - obj_stat.save_stat() + obj_stat.save_stat(obj) obj.convert_end = time.time() diff --git a/app/class_media_file.py b/app/class_media_file.py index e9c423e..d245e16 100644 --- a/app/class_media_file.py +++ b/app/class_media_file.py @@ -18,6 +18,7 @@ class Media: # target self.target_file: str = f"{path.rsplit(".", 1)[0]}.webm" + self.target_file_name: str = os.path.basename(self.target_file) self.target_size: int = 0 # process @@ -85,6 +86,7 @@ class Media: def to_dict_stat(self): return {self.id: { # source + "source_file_name": self.source_file_name, "source_file": self.source_file, "source_duration": self.source_duration, "source_size": self.source_size, @@ -93,6 +95,7 @@ class Media: "source_time": self.source_time, # target + "target_file_name": self.target_file_name, "target_file": self.target_file, "target_size": self.target_size, diff --git a/app/class_media_file_stat.py b/app/class_media_file_stat.py index cd71d11..d45c8cb 100644 --- a/app/class_media_file_stat.py +++ b/app/class_media_file_stat.py @@ -2,25 +2,29 @@ import yaml import os class Stat: - def __init__(self, obj): - self.obj = obj + def __init__(self): + self.path = "app/cfg/statistic.yaml" - def save_stat(self): - pfad = "app/cfg/statistic.yaml" + def save_stat(self, obj): - # Bestehende Daten laden - if os.path.exists(pfad): - with open(pfad, "r", encoding="utf8") as file: - daten = yaml.safe_load(file) or {} - else: - daten = {} + daten = self.read_stat() # Videosammlung initialisieren, falls nötig daten.setdefault("videos", {}) # Neuen Eintrag hinzufügen - daten["videos"].update(self.obj.to_dict_stat()) + daten["videos"].update(obj.to_dict_stat()) # Datei mit aktualisierten Daten speichern - with open(pfad, "w", encoding="utf8") as file: - yaml.dump(daten, file, default_flow_style=False, indent=4, allow_unicode=True) \ No newline at end of file + with open(self.path, "w", encoding="utf8") as file: + yaml.dump(daten, file, default_flow_style=False, indent=4, allow_unicode=True) + + def read_stat(self): + # Bestehende Daten laden + if os.path.exists(self.path): + with open(self.path, "r", encoding="utf8") as file: + daten = yaml.safe_load(file) or {} + else: + daten = {} + + return daten \ No newline at end of file diff --git a/app/main_server.py b/app/main_server.py index 14b01d8..d21cc47 100644 --- a/app/main_server.py +++ b/app/main_server.py @@ -4,12 +4,14 @@ import websockets import json import logging +from asyncio import CancelledError from websockets import InvalidUpgrade, ConnectionClosed, ConnectionClosedError from aiohttp import web from app.class_settings import Settings from app.class_file_path import Path from app.class_file_convert import Convert +from app.class_media_file_stat import Stat var_convert_active = False @@ -56,14 +58,14 @@ class Server: elif data.get("data_message"): logging.info(f"Server hat Empfangen: {data.get('data_message')}") - except (ConnectionClosedError, InvalidUpgrade): - pass - except json.JSONDecodeError as e: - logging.error(f"JSON Fehler: {e}") - except ConnectionClosed: - logging.error("Server sagt: Client getrennt") + except (ConnectionClosedError, ConnectionClosed): + logging.warning("Client Verbindung geschlossen") + except InvalidUpgrade: + logging.warning("Ungültiger Websocket Upgrade versuch") + except Exception as e: + logging.error(f"Unerwarteter Fehler {e}") finally: - self.clients.remove(websocket) + self.clients.discard(websocket) @staticmethod def set_var_convert_active(value: bool): @@ -87,10 +89,16 @@ class Server: port = self.yaml.get("server_port", 8000) return web.json_response({"server_ip": ip, "server_port": port}) + @staticmethod + async def handle_stat(request): + obj_stat = Stat() + return web.json_response(obj_stat.read_stat()) + async def server_http(self): app = web.Application() app.router.add_get("/", self.handle_index) app.router.add_get("/api/ip", self.handle_ip) + app.router.add_get("/api/stats", self.handle_stat) app.router.add_static("/client", path="./client", name="client") runner = web.AppRunner(app) await runner.setup() @@ -101,7 +109,12 @@ class Server: # Start Server ----------------------------------------------------------------------------------------------------- async def start_server(self): - await asyncio.gather( - self.server_websocket(), - self.server_http() - ) + try: + await asyncio.gather( + self.server_websocket(), + self.server_http() + ) + except CancelledError: + logging.warning("Server wurde durch Keyboard Interrupt gestoppt.") + except Exception as e: + logging.error(f"Unerwarteter Fehler beim Starten des Servers {e}") diff --git a/client b/client deleted file mode 160000 index 9cbce74..0000000 --- a/client +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9cbce7415d2429d2132afb3b1d985c09f6ddd7f2 diff --git a/client/client.js b/client/client.js new file mode 100755 index 0000000..70c3b93 --- /dev/null +++ b/client/client.js @@ -0,0 +1,84 @@ +/** + * @returns {Promise<{server_ip: string, server_port: number}>} + */ +async function getServerConfig() { + const response = await fetch('/api/ip'); + return await response.json(); +} + +async function getMediaStat() { + const response = await fetch('/api/stats'); + return await response.json(); +} + +getServerConfig() + .then(data => { + const websocketIp = data.server_ip; + const websocketPort = data.server_port; + const ws = new WebSocket(`ws://${websocketIp}:${websocketPort}`); + + ws.onopen = function() { + console.log("WebSocket ist geöffnet"); + ws.send(JSON.stringify({"data_message": "Server Adresse: " + websocketIp + ":" + websocketPort})); + }; + + ws.onmessage = function(messageEvent) { + console.log(messageEvent.data); + }; + + ws.onclose = function() { + console.log("WebSocket wurde geschlossen"); + }; + + ws.onerror = function(errorEvent) { + console.error("WebSocket-Fehler: ", errorEvent); + }; + }) + .catch(error => { + console.error('Error fetching settings:', error); + }); + +getMediaStat() + .then(data => { + console.log("Antwort von /api/stats:", data); // Debug-Ausgabe + + if (!data || typeof data !== 'object' || !data.videos || typeof data.videos !== 'object') { + throw new Error("Ungültiges Antwortformat oder fehlende 'videos'-Eigenschaft"); + } + + const stat_Container = document.getElementById('stat'); + + Object.keys(data.videos).forEach(key => { + const video = data.videos[key]; + const card = document.createElement('div'); + card.className = 'video-card'; + card.id = key + + card.innerHTML = ` +
Hier könnten Diagramme, Durchschnittswerte etc. angezeigt werden.
+