moved server to own folder

This commit is contained in:
Untriex Programming
2021-03-17 08:12:52 +01:00
parent f53ed7653f
commit deaf217370
13 changed files with 126 additions and 1 deletions

40
server/engine.py Normal file
View File

@@ -0,0 +1,40 @@
from datetime import datetime
class Log:
def __init__(self, settings=None):
if settings is None:
settings = {"save_error": True, "print_error": True, "save_warning": True, "print_warning": True,
"save_message": False, "print_message": True, "enable_debug": False}
self.save_error = settings["save_error"]
self.save_warning = settings["save_warning"]
self.save_messages = settings["save_message"]
self.print_error = settings["print_error"]
self.print_warning = settings["print_warning"]
self.print_messages = settings["print_message"]
self.debug_e = settings["enable_debug"]
def error(self, error):
if self.print_error:
print(f"{datetime.now()} -> ERROR: {error}")
if self.save_error:
with open("log.txt", "a") as file:
file.write(f"\n{datetime.now()} -> ERROR: {error}")
def warning(self, warning):
if self.print_warning:
print(f"{datetime.now()} -> Warning: {warning}")
if self.save_warning:
with open("log.txt", "a") as file:
file.write(f"\n{datetime.now()} -> Warning: {warning}")
def message(self, message):
if self.print_messages:
print(f"{datetime.now()} -> message: {message}")
if self.save_messages:
with open("log.txt", "a") as file:
file.write(f"\n{datetime.now()} -> message: {message}")
def debug(self, debug):
if self.debug_e:
print(f"{datetime.now()} -> DEBUG: {debug}")

BIN
server/files/test.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

1
server/files/test.txt Normal file
View File

@@ -0,0 +1 @@
toto je test číslo 1 zo serveru s ID 2

1
server/files/test2.txt Normal file
View File

@@ -0,0 +1 @@
toto je test n. 2 zo serveru ID2

22
server/filesystem.json Normal file
View File

@@ -0,0 +1,22 @@
{
"ID": 0,
"location": "izba",
"descrpition": {
"title": "legionrpi",
"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": "test",
"format": ".jpg",
"description": "toto je jpg test file"
}, {
"name": "test2",
"format": ".txt",
"description": "toto je txt test file"
}
]
}

3
server/log.txt Normal file
View File

@@ -0,0 +1,3 @@
2021-03-15 10:13:26.660898 -> Warning: 192.168.1.232 disconnected/is not available
2021-03-15 11:23:33.589998 -> Warning: 192.168.1.231 disconnected/is not available

183
server/main.py Normal file
View File

