From ebeeb6c3a548bf8c9e547c55a34de5e6bd2b4c23 Mon Sep 17 00:00:00 2001 From: Jokob-sk Date: Sat, 30 Sep 2023 09:53:15 +1000 Subject: [PATCH] Better version handling #458 + docs --- front/devices.php | 28 +++--- front/js/handle_version.js | 111 +++++++++--------------- front/maintenance.php | 6 ++ front/php/templates/language/en_us.json | 1 + front/plugins/README.md | 1 + front/plugins/ddns_update/README.md | 2 +- front/plugins/ddns_update/script.py | 2 +- front/plugins/internet_ip/README.md | 2 +- pialert/__main__.py | 20 ++--- pialert/helper.py | 74 +++++++++------- 10 files changed, 115 insertions(+), 132 deletions(-) diff --git a/front/devices.php b/front/devices.php index 4e261d9b..cffa4980 100755 --- a/front/devices.php +++ b/front/devices.php @@ -545,24 +545,24 @@ function getDevicesList (status) { }; function handleLoadingDialog() - { - $.get('api/app_state.json?nocache=' + Date.now(), function(appState) { - - console.log(appState["showSpinner"]) - if(appState["showSpinner"]) - { - showSpinner("settings_old") +{ + $.get('api/app_state.json?nocache=' + Date.now(), function(appState) { + + console.log(appState["showSpinner"]) + if(appState["showSpinner"]) + { + showSpinner("settings_old") - setTimeout("handleLoadingDialog()", 1000); + setTimeout("handleLoadingDialog()", 1000); - } else - { - hideSpinner() - } + } else + { + hideSpinner() + } - }) + }) - } +} diff --git a/front/js/handle_version.js b/front/js/handle_version.js index f8947fc5..4699da36 100755 --- a/front/js/handle_version.js +++ b/front/js/handle_version.js @@ -1,80 +1,51 @@ -function handleVersion(){ +//-------------------------------------------------------------- +// Handle the UI changes to show or hide notifications about a new version +function versionUpdateUI(){ - release_timestamp = getCookie("release_timestamp") + isNewVersion = getCookie("isNewVersion") - if(release_timestamp != "") - { + console.log(isNewVersion) - build_timestamp = parseInt($('#version').attr("data-build-time").match( /\d+/g ).join('')) - - // if the release_timestamp is older by 10 min or more as the build timestamp then there is a new release available - if(release_timestamp > build_timestamp + 600 ) - { - console.log("New release!") - // handling the navigation menu icon - $('#version').attr("class", $('#version').attr("class").replace("myhidden", "")) - - maintenanceDiv = $('#new-version-text') - } - else{ - console.log("All up-to-date!") - - maintenanceDiv = $('#current-version-text') - } - - // handling the maintenance section message - if(emptyArr.includes(maintenanceDiv) == false && $(maintenanceDiv).length != 0) - { - $(maintenanceDiv).attr("class", $(maintenanceDiv).attr("class").replace("myhidden", "")) - } - } - - } - - //-------------------------------------------------------------- - - function getVersion() + // if the release_timestamp is older by 10 min or more as the build timestamp then there is a new release available + if(isNewVersion != "false") { - release_timestamp = getCookie("release_timestamp") + console.log("New release!") + // handling the navigation menu icon + $('#version').attr("class", $('#version').attr("class").replace("myhidden", "")) - release_timestampNum = Number(release_timestamp) + maintenanceDiv = $('#new-version-text') + } + else{ + console.log("All up-to-date!") - // logging - console.log(`Latest release in cookie: ${new Date(release_timestampNum*1000)}`) - - // no cached value available - if(release_timestamp == "") - { - $.get('https://api.github.com/repos/jokob-sk/Pi.Alert/releases').done(function(response) { - // Handle successful response - var releases = response; - - console.log(response) - - if(releases.length > 0) - { - - release_datetime = releases[0].published_at; // get latest release - release_timestamp = new Date(release_datetime).getTime() / 1000; - - // cache value - setCookie("release_timestamp", release_timestamp, 30); - - handleVersion(); - } - - }).fail(function(jqXHR, textStatus, errorThrown) { - - $('.version').append(`

Github API: ${errorThrown} (${jqXHR.status}), ${jqXHR.responseJSON.message}

