diff --git a/fHDHR/__init__.py b/fHDHR/__init__.py index d485599..d7644db 100644 --- a/fHDHR/__init__.py +++ b/fHDHR/__init__.py @@ -21,6 +21,8 @@ class fHDHR_INT_OBJ(): self.api = fHDHR_API_URLs(settings, self.web) + self.threads = {} + class fHDHR_OBJ(): diff --git a/fHDHR/cli/run.py b/fHDHR/cli/run.py index 423e4b2..fa64582 100644 --- a/fHDHR/cli/run.py +++ b/fHDHR/cli/run.py @@ -1,8 +1,6 @@ import os import sys import argparse -import time -import threading from fHDHR import fHDHR_VERSION, fHDHR_OBJ import fHDHR.exceptions @@ -38,28 +36,24 @@ def run(settings, logger, db, script_dir, fHDHR_web, origin, alternative_epg): try: - fhdhr.logger.info("HTTP Server Starting") - fhdhr_web = threading.Thread(target=fhdhrweb.run) - fhdhr_web.start() + # Start Flask Thread + fhdhrweb.start() + # Start SSDP Thread if settings.dict["fhdhr"]["discovery_address"]: - fhdhr.logger.info("SSDP Server Starting") - fhdhr_ssdp = threading.Thread(target=fhdhr.device.ssdp.run) - fhdhr_ssdp.start() + fhdhr.device.ssdp.start() + # Start EPG Thread if settings.dict["epg"]["method"]: - fhdhr.logger.info("EPG Update Thread Starting") - fhdhr_epg = threading.Thread(target=fhdhr.device.epg.run) - fhdhr_epg.start() + fhdhr.device.epg.start() # Perform some actions now that HTTP Server is running - fhdhr.logger.info("Waiting 3 seconds to send startup tasks trigger.") - time.sleep(3) fhdhr.api.get("/api/startup_tasks") # wait forever - while True: - time.sleep(3600) + while fhdhr.threads["flask"].is_alive(): + restart_code = "restart" + return restart_code except KeyboardInterrupt: return ERR_CODE_NO_RESTART @@ -92,7 +86,10 @@ def main(script_dir, fHDHR_web, origin, alternative_epg): try: args = build_args_parser() - return start(args, script_dir, fHDHR_web, origin, alternative_epg) + while True: + returned_code = start(args, script_dir, fHDHR_web, origin, alternative_epg) + if returned_code not in ["restart"]: + return returned_code except KeyboardInterrupt: print("\n\nInterrupted") return ERR_CODE diff --git a/fHDHR/device/epg/__init__.py b/fHDHR/device/epg/__init__.py index fa6e554..2ef6bdc 100644 --- a/fHDHR/device/epg/__init__.py +++ b/fHDHR/device/epg/__init__.py @@ -1,6 +1,7 @@ import os import time import datetime +import threading from fHDHR.tools import channel_sort @@ -39,6 +40,8 @@ class EPG(): self.epg_update_url = "/api/epg?method=update" + self.fhdhr.threads["epg"] = threading.Thread(target=self.run) + def clear_epg_cache(self, method=None): if not method: @@ -294,19 +297,25 @@ class EPG(): self.fhdhr.db.set_fhdhr_value("update_time", method, time.time()) self.fhdhr.logger.info("Wrote %s EPG cache. %s Programs for %s Channels" % (epgtypename, total_programs, total_channels)) + def start(self): + self.fhdhr.logger.info("EPG Update Thread Starting") + self.fhdhr.threads["epg"].start() + + def stop(self): + self.fhdhr.logger.info("EPG Update Thread Stopping") + def run(self): time.sleep(1800) - try: - while True: - for epg_method in self.epg_methods: - last_update_time = self.fhdhr.db.get_fhdhr_value("update_time", epg_method) - updatetheepg = False - if not last_update_time: - updatetheepg = True - elif time.time() >= (last_update_time + self.sleeptime[epg_method]): - updatetheepg = True - if updatetheepg: - self.fhdhr.api.get("%s&source=%s" % (self.epg_update_url, epg_method)) - time.sleep(1800) - except KeyboardInterrupt: - pass + while True: + for epg_method in self.epg_methods: + last_update_time = self.fhdhr.db.get_fhdhr_value("update_time", epg_method) + updatetheepg = False + if not last_update_time: + updatetheepg = True + elif time.time() >= (last_update_time + self.sleeptime[epg_method]): + updatetheepg = True + if updatetheepg: + self.fhdhr.api.get("%s&source=%s" % (self.epg_update_url, epg_method)) + time.sleep(1800) + + self.stop() diff --git a/fHDHR/device/ssdp/__init__.py b/fHDHR/device/ssdp/__init__.py index c095325..7c70400 100644 --- a/fHDHR/device/ssdp/__init__.py +++ b/fHDHR/device/ssdp/__init__.py @@ -2,6 +2,7 @@ import socket import struct import time +import threading from .ssdp_detect import fHDHR_Detect from .rmg_ssdp import RMG_SSDP @@ -15,6 +16,8 @@ class SSDPServer(): self.detect_method = fHDHR_Detect(fhdhr) + self.fhdhr.threads["ssdp"] = threading.Thread(target=self.run) + if (self.fhdhr.config.dict["fhdhr"]["discovery_address"] and self.fhdhr.config.dict["ssdp"]["enabled"]): self.setup_ssdp() @@ -32,6 +35,21 @@ class SSDPServer(): self.do_alive() self.m_search() + def start(self): + self.fhdhr.logger.info("SSDP Server Starting") + self.fhdhr.threads["ssdp"].start() + + def stop(self): + self.fhdhr.logger.info("SSDP Server Stopping") + self.sock.close() + + def run(self): + while True: + data, address = self.sock.recvfrom(1024) + self.on_recv(data, address) + self.do_alive() + self.stop() + def do_alive(self, forcealive=False): send_alive = False @@ -132,15 +150,6 @@ class SSDPServer(): return data.encode("utf-8") - def run(self): - try: - while True: - data, address = self.sock.recvfrom(1024) - self.on_recv(data, address) - self.do_alive() - except KeyboardInterrupt: - self.sock.close() - def setup_ssdp(self): self.sock = None diff --git a/fHDHR_web/__init__.py b/fHDHR_web/__init__.py index b3e6d15..0f45e8c 100644 --- a/fHDHR_web/__init__.py +++ b/fHDHR_web/__init__.py @@ -1,5 +1,7 @@ from gevent.pywsgi import WSGIServer from flask import Flask, request, session +import threading +import uuid from .pages import fHDHR_Pages from .files import fHDHR_Files @@ -23,6 +25,7 @@ class fHDHR_HTTP_Server(): self.fhdhr.logger.info("Loading Flask.") self.fhdhr.app = Flask("fHDHR", template_folder=self.template_folder) + self.instance_id = str(uuid.uuid4()) # Allow Internal API Usage self.fhdhr.app.testing = True @@ -63,11 +66,24 @@ class fHDHR_HTTP_Server(): self.fhdhr.app.after_request(self.after_request) self.fhdhr.app.before_first_request(self.before_first_request) + self.fhdhr.threads["flask"] = threading.Thread(target=self.run) + + def start(self): + self.fhdhr.logger.info("Flask HTTP Thread Starting") + self.fhdhr.threads["flask"].start() + + def stop(self): + self.fhdhr.logger.info("Flask HTTP Thread Stopping") + self.http.stop() + def before_first_request(self): self.fhdhr.logger.info("HTTP Server Online.") def before_request(self): + session["session_id"] = str(uuid.uuid4()) + session["instance_id"] = self.instance_id + session["is_internal_api"] = self.detect_internal_api(request) if session["is_internal_api"]: self.fhdhr.logger.debug("Client is using internal API call.") @@ -84,6 +100,8 @@ class fHDHR_HTTP_Server(): session["tuner_used"] = None + session["restart"] = False + self.fhdhr.logger.debug("Client %s requested %s Opening" % (request.method, request.path)) def after_request(self, response): @@ -96,7 +114,10 @@ class fHDHR_HTTP_Server(): # tuner.close() self.fhdhr.logger.debug("Client %s requested %s Closing" % (request.method, request.path)) - return response + if not session["restart"]: + return response + else: + return self.stop() def detect_internal_api(self, request): user_agent = request.headers.get('User-Agent') @@ -165,8 +186,8 @@ class fHDHR_HTTP_Server(): self.http = WSGIServer(self.fhdhr.api.address_tuple, self.fhdhr.app.wsgi_app, log=self.fhdhr.logger) - try: self.http.serve_forever() - except KeyboardInterrupt: - self.http.stop() + self.stop() + except AttributeError: + self.fhdhr.logger.info("HTTP Server Offline") diff --git a/fHDHR_web/api/settings.py b/fHDHR_web/api/settings.py index a4fcf19..53a4d48 100644 --- a/fHDHR_web/api/settings.py +++ b/fHDHR_web/api/settings.py @@ -1,4 +1,4 @@ -from flask import request, redirect +from flask import request, redirect, session import urllib.parse @@ -34,6 +34,11 @@ class Settings(): self.fhdhr.config.write(config_section, config_name, config_value) + elif method == "restart": + instance_id = request.args.get('instance_id', default=None, type=str) + if instance_id == session["instance_id"]: + session["restart"] = True + if redirect_url: return redirect(redirect_url + "?retmessage=" + urllib.parse.quote("%s Success" % method)) else: diff --git a/fHDHR_web/templates/settings.html b/fHDHR_web/templates/settings.html index a4be054..504038b 100644 --- a/fHDHR_web/templates/settings.html +++ b/fHDHR_web/templates/settings.html @@ -2,67 +2,72 @@ {% block content %} -

