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.
This commit is contained in:
parent
55fcf7d4d4
commit
3a34e50432
6
server/.idea/vcs.xml
Normal file
6
server/.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
55
server/.idea/workspace.xml
Normal file
55
server/.idea/workspace.xml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="7d87058b-045e-4cef-a58c-742b2c4128db" name="Default Changelist" comment="" />
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="Git.Merge.Settings">
|
||||||
|
<option name="BRANCH" value="Development" />
|
||||||
|
</component>
|
||||||
|
<component name="Git.Settings">
|
||||||
|
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
||||||
|
<map>
|
||||||
|
<entry key="$PROJECT_DIR$/.." value="Development" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectId" id="1ptaObqar0IjON5s6ejh3akwf0j" />
|
||||||
|
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||||
|
<component name="ProjectViewState">
|
||||||
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
|
<option name="showLibraryContents" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent">
|
||||||
|
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||||
|
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
||||||
|
<property name="last_opened_file_path" value="$PROJECT_DIR$/../../Mabasej_work_server" />
|
||||||
|
</component>
|
||||||
|
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task">
|
||||||
|
<changelist id="7d87058b-045e-4cef-a58c-742b2c4128db" name="Default Changelist" comment="" />
|
||||||
|
<created>1616004808992</created>
|
||||||
|
<option name="number" value="Default" />
|
||||||
|
<option name="presentableId" value="Default" />
|
||||||
|
<updated>1616004808992</updated>
|
||||||
|
</task>
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="Vcs.Log.Tabs.Properties">
|
||||||
|
<option name="TAB_STATES">
|
||||||
|
<map>
|
||||||
|
<entry key="MAIN">
|
||||||
|
<value>
|
||||||
|
<State />
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
<option name="oldMeFiltersMigrated" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -1,4 +1,6 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
class Log:
|
class Log:
|
||||||
@ -38,3 +40,18 @@ class Log:
|
|||||||
def debug(self, debug):
|
def debug(self, debug):
|
||||||
if self.debug_e:
|
if self.debug_e:
|
||||||
print(f"{datetime.now()} -> DEBUG: {debug}")
|
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}
|
@ -1,5 +1,5 @@
|
|||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
from fastapi.responses import FileResponse
|
from fastapi.responses import FileResponse, HTMLResponse
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
import engine
|
import engine
|
||||||
import requests
|
import requests
|
||||||
@ -18,10 +18,13 @@ with open("filesystem.json", "r") as f: # loading settings
|
|||||||
IP = settings["IP"]
|
IP = settings["IP"]
|
||||||
ID = settings["ID"]
|
ID = settings["ID"]
|
||||||
location = settings["location"]
|
location = settings["location"]
|
||||||
|
time_to_save = settings["time_to_save"]
|
||||||
|
|
||||||
app = FastAPI() # init of FastAPI
|
app = FastAPI() # init of FastAPI
|
||||||
log = engine.Log(settings["log"]) # init of LOG
|
log = engine.Log(settings["log"]) # init of LOG
|
||||||
|
update = engine.Update()
|
||||||
offline = []
|
offline = []
|
||||||
|
save_time = time.time()
|
||||||
|
|
||||||
time_to_heartbeat = settings["time_to_heartbeat"] # Raspberry will be requesting heartbeat every __ seconds
|
time_to_heartbeat = settings["time_to_heartbeat"] # Raspberry will be requesting heartbeat every __ seconds
|
||||||
time_to_heartbeat_offline = settings[
|
time_to_heartbeat_offline = settings[
|
||||||
@ -141,6 +144,14 @@ def get_devices_list():
|
|||||||
return heartbeat_table["file_system"]
|
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):
|
def send_heartbeat(ip, id):
|
||||||
global heartbeat_table
|
global heartbeat_table
|
||||||
log.message(f"""sending heartbeat to {ip}({"offline" if id in offline else "online"})""")
|
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():
|
def mainloop():
|
||||||
|
global save_time
|
||||||
while True:
|
while True:
|
||||||
for device_number, device_ID in enumerate(heartbeat_table["ID"]):
|
for device_number, device_ID in enumerate(heartbeat_table["ID"]):
|
||||||
if device_ID != ID:
|
if device_ID != ID:
|
||||||
@ -160,22 +172,37 @@ def mainloop():
|
|||||||
if heartbeat_table["ID"][device_number] not in offline:
|
if heartbeat_table["ID"][device_number] not in offline:
|
||||||
log.warning(f"""{heartbeat_table["IP"][device_number]} disconnected/is not available""")
|
log.warning(f"""{heartbeat_table["IP"][device_number]} disconnected/is not available""")
|
||||||
offline.append(heartbeat_table["ID"][device_number])
|
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:
|
else:
|
||||||
if heartbeat_table["ID"][device_number] in offline:
|
if heartbeat_table["ID"][device_number] in offline:
|
||||||
offline.remove(heartbeat_table["ID"][device_number])
|
offline.remove(heartbeat_table["ID"][device_number])
|
||||||
log.message(f"""{heartbeat_table["IP"][device_number]} gone online""")
|
log.message(f"""{heartbeat_table["IP"][device_number]} gone online""")
|
||||||
heartbeat_table["last_heartbeat"][int(device_number)] = int(time_to_heartbeat) + 5
|
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]}""")
|
try:
|
||||||
heartbeat_table["last_heartbeat"][device_number] -= 1
|
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)
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
thread_1 = threading.Thread(target=mainloop, daemon=True)
|
thread_1 = threading.Thread(target=mainloop, daemon=True)
|
||||||
thread_1.start()
|
thread_1.start()
|
||||||
|
|
||||||
# Todo in next release: disconnect offline client after set time
|
|
||||||
# Todo send to mobile
|
|
||||||
# Todo new filesystem handeling
|
# Todo new filesystem handeling
|
||||||
# Todo implement update system
|
|
||||||
# Todo settings for easy adding/editing files/id/text
|
# Todo settings for easy adding/editing files/id/text
|
@ -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()
|
|
72
server/system.py
Normal file
72
server/system.py
Normal file
@ -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)
|
@ -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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)
|
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "0.1",
|
"version": "0.5",
|
||||||
"type": "Alpha"
|
"id": 3,
|
||||||
}
|
"url": "https://raw.githubusercontent.com/UntriexTv/test_directory/main/ver.json"
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user