Merge pull request #3 from Tucan444/Development
First working version of WikiSpot Server and app
This commit is contained in:
6
server/.idea/vcs.xml
generated
Normal file
6
server/.idea/vcs.xml
generated
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
generated
Normal file
55
server/.idea/workspace.xml
generated
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>
|
BIN
server/cache/1/test.jpg
vendored
Normal file
BIN
server/cache/1/test.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 354 KiB |
@@ -1,4 +1,8 @@
|
||||
from datetime import datetime
|
||||
import json
|
||||
import requests
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
|
||||
class Log:
|
||||
@@ -18,23 +22,104 @@ class Log:
|
||||
if self.print_error:
|
||||
print(f"{datetime.now()} -> ERROR: {error}")
|
||||
if self.save_error:
|
||||
with open("log.txt", "a") as file:
|
||||
with open("log.txt", "a", encoding='utf-8') 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:
|
||||
with open("log.txt", "a", encoding='utf-8') 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:
|
||||
with open("log.txt", "a", encoding='utf-8') as file:
|
||||
file.write(f"\n{datetime.now()} -> message: {message}")
|
||||
|
||||
def debug(self, debug):
|
||||
if self.debug_e:
|
||||
print(f"{datetime.now()} -> DEBUG: {debug}")
|
||||
|
||||
|
||||
class Update:
|
||||
def __init__(self):
|
||||
with open("version.json", "r", encoding='utf-8') as f: # loading settings
|
||||
version = json.load(f)
|
||||
self.url = "https://raw.githubusercontent.com/UntriexTv/test_directory/main/ver.json"
|
||||
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}
|
||||
|
||||
|
||||
class Scan:
|
||||
def __init__(self):
|
||||
self.cache_exist = os.path.isdir("cache")
|
||||
self.files_exist = os.path.isdir("files")
|
||||
if os.path.isfile("update.zip"):
|
||||
os.remove("update.zip")
|
||||
self.filesystem_exist = os.path.isfile("filesystem.json")
|
||||
self.settings_exist = os.path.isfile("settings.json")
|
||||
self.version_exist = os.path.isfile("version.json")
|
||||
self.errors = []
|
||||
self.state_list = {
|
||||
"error": [],
|
||||
"files": [], # 0 = does not exist, 1 = cant read, 2 = some values missing
|
||||
"filesystem": [],
|
||||
"settings": [],
|
||||
"version": [],
|
||||
"system": []
|
||||
}
|
||||
|
||||
def check_to_go(self):
|
||||
filesystem = ""
|
||||
if self.cache_exist is False:
|
||||
os.mkdir("cache")
|
||||
if self.filesystem_exist is False:
|
||||
self.state_list["error"].append("filesystem")
|
||||
self.state_list["filesystem"].append(0)
|
||||
self.errors.append("Filesystem is missing")
|
||||
else:
|
||||
try:
|
||||
with open("filesystem.json", "r", encoding='utf-8') as f:
|
||||
filesystem = json.load(f)
|
||||
except:
|
||||
self.state_list["error"].append("filesystem")
|
||||
self.state_list["filesystem"].append(1)
|
||||
self.errors.append("Filesystem is corrupted")
|
||||
else:
|
||||
filesystem_keys = filesystem.keys()
|
||||
for check in ["ID", "location", "description", "files"]:
|
||||
if check not in filesystem_keys:
|
||||
self.state_list["error"].append("filesystem")
|
||||
self.state_list["filesystem"].append(2)
|
||||
if self.files_exist is False:
|
||||
self.state_list["error"].append("files")
|
||||
self.state_list["files"].append(0)
|
||||
self.errors.append("Files folder does not exists")
|
||||
elif filesystem:
|
||||
for file in dict(filesystem)["files"]:
|
||||
if not os.path.isfile(f"""files/{dict(file)["name"]}{dict(file)["format"]}"""):
|
||||
self.errors.append(f"""{dict(file)["name"]}{dict(file)["format"]} does not exists in file folder.""")
|
||||
if "files" not in self.state_list["error"]:
|
||||
self.state_list["error"].append("files")
|
||||
self.state_list["files"].append(2)
|
||||
if self.settings_exist is False:
|
||||
self.state_list["error"].append("settings")
|
||||
self.state_list["settings"].append(0)
|
||||
if self.version_exist is False:
|
||||
self.state_list["error"].append("version")
|
||||
self.state_list["version"].append(0)
|
||||
|
||||
|
||||
def fix_version(self):
|
||||
o = subprocess.check_output(["python3", "system.py", "update"])
|
||||
print(o)
|
||||
|
||||
|
@@ -1 +1 @@
|
||||
toto je test číslo 1 zo serveru s ID 2
|
||||
toto je test číslo 1
|
||||
|
@@ -1 +0,0 @@
|
||||
toto je test n. 2 zo serveru ID2
|
@@ -1,22 +1,23 @@
|
||||
{
|
||||
"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"
|
||||
"location": "25.997417761947318, -97.15738221291177",
|
||||
"description": {
|
||||
"title": "WikiSpot-demo",
|
||||
"description_s": "Krátky popis",
|
||||
"description_l": "Dlhší popis",
|
||||
"photo_s": "test.jpg",
|
||||
"photo_b": "test.png"
|
||||
},
|
||||
"files": [
|
||||
{
|
||||
"name": "test",
|
||||
"format": ".jpg",
|
||||
"description": "This is jpg test file"
|
||||
},
|
||||
"files": [
|
||||
{
|
||||
"name": "test",
|
||||
"format": ".jpg",
|
||||
"description": "toto je jpg test file"
|
||||
}, {
|
||||
"name": "test2",
|
||||
"format": ".txt",
|
||||
"description": "toto je txt test file"
|
||||
}
|
||||
]
|
||||
{
|
||||
"name": "test",
|
||||
"format": ".txt",
|
||||
"description": "This is txt test file"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,3 +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
|
||||
2021-05-08 16:11:06.311275 -> Warning: 192.168.1.231 disconnected/is not available
|
||||
2021-05-08 16:11:37.323462 -> Warning: 192.168.1.231 disconnected/is not available
|
330
server/main.py
330
server/main.py
@@ -1,27 +1,79 @@
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import FileResponse
|
||||
from pydantic import BaseModel
|
||||
import engine
|
||||
import requests
|
||||
import time
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import threading
|
||||
import hashlib
|
||||
import time
|
||||
import engine
|
||||
import requests
|
||||
import uuid
|
||||
import subprocess
|
||||
import socket
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from fastapi import FastAPI, Request, File, UploadFile
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import FileResponse
|
||||
from pydantic import BaseModel
|
||||
|
||||
with open("settings.json", "r") as f: # loading settings
|
||||
devs = {
|
||||
"Matej Justus": {
|
||||
"git": "https://github.com/UntriexTv", "mail": "maco.justus@gmail.com"},
|
||||
"Benjamin Kojda": {
|
||||
"git": "https://github.com/Tucan444", "mail": "ben4442004@gmail.com"
|
||||
},
|
||||
"Jakub Ďuriš": {
|
||||
"git": "https://github.com/ff0082", "mail": "jakub1.duris@gmail.com"
|
||||
},
|
||||
"Samuel Šubika": {
|
||||
"git": "https://github.com/JustSteel", "mail": "SteelSamko2000@gmail.com"}
|
||||
}
|
||||
check = engine.Scan()
|
||||
check.check_to_go()
|
||||
if check.state_list["error"]:
|
||||
for error in check.errors:
|
||||
print(error)
|
||||
check.fix_version()
|
||||
|
||||
with open("settings.json", "r", encoding='utf-8') as f: # loading settings
|
||||
settings = json.load(f)
|
||||
|
||||
with open("filesystem.json", "r") as f: # loading settings
|
||||
with open("filesystem.json", "r", encoding='utf-8') as f: # loading filesystem
|
||||
filesystem = json.load(f)
|
||||
|
||||
IP = settings["IP"]
|
||||
ID = settings["ID"]
|
||||
location = settings["location"]
|
||||
|
||||
if settings["clear_cache_on_startup"]:
|
||||
shutil.rmtree("cache")
|
||||
os.mkdir("cache")
|
||||
|
||||
|
||||
def get_my_ip():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.connect(("8.8.8.8", 80))
|
||||
ip = s.getsockname()[0]
|
||||
s.close()
|
||||
return ip
|
||||
|
||||
|
||||
IP = get_my_ip()
|
||||
ID = filesystem["ID"]
|
||||
location = filesystem["location"]
|
||||
time_to_save = settings["time_to_save"]
|
||||
settings["location"]
|
||||
settings["ID"]
|
||||
app = FastAPI() # init of FastAPI
|
||||
|
||||
origins = ["*", ]
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
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[
|
||||
@@ -29,22 +81,17 @@ time_to_heartbeat_offline = settings[
|
||||
|
||||
# json variables
|
||||
heartbeat_table = settings["heartbeat_table"]
|
||||
sensors = { # List of "live" data like tempeature, etc.
|
||||
"teplota": 24,
|
||||
"vlhkosť": 25,
|
||||
"počet ľudí": 10,
|
||||
"doba čakania": 2
|
||||
}
|
||||
sensors = {}
|
||||
|
||||
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)
|
||||
messages = [] # {user: "", timestamp: time.Time(), message: ""}
|
||||
if ID not in heartbeat_table["ID"]:
|
||||
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
|
||||
@@ -53,6 +100,21 @@ class ServerTable(BaseModel): # table of content for heartbeat request
|
||||
last_heartbeat: list
|
||||
|
||||
|
||||
class Sensor(BaseModel):
|
||||
name: str
|
||||
value: str
|
||||
|
||||
|
||||
class Message(BaseModel):
|
||||
m_sender: str
|
||||
message: str
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return "wikispot"
|
||||
|
||||
|
||||
@app.post("/heartbeat")
|
||||
def heartbeat(s_table: ServerTable, request: Request):
|
||||
log.message(f"server requested heartbeat {request.client.host}:{request.client.port}")
|
||||
@@ -65,41 +127,60 @@ def heartbeat(s_table: ServerTable, request: Request):
|
||||
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]}")
|
||||
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])
|
||||
log.message(f"Heartbeat from new server:\n ID: {server_id} IP: {request.client}")
|
||||
heartbeat_table["ID"].append(int(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])
|
||||
heartbeat_table["last_heartbeat"].append(int(s_table.last_heartbeat[position]))
|
||||
log.debug(f"Created {server_id}`s heartbeat: {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")
|
||||
log.warning(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("/{IDx}/sensors")
|
||||
def get_sensors(IDx: int, request: Request):
|
||||
global sensors
|
||||
if IDx == ID:
|
||||
log.debug(f"Sensor data sent to {request.client.host} :\n {sensors}")
|
||||
return sensors
|
||||
else:
|
||||
try:
|
||||
r = requests.get(f"""http://{heartbeat_table["IP"][heartbeat_table["ID"].index(IDx)]}:8000/{IDx}/sensors""")
|
||||
log.debug(f"Sensor data from {IDx} sent to {request.client.host} :\n {r.json()}")
|
||||
return r.json()
|
||||
except Exception as error:
|
||||
log.error(f"Sensor data download from {IDx} failed.\n ERROR: {error}")
|
||||
return f"Sensor data download from {IDx} failed.\n ERROR: {error}"
|
||||
|
||||
|
||||
@app.get("/files/{IDx}/{file}")
|
||||
def get_file(IDx: int, file: str):
|
||||
def get_file(IDx: int, file: str, request: Request):
|
||||
log.debug(f"""{request.client} requested {file} from {"this server" if IDx == ID else f"id {IDx}"}""")
|
||||
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.isfile(f"files/{file}"):
|
||||
return FileResponse(f"files/{file}")
|
||||
else:
|
||||
log.warning(f"{request.client} tried to access file ({file}) that does not exist on this server.")
|
||||
return f"ERROR: File {file} does not exist."
|
||||
if IDx not in heartbeat_table["ID"]:
|
||||
log.warning(f"{request.client} tried to access id ({IDx}) that does not exist.")
|
||||
return f"ERROR: {IDx} does not exist."
|
||||
else:
|
||||
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:
|
||||
@@ -108,37 +189,149 @@ def get_file(IDx: int, file: str):
|
||||
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.")
|
||||
log.warning(f"{file} on server {server_ip} is changed.")
|
||||
else:
|
||||
log.debug(f"returning cached file cache/{IDx}{file}")
|
||||
return FileResponse(f"cache/{IDx}/{file}")
|
||||
elif sum(file.stat().st_size for file in Path("cache").rglob('*'))/1024**2 > settings["cache_size_mb"]:
|
||||
shutil.rmtree("cache")
|
||||
os.mkdir("cache")
|
||||
log.message(f"""Clearing cache, because of limit of {settings["cache_size_mb"]}MB""")
|
||||
os.mkdir(f"cache/{IDx}")
|
||||
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}")
|
||||
if "does not exist" in r.text:
|
||||
log.warning(f"{request.client} tried to access file ({file}) on id {IDx} that does not exist.")
|
||||
return f"ERROR: {file} does not exist."
|
||||
log.message(f"Downloaded {file} from {server_ip}")
|
||||
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.post("/{IDx}/update_sensor")
|
||||
def update_sensors(data: Sensor, request: Request, IDx: int):
|
||||
global sensors
|
||||
if IDx == ID:
|
||||
if data.name in sensors:
|
||||
if not data.value:
|
||||
log.message(f"{request.client.host} removed sensor {data.name}")
|
||||
del sensors[data.name]
|
||||
else:
|
||||
log.message(f"{request.client.host} updated sensor {data.name} with value {data.value}")
|
||||
sensors[data.name] = data.value
|
||||
else:
|
||||
log.warning(f"{request.client} created new sensor.\n SENSOR: {data}")
|
||||
sensors[data.name] = data.value
|
||||
return f"Successfuly made new sensor"
|
||||
else:
|
||||
r = requests.post(f"""http://{heartbeat_table["IP"][heartbeat_table["ID"].index(IDx)]}:8000/{IDx}/update_sensor""",
|
||||
json={"name": data.name, "value": data.value})
|
||||
return r.text
|
||||
|
||||
|
||||
@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()
|
||||
try:
|
||||
with open(f"files/{file}", "rb") as compared_file:
|
||||
m = hashlib.md5()
|
||||
for line in compared_file:
|
||||
m.update(line)
|
||||
return m.hexdigest()
|
||||
except FileNotFoundError:
|
||||
return f"ERROR {file} does not exist"
|
||||
|
||||
|
||||
@app.get("/devices_list")
|
||||
def get_devices_list():
|
||||
return heartbeat_table["file_system"]
|
||||
returning_value = [{"connected_id": ID}, *heartbeat_table["file_system"]]
|
||||
while "" in returning_value:
|
||||
returning_value.remove("")
|
||||
return returning_value
|
||||
|
||||
|
||||
@app.get("/admin/get/{command}")
|
||||
def admin_get(command: str, request: Request):
|
||||
log.message(f"{request.client} used admin command.")
|
||||
if command == "get_updates":
|
||||
return [update.get_version(), update.get_updates()]
|
||||
if "update-" in command:
|
||||
state = []
|
||||
version = command.split("-")[1]
|
||||
for rpi in heartbeat_table["IP"]:
|
||||
if rpi != IP:
|
||||
r = requests.get(f"""http://{rpi}:8000/admin/get/update_one-{version}""")
|
||||
if r.text.strip('"').split("\\n")[0] == "SUCCESS":
|
||||
log.message(f"{rpi} was updated to {version}")
|
||||
else:
|
||||
log.error(f"""{rpi} failed to update. Manual update may be needed for proper working of network.
|
||||
Response from server: {r.text}""")
|
||||
state.append({rpi: r.text.strip('"').split("\\n")})
|
||||
subprocess.check_output(f"""python3 system.py update -version {version}""")
|
||||
log.message(f"All devices in network should be updated to {version}")
|
||||
state.append({IP: "updated"})
|
||||
return state
|
||||
if "update_one-" in command:
|
||||
state = subprocess.check_output(["python3", "system.py", "update", "-version", f"""{command.split("-")[1]}"""])
|
||||
log.message(state.decode("utf-8"))
|
||||
return state.decode("utf-8")
|
||||
if command == "heartbeat_table":
|
||||
return heartbeat_table
|
||||
if command == "filesystem":
|
||||
return filesystem
|
||||
|
||||
|
||||
@app.post("/admin/{id_server}/upload_file")
|
||||
async def create_upload_file(id_server: int, uploaded_file: UploadFile = File(...), patch: str = ""):
|
||||
file_location = f"{patch}{uploaded_file.filename}"
|
||||
if id_server == ID:
|
||||
with open(file_location, "wb+") as file_object:
|
||||
file_object.write(uploaded_file.file.read())
|
||||
else:
|
||||
with open(f"cache/{uploaded_file.filename}", "wb+") as file_object:
|
||||
file_object.write(uploaded_file.file.read())
|
||||
file = open(f"cache/{uploaded_file.filename}", "rb")
|
||||
requests.post(f"""http://{heartbeat_table["IP"][heartbeat_table["ID"].index(id_server)]}:8000/admin/{id_server}/upload_file""",
|
||||
files={"uploaded_file": file, "patch": patch})
|
||||
file.close()
|
||||
return {"info": f"""file '{uploaded_file.filename}' saved at '{id_server}/{file_location}'"""}
|
||||
|
||||
|
||||
@app.get("/messages/get")
|
||||
def get_messages(timestamp: str = None):
|
||||
if timestamp:
|
||||
for position, message in enumerate(reversed(messages)):
|
||||
if float(message["timestamp"]) <= float(timestamp):
|
||||
return list(reversed(list(reversed(messages))[:position]))
|
||||
|
||||
if timestamp == "0":
|
||||
return messages
|
||||
return []
|
||||
else:
|
||||
return messages[:10]
|
||||
|
||||
|
||||
@app.get("/messages/register")
|
||||
def register():
|
||||
return [uuid.uuid4().hex[24:], messages[:9]]
|
||||
|
||||
|
||||
@app.get("/discovery")
|
||||
def discovery():
|
||||
return "Success"
|
||||
|
||||
|
||||
@app.post("/messages/post")
|
||||
def post_messages(data: Message):
|
||||
log.debug(f"Message was posted. Sender: {data.m_sender}\n MESSAGE: {data.message}")
|
||||
if len(messages) >= settings["max_mess"]:
|
||||
del messages[:len(messages) - settings["max_mess"]]
|
||||
if data.m_sender and data.message:
|
||||
messages.append({"sender": data.m_sender, "message": data.message, "timestamp": time.time()})
|
||||
return "successful"
|
||||
else:
|
||||
return "Empty message/sender"
|
||||
|
||||
|
||||
def send_heartbeat(ip, id):
|
||||
@@ -150,32 +343,51 @@ 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:
|
||||
if heartbeat_table["last_heartbeat"][device_number] < 0:
|
||||
if int(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)
|
||||
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] = int(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", encoding='utf-8') as file:
|
||||
json.dump(settings, file, indent=2)
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
print(f"""Starting WikiSpot V{update.get_version()["version"]} on http://{IP}:8000""")
|
||||
print("GitHub: https://github.com/Tucan444/Mabasej_Team")
|
||||
print("Developers of this project: ")
|
||||
for dev in devs:
|
||||
print(f"""{dev}, GitHub: {devs[dev]["git"]}, mail: {devs[dev]["mail"]}""")
|
||||
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
|
BIN
server/plugins/computer_vision/MobileNetSSD_deploy.caffemodel
Normal file
BIN
server/plugins/computer_vision/MobileNetSSD_deploy.caffemodel
Normal file
Binary file not shown.
1912
server/plugins/computer_vision/MobileNetSSD_deploy.prototxt
Normal file
1912
server/plugins/computer_vision/MobileNetSSD_deploy.prototxt
Normal file
File diff suppressed because it is too large
Load Diff
46
server/plugins/computer_vision/com_vision.py
Normal file
46
server/plugins/computer_vision/com_vision.py
Normal file
@@ -0,0 +1,46 @@
|
||||
#! /usr/bin/python3
|
||||
from picamera.array import PiRGBArray
|
||||
from picamera import PiCamera
|
||||
import time
|
||||
import cv2
|
||||
import imutils
|
||||
import numpy as np
|
||||
import requests
|
||||
|
||||
protopath = "MobileNetSSD_deploy.prototxt"
|
||||
modelpath = "MobileNetSSD_deploy.caffemodel"
|
||||
detector = cv2.dnn.readNetFromCaffe(prototxt=protopath, caffeModel=modelpath)
|
||||
person_counter = 0
|
||||
|
||||
CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat",
|
||||
"bottle", "bus", "car", "cat", "chair", "cow", "diningtable",
|
||||
"dog", "horse", "motorbike", "person", "pottedplant", "sheep",
|
||||
"sofa", "train", "tvmonitor"]
|
||||
|
||||
# initialize the camera and grab a reference to the raw camera capture
|
||||
camera = PiCamera()
|
||||
rawCapture = PiRGBArray(camera)
|
||||
# allow the camera to warmup
|
||||
time.sleep(0.1)
|
||||
# grab an image from the camera
|
||||
while True:
|
||||
camera.capture(rawCapture, format="bgr")
|
||||
image = rawCapture.array
|
||||
|
||||
image = imutils.resize(image, width=1024, height=1024)
|
||||
(H, W) = image.shape[:2]
|
||||
|
||||
blob = cv2.dnn.blobFromImage(image, 0.007843, (W, H), 127.5)
|
||||
|
||||
detector.setInput(blob)
|
||||
person_detections = detector.forward()
|
||||
|
||||
for i in np.arange(0, person_detections.shape[2]):
|
||||
confidence = person_detections[0, 0, i, 2]
|
||||
if confidence > 0.2:
|
||||
idx = int(person_detections[0, 0, i, 1])
|
||||
|
||||
if CLASSES[idx] == "person":
|
||||
person_counter += 1
|
||||
r = requests.post("http://127.0.0.1:8000/update_sensor", json={"name": "pocet ludi", "value": str(person_counter)})
|
||||
time.sleep(60)
|
@@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=WikiSpot official computer vision plugin
|
||||
After=wikispot.service
|
||||
StartLimitIntervalSec=4
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
User=root
|
||||
WorkingDirectory=/root/test_directory/plugins/computer_vision
|
||||
ExecStart=/root/test_directory/plugins/computer_vision
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@@ -1,9 +1,11 @@
|
||||
{
|
||||
"ID": 0,
|
||||
"IP": "192.168.1.99",
|
||||
"location": "izba",
|
||||
"time_to_heartbeat": 20,
|
||||
"time_to_heartbeat_offline": 25,
|
||||
"save_table": true,
|
||||
"time_to_save": 60,
|
||||
"max_mess": 20,
|
||||
"cache_size_mb": 1000,
|
||||
"clear_cache_on_startup": false,
|
||||
"log": {
|
||||
"save_error": true,
|
||||
"print_error": true,
|
||||
@@ -19,5 +21,5 @@
|
||||
"location": [],
|
||||
"file_system": [],
|
||||
"last_heartbeat": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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()
|
81
server/system.py
Normal file
81
server/system.py
Normal file
@@ -0,0 +1,81 @@
|
||||
#! /usr/bin/python3
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import zipfile
|
||||
import requests
|
||||
|
||||
arguments = sys.argv
|
||||
arguments.remove(sys.argv[0])
|
||||
url = "https://raw.githubusercontent.com/UntriexTv/test_directory/main/ver.json"
|
||||
|
||||
if len(arguments) == 0:
|
||||
sys.exit()
|
||||
|
||||
command = arguments[0]
|
||||
if command in ["u", "update"]:
|
||||
try:
|
||||
server_version = json.loads(requests.get(url).text)
|
||||
except Exception as error:
|
||||
print(f"CAN'T DOWNLOAD VERSION LIST. ERROR: {error}")
|
||||
sys.exit()
|
||||
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:
|
||||
try:
|
||||
with open("version.json", "r", encoding='utf-8') as f: # loading settings
|
||||
version = json.load(f)
|
||||
except:
|
||||
version = {"id": 0, "version": "recovery"}
|
||||
for ver, data in enumerate(server_version.values()):
|
||||
if data["id"] > version["id"]:
|
||||
version_download = list(server_version.keys())[ver]
|
||||
try:
|
||||
with open("update.zip", "wb", encoding='utf-8') as save:
|
||||
save.write(
|
||||
bytes(requests.get(
|
||||
f"https://github.com/UntriexTv/test_directory/releases/download/{version_download}/update.zip").content))
|
||||
except Exception as error:
|
||||
print(f"FAILED TO DOWNLOAD UPDATE. ERROR: {error}")
|
||||
sys.exit()
|
||||
with zipfile.ZipFile("update.zip", "r") as zip_ref:
|
||||
zip_ref.extractall("")
|
||||
os.remove("update.zip")
|
||||
print("SUCCESS")
|
||||
print(f"""Update from version {version["version"]} to {version_download} was sucesfull""")
|
||||
|
||||
if command == "clean":
|
||||
if arguments[1] == "all":
|
||||
open("log.txt", "w").close()
|
||||
|
||||
with open("settings.json", "r", encoding='utf-8') as file:
|
||||
settings = json.load(file)
|
||||
|
||||
for line in settings["heartbeat_table"]:
|
||||
settings["heartbeat_table"][line] = []
|
||||
|
||||
with open("settings.json", "w", encoding='utf-8') 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", encoding='utf-8') as file:
|
||||
settings = json.load(file)
|
||||
|
||||
for line in settings["heartbeat_table"]:
|
||||
settings["heartbeat_table"][line] = []
|
||||
|
||||
with open("settings.json", "w", encoding='utf-8') 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,4 @@
|
||||
{
|
||||
"version": "0.1",
|
||||
"type": "Alpha"
|
||||
}
|
||||
"version": "1.0",
|
||||
"id": 7
|
||||
}
|
||||
|
Reference in New Issue
Block a user