import os from pathlib import Path from flask import Flask, Blueprint, request, send_from_directory, jsonify from flask_cors import CORS, cross_origin from flask_socketio import SocketIO, Namespace from libs.app.common.logging import get_logger from libs.app.common.paths import ROOT_DIR from libs.fspn.utils.wrapper_util import threaded from .apiBlueprint import ApiBlueprint from .eventsSocketio import EventsSocketio from libs.noSys.noSysModule import NoSysModule from .certs import generate_ca_and_cert, add_ca_os logger = get_logger() class Api(NoSysModule): def __init__(self, nosys_core): super().__init__(nosys_core) self.dist_dir = os.path.join(ROOT_DIR, "libs/vueNoSys/dist") self.assets_dir = os.path.join(self.dist_dir, "assets") self.app = Flask(__name__, static_folder=self.assets_dir, template_folder=self.dist_dir) CORS(self.app, resources={r"/*": {"origins": "*"}}, supports_credentials=True) self.socketio = SocketIO(self.app, cors_allowed_origins="*") self.server = None self.host = self.config["server"]["host"] self.port = self.config["server"]["port"] self.register_blueprint(BasicBlueprint(self).blueprint) self.register_socketio(BasicEventSocketIo(self)) def setup(self): self.nosys_core.modules.api = self certs_path = os.path.join(ROOT_DIR, "libs", "api", "certs") self.ca_path = os.path.join(certs_path , "ca.pem") self.ca_key_path = os.path.join(certs_path, "ca_key.pem") self.cert_path = os.path.join(certs_path, "cert.pem") self.key_path = os.path.join(certs_path, "key.pem") if not os.path.exists(self.cert_path) or not os.path.exists(self.key_path) or not os.path.exists(self.ca_path) or not os.path.exists(self.ca_key_path): Path(certs_path).mkdir(parents=True, exist_ok=True) logger.debug("Generating certs") ca, cert, key = generate_ca_and_cert(self.ca_path, self.ca_key_path, self.cert_path, self.key_path) logger.debug("Adding ca to operational system") add_ca_os(self.ca_path) logger.debug("Cert installed") else: logger.debug("Certs already exists") def register_blueprint(self, blueprint:Blueprint): try: self.app.register_blueprint(blueprint) logger.debug(f"Registered blueprint {blueprint.url_prefix}") except Exception: logger.exception(f"Failed registering blueprint {blueprint.url_prefix}") def register_socketio(self, handler:EventsSocketio): try: handler.register_events(self.socketio) logger.debug(f"Registered socketio {handler.namespace}") except Exception: logger.exception(f"Failed registering socketio {handler.namespace}") def on_nosys_ready(self, event): self.run() @threaded def run(self): self.routes() logger.debug(f'Running Flask API ({self.host}:{self.port}) with urls: {self.app.url_map}') try: self.socketio.run(app=self.app, host=self.host, port=self.port, allow_unsafe_werkzeug=True, ssl_context=(self.cert_path, self.key_path)) except Exception as e: logger.error(e) def routes(self): @self.app.route("/", defaults={"path": ""}) @self.app.route("/") def index(path): if path != "" and os.path.exists(os.path.join(self.dist_dir, path)): return send_from_directory(self.dist_dir, path) return send_from_directory(self.dist_dir, "index.html") class BasicBlueprint(ApiBlueprint): def routes(self): self.api:Api = self.module @self.blueprint.route('/') def show(): return "API" class BasicEventSocketIo(EventsSocketio): def events(self): @self.on("connect") def on_connect(*args, **kwargs): print('API connected',args, kwargs, request.sid) self.emit("welcome", {"msg": f"Your id {request.sid}"}) @self.on("disconnect") def on_disconnect(*args, **kwargs): print('API disconnected',args, kwargs, request.sid) @self.on("message") def on_message(*args, **kwargs): print('API Message',args, kwargs) self.emit("message", f"Message received {args[0]}")