mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-07 09:36:05 -08:00
/data and /tmp standarization
This commit is contained in:
157
server/api.py
157
server/api.py
@@ -3,17 +3,30 @@ import time
|
||||
import threading
|
||||
import datetime
|
||||
|
||||
# Register NetAlertX modules
|
||||
import conf
|
||||
from const import (apiPath, sql_appevents, sql_devices_all, sql_events_pending_alert, sql_settings, sql_plugins_events, sql_plugins_history, sql_plugins_objects,sql_language_strings, sql_notifications_all, sql_online_history, sql_devices_tiles, sql_devices_filters)
|
||||
# Register NetAlertX modules
|
||||
import conf
|
||||
from const import (
|
||||
apiPath,
|
||||
sql_appevents,
|
||||
sql_devices_all,
|
||||
sql_events_pending_alert,
|
||||
sql_settings,
|
||||
sql_plugins_events,
|
||||
sql_plugins_history,
|
||||
sql_plugins_objects,
|
||||
sql_language_strings,
|
||||
sql_notifications_all,
|
||||
sql_online_history,
|
||||
sql_devices_tiles,
|
||||
sql_devices_filters,
|
||||
)
|
||||
from logger import mylog
|
||||
from helper import write_file, get_setting_value, timeNowTZ
|
||||
from app_state import updateState
|
||||
from models.user_events_queue_instance import UserEventsQueueInstance
|
||||
from messaging.in_app import write_notification
|
||||
|
||||
# Import the start_server function
|
||||
from api_server.api_server_start import start_server
|
||||
from api_server.api_server_start import start_server
|
||||
|
||||
apiEndpoints = []
|
||||
|
||||
@@ -22,25 +35,28 @@ api_lock = threading.Lock()
|
||||
periodic_write_lock = threading.Lock()
|
||||
stop_event = threading.Event() # Event to signal thread termination
|
||||
|
||||
#===============================================================================
|
||||
|
||||
# ===============================================================================
|
||||
# API
|
||||
#===============================================================================
|
||||
def update_api(db, all_plugins, forceUpdate, updateOnlyDataSources=[], is_ad_hoc_user_event=False):
|
||||
mylog('debug', ['[API] Update API starting'])
|
||||
# ===============================================================================
|
||||
def update_api(
|
||||
db, all_plugins, forceUpdate, updateOnlyDataSources=[], is_ad_hoc_user_event=False
|
||||
):
|
||||
mylog("debug", ["[API] Update API starting"])
|
||||
|
||||
# Start periodic write if not running
|
||||
start_periodic_write(interval=1)
|
||||
|
||||
# Update app_state.json and retrieve app_state to check if GraphQL server is running
|
||||
app_state = updateState()
|
||||
|
||||
# Save plugins
|
||||
write_file(apiPath + 'plugins.json', json.dumps({"data": all_plugins}))
|
||||
|
||||
# Prepare database tables we want to expose
|
||||
# Save plugins
|
||||
write_file(apiPath + "plugins.json", json.dumps({"data": all_plugins}))
|
||||
|
||||
# Prepare database tables we want to expose
|
||||
dataSourcesSQLs = [
|
||||
["appevents", sql_appevents],
|
||||
["devices", sql_devices_all],
|
||||
["appevents", sql_appevents],
|
||||
["devices", sql_devices_all],
|
||||
["events_pending_alert", sql_events_pending_alert],
|
||||
["settings", sql_settings],
|
||||
["plugins_events", sql_plugins_events],
|
||||
@@ -57,8 +73,14 @@ def update_api(db, all_plugins, forceUpdate, updateOnlyDataSources=[], is_ad_hoc
|
||||
# Save selected database tables
|
||||
for dsSQL in dataSourcesSQLs:
|
||||
if not updateOnlyDataSources or dsSQL[0] in updateOnlyDataSources:
|
||||
api_endpoint_class(db, forceUpdate, dsSQL[1], apiPath + 'table_' + dsSQL[0] + '.json', is_ad_hoc_user_event)
|
||||
|
||||
api_endpoint_class(
|
||||
db,
|
||||
forceUpdate,
|
||||
dsSQL[1],
|
||||
apiPath + "table_" + dsSQL[0] + ".json",
|
||||
is_ad_hoc_user_event,
|
||||
)
|
||||
|
||||
# Start the GraphQL server
|
||||
graphql_port_value = get_setting_value("GRAPHQL_PORT")
|
||||
api_token_value = get_setting_value("API_TOKEN")
|
||||
@@ -67,16 +89,26 @@ def update_api(db, all_plugins, forceUpdate, updateOnlyDataSources=[], is_ad_hoc
|
||||
if app_state.graphQLServerStarted == 0:
|
||||
if graphql_port_value is not None and len(api_token_value) > 1:
|
||||
try:
|
||||
graphql_port_value = int(graphql_port_value) # Ensure port is an integer
|
||||
graphql_port_value = int(
|
||||
graphql_port_value
|
||||
) # Ensure port is an integer
|
||||
start_server(graphql_port_value, app_state) # Start the server
|
||||
except ValueError:
|
||||
mylog('none', [f"[API] Invalid GRAPHQL_PORT value, must be an integer: {graphql_port_value}"])
|
||||
mylog(
|
||||
"none",
|
||||
[
|
||||
f"[API] Invalid GRAPHQL_PORT value, must be an integer: {graphql_port_value}"
|
||||
],
|
||||
)
|
||||
else:
|
||||
mylog('none', [f"[API] GRAPHQL_PORT or API_TOKEN is not set, will try later."])
|
||||
mylog(
|
||||
"none", ["[API] GRAPHQL_PORT or API_TOKEN is not set, will try later."]
|
||||
)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# -------------------------------------------------------------------------------
|
||||
class api_endpoint_class:
|
||||
def __init__(self, db, forceUpdate, query, path, is_ad_hoc_user_event=False):
|
||||
def __init__(self, db, forceUpdate, query, path, is_ad_hoc_user_event=False):
|
||||
global apiEndpoints
|
||||
|
||||
current_time = timeNowTZ()
|
||||
@@ -85,29 +117,39 @@ class api_endpoint_class:
|
||||
self.query = query
|
||||
self.jsonData = db.get_table_as_json(self.query).json
|
||||
self.path = path
|
||||
self.fileName = path.split('/')[-1]
|
||||
self.fileName = path.split("/")[-1]
|
||||
self.hash = hash(json.dumps(self.jsonData))
|
||||
self.debounce_interval = 3 # Time in seconds to wait before writing
|
||||
self.changeDetectedWhen = None
|
||||
self.changeDetectedWhen = None
|
||||
# self.last_update_time = current_time - datetime.timedelta(minutes=1) # Last time data was updated
|
||||
self.is_ad_hoc_user_event = is_ad_hoc_user_event
|
||||
self.needsUpdate = False
|
||||
|
||||
# Check if the endpoint needs to be updated
|
||||
found = False
|
||||
found = False
|
||||
index = 0
|
||||
|
||||
|
||||
# Search previous endpoint states to check if API needs updating
|
||||
for endpoint in apiEndpoints:
|
||||
# Match SQL and API endpoint path
|
||||
# Match SQL and API endpoint path
|
||||
if endpoint.query == self.query and endpoint.path == self.path:
|
||||
found = True
|
||||
mylog('trace', [f'[API] api_endpoint_class: Hashes (file|old|new): ({self.fileName}|{endpoint.hash}|{self.hash})'])
|
||||
if endpoint.hash != self.hash:
|
||||
found = True
|
||||
mylog(
|
||||
"trace",
|
||||
[
|
||||
f"[API] api_endpoint_class: Hashes (file|old|new): ({self.fileName}|{endpoint.hash}|{self.hash})"
|
||||
],
|
||||
)
|
||||
if endpoint.hash != self.hash:
|
||||
self.needsUpdate = True
|
||||
# Only update changeDetectedWhen if it hasn't been set recently
|
||||
if not self.changeDetectedWhen or current_time > (self.changeDetectedWhen + datetime.timedelta(seconds=self.debounce_interval)):
|
||||
self.changeDetectedWhen = current_time # Set timestamp for change detection
|
||||
if not self.changeDetectedWhen or current_time > (
|
||||
self.changeDetectedWhen
|
||||
+ datetime.timedelta(seconds=self.debounce_interval)
|
||||
):
|
||||
self.changeDetectedWhen = (
|
||||
current_time # Set timestamp for change detection
|
||||
)
|
||||
if index < len(apiEndpoints):
|
||||
apiEndpoints[index] = self
|
||||
# check end of bounds and replace
|
||||
@@ -120,28 +162,45 @@ class api_endpoint_class:
|
||||
if not found:
|
||||
self.needsUpdate = True
|
||||
# Only update changeDetectedWhen if it hasn't been set recently
|
||||
if not self.changeDetectedWhen or current_time > (self.changeDetectedWhen + datetime.timedelta(seconds=self.debounce_interval)):
|
||||
self.changeDetectedWhen = current_time # Initialize timestamp for new endpoint
|
||||
if not self.changeDetectedWhen or current_time > (
|
||||
self.changeDetectedWhen
|
||||
+ datetime.timedelta(seconds=self.debounce_interval)
|
||||
):
|
||||
self.changeDetectedWhen = (
|
||||
current_time # Initialize timestamp for new endpoint
|
||||
)
|
||||
apiEndpoints.append(self)
|
||||
|
||||
# Needs to be called for initial updates
|
||||
self.try_write(forceUpdate)
|
||||
|
||||
#----------------------------------------
|
||||
# ----------------------------------------
|
||||
def try_write(self, forceUpdate):
|
||||
current_time = timeNowTZ()
|
||||
|
||||
# Debugging info to understand the issue
|
||||
# Debugging info to understand the issue
|
||||
# mylog('debug', [f'[API] api_endpoint_class: {self.fileName} is_ad_hoc_user_event {self.is_ad_hoc_user_event} last_update_time={self.last_update_time}, debounce time={self.last_update_time + datetime.timedelta(seconds=self.debounce_interval)}.'])
|
||||
|
||||
# Only attempt to write if the debounce time has passed
|
||||
if forceUpdate == True or (self.needsUpdate and (self.changeDetectedWhen is None or current_time > (self.changeDetectedWhen + datetime.timedelta(seconds=self.debounce_interval)))):
|
||||
|
||||
mylog('debug', [f'[API] api_endpoint_class: Writing {self.fileName} after debounce.'])
|
||||
if forceUpdate == True or (
|
||||
self.needsUpdate
|
||||
and (
|
||||
self.changeDetectedWhen is None
|
||||
or current_time
|
||||
> (
|
||||
self.changeDetectedWhen
|
||||
+ datetime.timedelta(seconds=self.debounce_interval)
|
||||
)
|
||||
)
|
||||
):
|
||||
mylog(
|
||||
"debug",
|
||||
[f"[API] api_endpoint_class: Writing {self.fileName} after debounce."],
|
||||
)
|
||||
|
||||
write_file(self.path, json.dumps(self.jsonData))
|
||||
|
||||
self.needsUpdate = False
|
||||
self.needsUpdate = False
|
||||
self.last_update_time = timeNowTZ() # Reset last_update_time after writing
|
||||
|
||||
# Update user event execution log
|
||||
@@ -156,13 +215,13 @@ class api_endpoint_class:
|
||||
# mylog('trace', [f'[API] api_endpoint_class: Skipping write for {self.fileName}, debounce time not passed.'])
|
||||
|
||||
|
||||
|
||||
#===============================================================================
|
||||
# ===============================================================================
|
||||
# Periodic Write Functions
|
||||
#===============================================================================
|
||||
# ===============================================================================
|
||||
periodic_write_running = False
|
||||
periodic_write_thread = None
|
||||
|
||||
|
||||
def periodic_write(interval=1):
|
||||
"""Periodically checks all endpoints for pending writes."""
|
||||
global apiEndpoints
|
||||
@@ -179,12 +238,15 @@ def start_periodic_write(interval=1):
|
||||
|
||||
with periodic_write_lock:
|
||||
if not periodic_write_running:
|
||||
mylog('trace', ["[API] Starting periodic_write thread."])
|
||||
mylog("trace", ["[API] Starting periodic_write thread."])
|
||||
periodic_write_running = True
|
||||
periodic_write_thread = threading.Thread(target=periodic_write, args=(interval,), daemon=True)
|
||||
periodic_write_thread = threading.Thread(
|
||||
target=periodic_write, args=(interval,), daemon=True
|
||||
)
|
||||
periodic_write_thread.start()
|
||||
else:
|
||||
mylog('trace', ["[API] periodic_write is already running."])
|
||||
mylog("trace", ["[API] periodic_write is already running."])
|
||||
|
||||
|
||||
def stop_periodic_write():
|
||||
"""Stop the periodic_write thread."""
|
||||
@@ -195,5 +257,4 @@ def stop_periodic_write():
|
||||
stop_event.set()
|
||||
periodic_write_thread.join()
|
||||
periodic_write_running = False
|
||||
mylog('trace', ["[API] periodic_write thread stopped."])
|
||||
|
||||
mylog("trace", ["[API] periodic_write thread stopped."])
|
||||
|
||||
Reference in New Issue
Block a user