@@ -0,0 +1,183 @@
from fastapi import FastAPI, Request
from fastapi.responses import FileResponse
from pydantic import BaseModel
import engine
import requests
import time
import json
import os
import threading
import hashlib
with open("settings.json", "r") as f: # loading settings
settings = json.load(f)
IP = settings["IP"]
ID = settings["ID"]
location = settings["location"]
app = FastAPI() # init of FastAPI
log = engine.Log(settings["log"]) # init of LOG
offline = []
time_to_heartbeat = settings["time_to_heartbeat"] # Raspberry will be requesting heartbeat every __ seconds
time_to_heartbeat_offline = settings[
"time_to_heartbeat_offline"] # Raspberry will be requesting heartbeat every __ seconds from offline rpi
# json variables
filesystem = { # Here will be files saved on this raspberry
"otvaracie_hod": ["t", {"pon": "10-25"}, {"uto": "10-25"}],
"prehliadka": ["pdf", "/files/prehliadka.pdf"],
"fotky_hrad": ["png_z", ["/files/hrad1.png", "/files/hrad2.png"]]
}
heartbeat_table = settings["heartbeat_table"]
sensors = { # List of "live" data like tempeature, etc.
"teplota": 24,
"vlhkosť": 25,
"počet ľudí": 10,
"doba čakania": 2
}
heartbeat_table["ID"].append(ID)
heartbeat_table["IP"].append(IP)
heartbeat_table["location"].append(location)
heartbeat_table["file_system"].append(filesystem)
heartbeat_table["last_heartbeat"].append(time_to_heartbeat)
# Todo better "host" ID handeling
class ServerTable(BaseModel): # table of content for heartbeat request
ID: list
IP: list
location: list
file_system: list
last_heartbeat: list
@app.post("/heartbeat")
def heartbeat(s_table: ServerTable, request: Request):
log.message(f"server requested heartbeat {request.client.host}:{request.client.port}")
log.debug(f"Recieved server table: {s_table}")
try:
for position, server_id in enumerate(s_table.ID):
if server_id in heartbeat_table["ID"]:
if heartbeat_table["last_heartbeat"][heartbeat_table["ID"].index(server_id)] < \
s_table.last_heartbeat[position]:
heartbeat_table["last_heartbeat"][heartbeat_table["ID"].index(server_id)] = s_table.last_heartbeat[
position]
log.debug(f"updated {server_id}`s heartbeat to {s_table.last_heartbeat[position]}")
heartbeat_table["file_system"][heartbeat_table["ID"].index(server_id)] = s_table.file_system[
position]
elif server_id == ID:
log.debug(f"Updated my heartbeat from {s_table.last_heartbeat[position]} to {time_to_heartbeat}")
heartbeat_table["last_heartbeat"][heartbeat_table["ID"].index(ID)] = time_to_heartbeat
else:
heartbeat_table["ID"].append(s_table.ID[position])
heartbeat_table["IP"].append(s_table.IP[position])
heartbeat_table["location"].append(s_table.location[position])
heartbeat_table["file_system"].append(s_table.file_system[position])
heartbeat_table["last_heartbeat"].append(s_table.last_heartbeat[position])
except Exception as error:
log.error(f"heartbeat > {error}")
if heartbeat_table["ID"][heartbeat_table["IP"].index(request.client.host)] in offline:
offline.remove(heartbeat_table["ID"][heartbeat_table["IP"].index(request.client.host)])
log.message(f"{request.client.host} gone online")
return heartbeat_table, {"ID": ID, "file_system": filesystem, "location": location}
@app.get("/sensors")
def get_sensors(request: Request):
log.message(f"sensor data sent to {request.client.host}:{request.client.port}")
log.debug(f"sensor data: {sensors}")
return sensors
@app.get("/files/{IDx}/{file}")
def get_file(IDx: int, file: str):
server_ip = heartbeat_table["IP"][heartbeat_table["ID"].index(IDx)]
if IDx == ID:
return FileResponse(f"files/{file}")
elif IDx in heartbeat_table["ID"]:
if os.path.isdir(f"cache/{IDx}"):
if os.path.isfile(f"cache/{IDx}/{file}"):
with open(f"cache/{IDx}/{file}", "rb") as compared_file:
m = hashlib.md5()
for line in compared_file:
m.update(line)
rr = requests.get(f"""http://{server_ip}:8000/compare/{file}""")
if rr.text.strip('"') != str(m.hexdigest()):
log.message(f"{file} on server {server_ip} is changed.")
else:
log.debug(f"returning cached file cache/{IDx}{file}")
return FileResponse(f"cache/{IDx}/{file}")
else:
os.mkdir(f"cache/{IDx}")
log.message(f"downloading {file} from {server_ip}")
r = requests.get(f"http://{server_ip}:8000/files/{IDx}/{file}")
with open(f"cache/{IDx}/{file}", "wb") as save:
save.write(bytes(r.content))
return FileResponse(f"cache/{IDx}/{file}")
@app.post("/update")
def update_sensors():
pass
# Todo Make option to upload "live data" manually to rpi
@app.get("/compare/{file}")
def comparision(file: str):
with open(f"files/{file}", "rb") as compared_file:
m = hashlib.md5()
for line in compared_file:
m.update(line)
return m.hexdigest()
@app.get("/devices_list")
def get_devices_list():
return heartbeat_table
def send_heartbeat(ip, id):
global heartbeat_table
log.message(f"""sending heartbeat to {ip}({"offline" if id in offline else "online"})""")
cache_request = requests.post(f"http://{ip}:8000/heartbeat", data=json.dumps(heartbeat_table))
heartbeat_table = dict(cache_request.json()[0])
log.debug(json.dumps(cache_request.json(), indent=4))
def mainloop():
while True:
for device_number, device_ID in enumerate(heartbeat_table["ID"]):
if device_ID != ID:
if heartbeat_table["last_heartbeat"][device_number] < 0:
try:
send_heartbeat(heartbeat_table["IP"][device_number], heartbeat_table["ID"][device_number])
except requests.exceptions.ConnectionError:
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)
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
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

16
server/settings.json Normal file
View File

@@ -0,0 +1,16 @@
{
"ID": 0,
"IP": "192.168.1.99",
"location": "izba",
"time_to_heartbeat": 20,
"time_to_heartbeat_offline": 25,
"log": {
"save_error": true,
"print_error": true,
"save_warning": true,
"print_warning": true,
"save_message": false,
"print_message": true,
"enable_debug": false
}
}

12
server/setup.py Normal file
View File

@@ -0,0 +1,12 @@
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()

47
server/test.json Normal file
View File

@@ -0,0 +1,47 @@
{
"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"
}
]
}
}

60
server/test.py Normal file
View File

@@ -0,0 +1,60 @@
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)

4
server/version.json Normal file
View File

@@ -0,0 +1,4 @@
{
"version": "0.1",
"type": "Alpha"
}