class HttpServer: # prepare may be rewrite it config = { 'SECRET_KEY': 'someWOrkSD20KMS9330)&#', 'coco': None, 'LOGIN_URL': '/login' } init_kwargs = dict( async_mode="eventlet", # async_mode="threading", # ping_timeout=20, # ping_interval=10, # engineio_logger=True, # logger=True ) def __init__(self): config.update(self.config) self.flask_app = Flask(__name__, template_folder='dist') self.flask_app.config.update(config) self.socket_io = SocketIO() self.register_routes() self.register_error_handler() def register_routes(self): self.socket_io.on_namespace(ProxyNamespace('/ssh')) @staticmethod def on_error_default(e): logger.exception(e) def register_error_handler(self): self.socket_io.on_error_default(self.on_error_default) def run(self): # return host = config["BIND_HOST"] port = config["HTTPD_PORT"] print('Starting websocket server at {}:{}'.format(host, port)) self.socket_io.init_app( self.flask_app, **self.init_kwargs ) self.socket_io.run(self.flask_app, port=port, host=host, debug=False) def shutdown(self): self.socket_io.stop() pass
from coco.httpd.ws import ProxyNamespace, ElfinderNamespace logger = get_logger(__file__) app = Flask(__name__, template_folder='templates', static_folder='static') app.config.update(config) socket_io = SocketIO() socket_io.on_namespace(ProxyNamespace('/ssh')) socket_io.on_namespace(ElfinderNamespace('/elfinder')) if os.environ.get('USE_EVENTLET', '1') == '1': init_kwargs = {'async_mode': 'eventlet'} else: init_kwargs = {'async_mode': 'threading'} socket_io.init_app(app, **init_kwargs), socket_io.on_error_default(lambda x: logger.exception(x)) class HttpServer: @staticmethod def run(): host = config["BIND_HOST"] port = config["HTTPD_PORT"] print('Starting websocket server at {}:{}'.format(host, port)) socket_io.run(app, port=port, host=host, debug=False) @staticmethod def shutdown(): socket_io.stop() pass
class Cgi(object): def __init__(self, folder='%s/static' % getcwd()): self.events = { 'push-sio': self.push, 'create-cgi': self.create, 'cgi-options': self.decorate } self.args = { 'emitter': None, 'host': '0.0.0.0', 'port': 5000, 'logger': None, 'debug': False, 'deamon': True, 'key': 'ssl/host.key', 'crt': 'ssl/host.crt', 'env': 'production' } from flask import Flask self.cgi = Flask(__name__, template_folder=folder, static_folder=folder) from flask_socketio import SocketIO # async_mode eventlet|gevent|threading self.socket = SocketIO( self.cgi, async_mode='threading', debug=self.args.get( 'debug')) # eventlet is best performance, but threading works self.socket.on_error_default( self.error ) # == @socketio.on_error_default | socketio.on_error(None)(handler) from flask_login import LoginManager self.login = LoginManager(self.cgi) self.login.login_view = 'login' # == url_for(login) # name of the function from glob import glob path = '%s/static/errors/' % getcwd() pages = glob('%s[1-5][0-9][0-9].html' % path) for i, page in enumerate(pages): pages[i] = int(page.replace(path, '').replace('.html', '')) CgiErrors().decorate({'errors': pages}).create(self.cgi) CgiRoutes().decorate({'watchdog': 'firebase'}).create(self.cgi) def decorate(self, arguments): from Process import decorate return decorate(self, arguments) def create(self, data={}): self.cgi.config['HOST'] = self.args.get('host') self.cgi.config['PORT'] = self.args.get('port') self.cgi.config['DEBUG'] = self.args.get('debug') self.cgi.config['ENV'] = self.args.get('env') # production|development if not None == self.args.get('logger'): # self.cgi.logger = self.args.get('logger') # error can't set attribute if (0 < len(self.cgi.logger.handlers)): self.cgi.logger.handlers.pop() self.cgi.logger.addHandler(self.args.get('logger')) from threading import Thread self.thread = Thread(target=self.start) self.thread.setDaemon(self.args.get('deamon')) self.thread.start() return self def start(self): self.cgi.run(host=self.args.get('host'), ssl_context=(self.args.get('crt'), self.args.get('key'))) return self def error(self, error): logging.error('default socket error %s' % str(error)) def push(self, data): namespace = data.get('namespace') self.socket.emit('response', { 'call': '%s-got' % namespace, 'id': 'push-%s' % namespace, 'data': data }, namespace='/%s' % namespace)
class Monitor(object): def __init__(self, folder=os.getcwd()): self.events = { 'push-sio': self.push, 'start-monitor': self.create, 'monitor-options': self.decorate } self.args = { 'emitter': None, 'host': '0.0.0.0', 'port': 5000, 'logger': None, 'debug': False, 'deamon': True, 'namespace': 'default' } from flask import Flask self.cgi = Flask(__name__, template_folder=folder, static_folder=folder) from flask_socketio import SocketIO # async_mode eventlet|gevent|threading self.socket = SocketIO( self.cgi, async_mode='threading', debug=self.args.get( 'debug')) # eventlet is best performance, but threading works self.socket.on_error_default( self.error ) # == @socketio.on_error_default | socketio.on_error(None)(handler) MonitorRoutes().create(self.cgi) self.pusher = MonitorSocket().create(self.socket) def decorate(self, arguments): from Util import decorate self.pusher.decorate(arguments) return decorate(self, arguments) def create(self, data={}): self.cgi.config['HOST'] = self.args.get('host') self.cgi.config['PORT'] = self.args.get('port') self.cgi.config['DEBUG'] = self.args.get('debug') if not None == self.args.get('logger'): # self.cgi.logger = self.args.get('logger') # error can't set attribute if (0 < len(self.cgi.logger.handlers)): self.cgi.logger.handlers.pop() self.cgi.logger.addHandler(self.args.get('logger')) from threading import Thread self.thread = Thread(target=self.cgi.run) self.thread.setDaemon(self.args.get('deamon')) self.thread.start() self.pusher.create(self.socket) return self def error(self, error): logging.error('default socket error %s' % str(error)) def push(self, data): namespace = data.get('namespace') self.socket.emit('response', { 'call': '%s-got' % namespace, 'id': 'push-%s' % namespace, 'data': data }, namespace='/%s' % namespace)
class SocketIOServer: """Basic server for socketio.""" name: str = None app: Flask = None socket: SocketIO = None _socket_base_url: str = None _socket_ip: str = '0.0.0.0' _socket_port: int = 7666 def __init__(self, name: str = None, socket_ip: str = None, socket_port: int = None) -> None: """ Init the api server, and init the super class RPC """ if name is None: raise Exception("SocketServer needs distinguishable name for logging purposes") self.name = '{}.{}'.format(__name__, name) self.logger = setup_logger(name=self.name) self.logger.info('Initializing %s component.', self.name) self.app = Flask(__name__) CORS(self.app) self.app.config['SECRET_KEY'] = "s!"#$123%!%&!&e!"123424#34534$%!5345%&!&c345!"#234$%!1342334224%&!&et!242!"#$%342!%&!&" self.socket = SocketIO(self.app) if socket_ip is None: self.logger.info("SocketServer got no `socket_ip` defaulting to {}".format(self._socket_ip)) else: self._socket_ip = socket_ip if socket_port is None: self.logger.info("SocketServer got no `socket_port` defaulting to {}".format(self._socket_port)) else: self._socket_port = socket_port self._socket_base_url = '{}:{}'.format(self._socket_ip, self._socket_port) self.logger.info("Will serve Socket at %s", self._socket_base_url) def Start(self) -> None: """ Spawns the thread that will run the `run` method of SocketServer. The `run` method creates the HTTP Server and maps it to the Flask app.. """ thread = threading.Thread(target=self.run, daemon=True) thread.start() def cleanup(self) -> None: self.logger.info("Stopping API Server") self.srv.shutdown() def run(self): """ Method that runs flask-socketio app in its own thread forever. """ self.logger.info(f"Starting Socket Server at {self._socket_base_url}") try: self.socket.run(self.app, host=self._socket_ip, port=self._socket_port, log_output=True) except Exception: self.logger.exception("Socket Server failed to start.") def json_dump(self, return_value): """ Helper function to jsonify object for a webserver """ return jsonify(return_value) def json_error(self, error_msg): return jsonify({"error": error_msg}), 502 def register_base_socket_events(self): """ Registers flask app URLs that are calls to functonality in rpc.rpc. First two arguments passed are /URL and 'Label' Label can be used as a shortcut when refactoring :return: """ # Error handling self.socket.on_error_default(self._base_error_handler) # Testing self.socket.on_event("message", self._base_message_handler, namespace="/") self.socket.on_event("json", self._base_json_handler, namespace="/") self.socket.on_event("connect", self._base_connection_handler, namespace="/") self.socket.on_event("disconnect", self._base_disconnection_handler, namespace="/") def register_socket_events(self, events: List[SocketIOEvent]): """ Registers flask-socketio events that are handled by the socket server. :param events: is a list of events of type `SocketEvent` from the same module. :return: """ # Register the passed events for event in events: self.socket.on_event( message=event.name, handler=event.handler, namespace=event.namespace, ) def _base_error_handler(self, e): """ Base error handler. """ print("An error has occurred: " + str(e)) def _base_message_handler(self, message): """ Base message handler. """ print("received message: " + message) def _base_json_handler(self, message): """ Base json handler. """ print("received json: " + message) def _base_connection_handler(self, message): """ Base connection handler. """ print("received message: " + message) def _base_disconnection_handler(self, message): """ Base disconnection handler. """ print("received message: " + message)