fHDHR Settings

+

fHDHR Settings

-

Settings will require a manual restart.

+

Some Settings will require a manual restart.

- {% for config_section in list(web_settings_dict.keys()) %} +
+

Note: This may take some time, and you will have to refresh your page.

+
+
- {% if config_section == "origin" %} -

{{ fhdhr.config.dict["main"]["dictpopname"] }}

- {% else %} -

{{ config_section }}

- {% endif %} + {% for config_section in list(web_settings_dict.keys()) %} + + {% if config_section == "origin" %} +

{{ fhdhr.config.dict["main"]["dictpopname"] }}

+ {% else %} +

{{ config_section }}

+ {% endif %}
- - - - - - - - - - +
Config NameConfig Default ValueConfig ValueAction
+ + + + + + + + + {% for config_item in list(web_settings_dict[config_section].keys()) %} - - + + - + - - + + - + {% endfor %} - + - {% endfor %} + {% endfor %} {% endblock %}
Config NameConfig Default ValueConfig ValueAction
{{ config_item }}
{{ config_item }}{{ web_settings_dict[config_section][config_item]["value_default"] }}{{ web_settings_dict[config_section][config_item]["value_default"] }} -
- - - - {% if web_settings_dict[config_section][config_item]["hide"] %} - - {% else %} - - {% endif %} -
- - - - -
- - - - - -
-
+
+ + + + {% if web_settings_dict[config_section][config_item]["hide"] %} + + {% else %} + + {% endif %} +
+ + + + +
+ + + + + +
+