From 3a34e504329d4f0c42f27a979b37220ba1907410 Mon Sep 17 00:00:00 2001 From: Untriex Programming Date: Sun, 21 Mar 2021 12:52:55 +0100 Subject: [PATCH] Online updates/save heartbeat table etc. News: - Online updates from test github repository - Removing offline clients after selected period of time - Saving heartbeat table (can be disabled) Added system.py it is handeling updates and cleaning of logs/heartbeat table. In the future should be able to fix errors in case program crashes. --- server/.idea/vcs.xml | 6 ++++ server/.idea/workspace.xml | 55 +++++++++++++++++++++++++++++ server/engine.py | 17 +++++++++ server/main.py | 41 ++++++++++++++++++---- server/setup.py | 12 ------- server/system.py | 72 ++++++++++++++++++++++++++++++++++++++ server/test.json | 47 ------------------------- server/test.py | 60 ------------------------------- server/version.json | 7 ++-- 9 files changed, 188 insertions(+), 129 deletions(-) create mode 100644 server/.idea/vcs.xml create mode 100644 server/.idea/workspace.xml delete mode 100644 server/setup.py create mode 100644 server/system.py delete mode 100644 server/test.json delete mode 100644 server/test.py diff --git a/server/.idea/vcs.xml b/server/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/server/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/server/.idea/workspace.xml b/server/.idea/workspace.xml new file mode 100644 index 0000000..d092fe3 --- /dev/null +++ b/server/.idea/workspace.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + 1616004808992 + + + + + + + \ No newline at end of file diff --git a/server/engine.py b/server/engine.py index 1d0a044..95d9566 100644 --- a/server/engine.py +++ b/server/engine.py @@ -1,4 +1,6 @@ from datetime import datetime +import json +import requests class Log: @@ -38,3 +40,18 @@ class Log: def debug(self, debug): if self.debug_e: print(f"{datetime.now()} -> DEBUG: {debug}") + + +class Update: + def __init__(self): + with open("version.json", "r") as f: # loading settings + version = json.load(f) + self.url = version["url"] + self.version = version["version"] + self.id = version["id"] + + def get_updates(self): + return json.loads(requests.get(self.url).text) + + def get_version(self): + return {"version": self.version, "id": self.id} \ No newline at end of file diff --git a/server/main.py b/server/main.py index 1ec9f9c..42a6f21 100644 --- a/server/main.py +++ b/server/main.py @@ -1,5 +1,5 @@ from fastapi import FastAPI, Request -from fastapi.responses import FileResponse +from fastapi.responses import FileResponse, HTMLResponse from pydantic import BaseModel import engine import requests @@ -18,10 +18,13 @@ with open("filesystem.json", "r") as f: # loading settings IP = settings["IP"] ID = settings["ID"] location = settings["location"] +time_to_save = settings["time_to_save"] app = FastAPI() # init of FastAPI log = engine.Log(settings["log"]) # init of LOG +update = engine.Update() offline = [] +save_time = time.time() time_to_heartbeat = settings["time_to_heartbeat"] # Raspberry will be requesting heartbeat every __ seconds time_to_heartbeat_offline = settings[ @@ -141,6 +144,14 @@ def get_devices_list(): return heartbeat_table["file_system"] +@app.get("/admin/{command}") +def admin(command: str): + if command == "get_updates": + return [update.get_version(), update.get_updates()] + if "update-" in command: + os.system(f"""python3 system.py update -version {command.split("-")[1]}""") + + def send_heartbeat(ip, id): global heartbeat_table log.message(f"""sending heartbeat to {ip}({"offline" if id in offline else "online"})""") @@ -150,6 +161,7 @@ def send_heartbeat(ip, id): def mainloop(): + global save_time while True: for device_number, device_ID in enumerate(heartbeat_table["ID"]): if device_ID != ID: @@ -160,22 +172,37 @@ def mainloop(): if heartbeat_table["ID"][device_number] not in offline: log.warning(f"""{heartbeat_table["IP"][device_number]} disconnected/is not available""") offline.append(heartbeat_table["ID"][device_number]) - heartbeat_table["last_heartbeat"][int(device_number)] = int(time_to_heartbeat_offline) + heartbeat_table["last_heartbeat"][int(device_number)] = int(time_to_heartbeat_offline) + else: + offline.remove(heartbeat_table["ID"][device_number]) + log.message(f"""Removing {device_ID} because of long inactivity.""") + del heartbeat_table["ID"][device_number] + del heartbeat_table["IP"][device_number] + del heartbeat_table["location"][device_number] + del heartbeat_table["file_system"][device_number] + del heartbeat_table["last_heartbeat"][device_number] else: if heartbeat_table["ID"][device_number] in offline: offline.remove(heartbeat_table["ID"][device_number]) log.message(f"""{heartbeat_table["IP"][device_number]} gone online""") heartbeat_table["last_heartbeat"][int(device_number)] = int(time_to_heartbeat) + 5 - log.debug(f"""{device_ID} : time to heartbeat : {heartbeat_table["last_heartbeat"][device_number]}""") - heartbeat_table["last_heartbeat"][device_number] -= 1 + try: + log.debug(f"""{device_ID} : time to heartbeat : {heartbeat_table["last_heartbeat"][device_number]}""") + heartbeat_table["last_heartbeat"][device_number] -= 1 + except IndexError: + pass + if time.time() - time_to_save > save_time and settings["save_table"]: + save_time = time.time() + log.message("Saving heartbeat table.") + log.debug(f"Saving heartbeat table: {heartbeat_table}") + settings["heartbeat_table"] = heartbeat_table + with open("settings.json", "w") as file: + json.dump(settings, file, indent=2) time.sleep(1) thread_1 = threading.Thread(target=mainloop, daemon=True) thread_1.start() -# Todo in next release: disconnect offline client after set time -# Todo send to mobile # Todo new filesystem handeling -# Todo implement update system # Todo settings for easy adding/editing files/id/text \ No newline at end of file diff --git a/server/setup.py b/server/setup.py deleted file mode 100644 index 88d6fa2..0000000 --- a/server/setup.py +++ /dev/null @@ -1,12 +0,0 @@ -import tkinter -import json -height = 750 -width = 1200 -with open("settings.json", "r") as file: - settings = json.load(file) -with open("settings.json", "r") as file: - filesystem = json.load(file) -canvas = tkinter.Canvas(height=height, width=width) -canvas.pack() - -canvas.mainloop() \ No newline at end of file diff --git a/server/system.py b/server/system.py new file mode 100644 index 0000000..d4281a0 --- /dev/null +++ b/server/system.py @@ -0,0 +1,72 @@ +import sys +import os +import json +import zipfile +import requests + +arguments = sys.argv +arguments.remove(sys.argv[0]) + +if len(arguments) == 0: + sys.exit() + +command = arguments[0] +if command in ["u", "update"]: + with open("version.json", "r") as f: # loading settings + version = json.load(f) + url = version["url"] + server_version = json.loads(requests.get(url).text) + if "-version" in arguments: + try: + version_download = arguments[arguments.index("-version") + 1] + except IndexError: + print("Version argument is empty.") + sys.exit() + if version_download not in list(server_version.keys()): + print("Version not found.") + sys.exit() + + else: + for ver, data in enumerate(server_version.values()): + if data["id"] > version["id"]: + version_download = list(server_version.keys())[ver] + + with open("update.zip", "wb") as save: + save.write( + bytes(requests.get( + f"https://github.com/UntriexTv/test_directory/releases/download/{version_download}/update.zip").content)) + print("Download succefull") + print("Extracting update") + if not os.path.isdir("update"): + os.mkdir("update") + with zipfile.ZipFile("update.zip", "r") as zip_ref: + zip_ref.extractall("") + os.rmdir("update") + os.remove("update.zip") + print(f"update to {version_download} was succefull.") + +if command == "clean": + if arguments[1] == "all": + open("log.txt", "w").close() + + with open("settings.json", "r") as file: + settings = json.load(file) + + for line in settings["heartbeat_table"]: + settings["heartbeat_table"][line] = [] + + with open("settings.json", "w") as file: + json.dump(settings, file, indent=2) + + if arguments[1] == "log": + open("log.txt", "w").close() + + if arguments[1] == "heartbeat_table": + with open("settings.json", "r") as file: + settings = json.load(file) + + for line in settings["heartbeat_table"]: + settings["heartbeat_table"][line] = [] + + with open("settings.json", "w") as file: + json.dump(settings, file, indent=2) diff --git a/server/test.json b/server/test.json deleted file mode 100644 index ea7f657..0000000 --- a/server/test.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "connected_id": 1, - "1": { - "ID": 1, - "location": "GPS", - "descrpition": { - "title": "nazov rpi ako nazov", - "description_s": "krátky popis, ktorý bude zobrazený iba v náhladovom okne", - "description_l": "dlhší popis zariadenia, ktorý bude zobrazený po otvorení", - "photo_s": "mala_fotka.png", - "photo_b": "velka_fotka.png" - }, - "files": [ - { - "name": "prehliadky", - "format": ".pdf", - "description": "tento súbor obsahuje prehliadky" - }, { - "name": "prehliadky", - "format": ".pdf", - "description": "tento súbor obsahuje prehliadky" - } - ] - }, - "2": { - "ID": 2, - "location": "GPS", - "descrpition": { - "title": "nazov rpi ako nazov", - "description_s": "krátky popis, ktorý bude zobrazený iba v náhladovom okne", - "description_l": "dlhší popis zariadenia, ktorý bude zobrazený po otvorení", - "photo_s": "mala_fotka.png", - "photo_b": "velka fotka.png" - }, - "files": [ - { - "name": "prehliadky", - "format": ".pdf", - "description": "tento súbor obsahuje prehliadky" - }, { - "name": "prehliadky", - "format": ".pdf", - "description": "tento súbor obsahuje prehliadky" - } - ] - } -} \ No newline at end of file diff --git a/server/test.py b/server/test.py deleted file mode 100644 index 81785ff..0000000 --- a/server/test.py +++ /dev/null @@ -1,60 +0,0 @@ -import curses - -menu = ['Home', 'Play', 'Scoreboard', 'Exit'] - - -def print_menu(stdscr, selected_row_idx): - stdscr.clear() - h, w = stdscr.getmaxyx() - for idx, row in enumerate(menu): - x = w//2 - len(row)//2 - y = h//2 - len(menu)//2 + idx - if idx == selected_row_idx: - stdscr.attron(curses.color_pair(1)) - stdscr.addstr(y, x, row) - stdscr.attroff(curses.color_pair(1)) - else: - stdscr.addstr(y, x, row) - stdscr.refresh() - - -def print_center(stdscr, text): - stdscr.clear() - h, w = stdscr.getmaxyx() - x = w//2 - len(text)//2 - y = h//2 - stdscr.addstr(y, x, text) - stdscr.refresh() - - -def main(stdscr): - # turn off cursor blinking - curses.curs_set(0) - - # color scheme for selected row - curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE) - - # specify the current selected row - current_row = 0 - - # print the menu - print_menu(stdscr, current_row) - - while 1: - key = stdscr.getch() - - if key == curses.KEY_UP and current_row > 0: - current_row -= 1 - elif key == curses.KEY_DOWN and current_row < len(menu)-1: - current_row += 1 - elif key == curses.KEY_ENTER or key in [10, 13]: - print_center(stdscr, "You selected '{}'".format(menu[current_row])) - stdscr.getch() - # if user selected last row, exit the program - if current_row == len(menu)-1: - break - - print_menu(stdscr, current_row) - - -curses.wrapper(main) \ No newline at end of file diff --git a/server/version.json b/server/version.json index 63f5b53..0d562bd 100644 --- a/server/version.json +++ b/server/version.json @@ -1,4 +1,5 @@ { - "version": "0.1", - "type": "Alpha" -} \ No newline at end of file + "version": "0.5", + "id": 3, + "url": "https://raw.githubusercontent.com/UntriexTv/test_directory/main/ver.json" +}