`) - - }); - } else - { - // cache is available, just call the handler - handleVersion() - } + maintenanceDiv = $('#current-version-text') } + // handling the maintenance section message + if(emptyArr.includes(maintenanceDiv) == false && $(maintenanceDiv).length != 0) + { + $(maintenanceDiv).attr("class", $(maintenanceDiv).attr("class").replace("myhidden", "")) + } + +} + +//-------------------------------------------------------------- +// Checks if a new version is available via the global app_state.json +function checkIfNewVersionAvailable() +{ + $.get('api/app_state.json?nocache=' + Date.now(), function(appState) { + + console.log(appState["isNewVersionChecked"]) + console.log(appState["isNewVersion"]) + + // cache value + setCookie("isNewVersion", appState["isNewVersion"], 30); + setCookie("isNewVersionChecked", appState["isNewVersionChecked"], 30); + + versionUpdateUI(); + + }) +} // handle the dispaly of the NEW icon -getVersion() \ No newline at end of file +checkIfNewVersionAvailable() \ No newline at end of file diff --git a/front/maintenance.php b/front/maintenance.php index 94ebf11e..4b9f754a 100755 --- a/front/maintenance.php +++ b/front/maintenance.php @@ -174,6 +174,12 @@ $db->close(); +
+
+
+ +
+
diff --git a/front/php/templates/language/en_us.json b/front/php/templates/language/en_us.json index ff1b3f1a..bd50ac87 100755 --- a/front/php/templates/language/en_us.json +++ b/front/php/templates/language/en_us.json @@ -260,6 +260,7 @@ "Maintenance_new_version" : "🆕 A new version is available. Check out the release notes.", "Maintenance_current_version" : "You are up-to-date. Check out what I am working on.", "Maintenance_built_on" : "Built on", + "Maintenance_Running_Version" : "Installed version", "Maintenance_database_path" : "Database-Path", "Maintenance_database_size" : "Database-Size", "Maintenance_database_rows" : "Table (Rows)", diff --git a/front/plugins/README.md b/front/plugins/README.md index db266652..a0367fe8 100755 --- a/front/plugins/README.md +++ b/front/plugins/README.md @@ -19,6 +19,7 @@ | | Yes | ARPSCAN | Script | 📚[arp_scan](/front/plugins/arp_scan/) | | | | CSVBCKP | Script | 📚[csv_backup](/front/plugins/csv_backup/) | | Yes* | | DBCLNP | Script | 📚[db_cleanup](/front/plugins/db_cleanup/) | +| | | DDNS | Script | 📚[ddns_update](/front/plugins/ddns_update/) | | | Yes | DHCPLSS | Script | 📚[dhcp_leases](/front/plugins/dhcp_leases/) | | | | DHCPSRVS | Script | 📚[dhcp_servers](/front/plugins/dhcp_servers/) | | | Yes | INTRNT | Script | 📚[internet_ip](/front/plugins/internet_ip/) | diff --git a/front/plugins/ddns_update/README.md b/front/plugins/ddns_update/README.md index 03fa70f4..972df9f7 100755 --- a/front/plugins/ddns_update/README.md +++ b/front/plugins/ddns_update/README.md @@ -1,6 +1,6 @@ ## Overview -Plugin to run regular database cleanup tasks. It is strongly recommended to have an hourly or at least daily schedule running. +Plugin to run regular DDNS update tasks. ### Usage diff --git a/front/plugins/ddns_update/script.py b/front/plugins/ddns_update/script.py index 67c62168..facb3373 100755 --- a/front/plugins/ddns_update/script.py +++ b/front/plugins/ddns_update/script.py @@ -75,7 +75,7 @@ def ddns_update ( DDNS_UPDATE_URL, DDNS_USER, DDNS_PASSWORD, DDNS_DOMAIN, PREV_I mylog('none', ['[DDNS] ', dns_IP]) # Check DNS Change - if dns_IP != internet_IP : + if dns_IP != PREV_IP : mylog('none', ['[DDNS] Updating Dynamic DNS IP']) message = set_dynamic_DNS_IP (DDNS_UPDATE_URL, DDNS_USER, DDNS_PASSWORD, DDNS_DOMAIN) mylog('none', ['[DDNS] ', message]) diff --git a/front/plugins/internet_ip/README.md b/front/plugins/internet_ip/README.md index 03fa70f4..4d4b08fe 100755 --- a/front/plugins/internet_ip/README.md +++ b/front/plugins/internet_ip/README.md @@ -1,6 +1,6 @@ ## Overview -Plugin to run regular database cleanup tasks. It is strongly recommended to have an hourly or at least daily schedule running. +Plugin to run regular Internet connectivity and IP checks. ### Usage diff --git a/pialert/__main__.py b/pialert/__main__.py index ab90f581..c59e1f7c 100755 --- a/pialert/__main__.py +++ b/pialert/__main__.py @@ -24,7 +24,7 @@ import multiprocessing import conf from const import * from logger import mylog -from helper import filePermissions, isNewVersion, timeNowTZ, updateState, get_setting_value +from helper import filePermissions, timeNowTZ, updateState, get_setting_value from api import update_api from networkscan import process_scan from initialise import importConfigs @@ -60,10 +60,6 @@ def main (): mylog('none', ['[MAIN] Setting up ...']) # has to be level 'none' as user config not loaded yet mylog('none', [f'[conf.tz] Setting up ...{conf.tz}']) - - - # indicates, if a new version is available - conf.newVersionAvailable = False # check file permissions and fix if required filePermissions() @@ -83,24 +79,18 @@ def main (): mylog('debug', '[MAIN] Starting loop') + # Header + init app state + updateState("Initializing") + while True: # re-load user configuration and plugins importConfigs(db) # update time started - conf.loop_start_time = timeNowTZ() + conf.loop_start_time = timeNowTZ() - # TODO fix these loop_start_time = conf.loop_start_time # TODO fix - last_version_check = conf.last_version_check - - # check if new version is available / only check once an hour - if conf.last_version_check + datetime.timedelta(hours=1) < conf.loop_start_time : - # if newVersionAvailable is already true the function does nothing and returns true again - mylog('debug', [f"[Version check] Last version check timestamp: {conf.last_version_check}"]) - conf.last_version_check = conf.loop_start_time - conf.newVersionAvailable = isNewVersion(conf.newVersionAvailable) # Handle plugins executed ONCE if conf.plugins_once_run == False: diff --git a/pialert/helper.py b/pialert/helper.py index 175071bb..3da5aada 100755 --- a/pialert/helper.py +++ b/pialert/helper.py @@ -3,12 +3,12 @@ import io import sys import datetime +# from datetime import strptime import os import re import subprocess import pytz from pytz import timezone -from datetime import timedelta import json import time from pathlib import Path @@ -43,6 +43,9 @@ class app_state_class: # json file containing the state to communicate with the frontend stateFile = apiPath + '/app_state.json' + # if currentState == 'Initializing': + # checkNewVersion(False) + # Update self self.currentState = currentState self.lastUpdated = str(timeNowTZ()) @@ -50,16 +53,20 @@ class app_state_class: # Check if the file exists and init values if os.path.exists(stateFile): with open(stateFile, 'r') as json_file: - previousState = json.load(json_file) - self.settingsSaved = previousState.get("settingsSaved", 0) - self.settingsImported = previousState.get("settingsImported", 0) - self.showSpinner = previousState.get("showSpinner", False) + previousState = json.load(json_file) + self.settingsSaved = previousState.get("settingsSaved", 0) + self.settingsImported = previousState.get("settingsImported", 0) + self.showSpinner = previousState.get("showSpinner", False) + self.isNewVersion = previousState.get("isNewVersion", False) + self.isNewVersionChecked = previousState.get("isNewVersionChecked", 0) else: - self.settingsSaved = 0 - self.settingsImported = 0 - self.showSpinner = False + self.settingsSaved = 0 + self.settingsImported = 0 + self.showSpinner = False + self.isNewVersion = checkNewVersion() + self.isNewVersionChecked = int(timeNow().timestamp()) - # Overwrite with provided parameters if not None + # Overwrite with provided parameters if supplied if settingsSaved is not None: self.settingsSaved = settingsSaved if settingsImported is not None: @@ -67,6 +74,11 @@ class app_state_class: if showSpinner is not None: self.showSpinner = showSpinner + # check for new version every hour and if currently not running new version + if self.isNewVersion is False and self.isNewVersionChecked + 3600 < int(timeNow().timestamp()): + self.isNewVersion = checkNewVersion() + self.isNewVersionChecked = int(timeNow().timestamp()) + # Update .json file with open(stateFile, 'w') as json_file: json.dump(self, json_file, cls=AppStateEncoder, indent=4) @@ -547,36 +559,38 @@ def collect_lang_strings(json, pref, stringSqlParams): #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- -def isNewVersion(newVersion: bool): +def checkNewVersion(): - mylog('debug', [f"[Version check] New version available? {newVersion}"]) + mylog('debug', [f"[Version check] Checking if new version available"]) - if newVersion == False: + newVersion = False - f = open(pialertPath + '/front/buildtimestamp.txt', 'r') - buildTimestamp = int(f.read().strip()) - f.close() + f = open(pialertPath + '/front/buildtimestamp.txt', 'r') + buildTimestamp = int(f.read().strip()) + f.close() + data = "" + + try: + url = requests.get("https://api.github.com/repos/jokob-sk/Pi.Alert/releases") + text = url.text + data = json.loads(text) + except requests.exceptions.ConnectionError as e: + mylog('minimal', ["[Version check] Error: Couldn't check for new release."]) data = "" - try: - url = requests.get("https://api.github.com/repos/jokob-sk/Pi.Alert/releases") - text = url.text - data = json.loads(text) - except requests.exceptions.ConnectionError as e: - mylog('minimal', [" Couldn't check for new release."]) - data = "" + # make sure we received a valid response and not an API rate limit exceeded message + if data != "" and len(data) > 0 and isinstance(data, list) and "published_at" in data[0]: - # make sure we received a valid response and not an API rate limit exceeded message - if data != "" and len(data) > 0 and isinstance(data, list) and "published_at" in data[0]: + dateTimeStr = data[0]["published_at"] - dateTimeStr = data[0]["published_at"] + realeaseTimestamp = int(datetime.datetime.strptime(dateTimeStr, '%Y-%m-%dT%H:%M:%SZ').strftime('%s')) - realeaseTimestamp = int(datetime.datetime.strptime(dateTimeStr, '%Y-%m-%dT%H:%M:%SZ').strftime('%s')) - - if realeaseTimestamp > buildTimestamp + 600: - mylog('none', ["[Version check] New version of the container available!"]) - newVersion = True + if realeaseTimestamp > buildTimestamp + 600: + mylog('none', ["[Version check] New version of the container available!"]) + newVersion = True + else: + mylog('none', ["[Version check] Running the latest version."]) return newVersion