def __init__(self, config): self.server = config.get_server() self.tornado_server = None self.api_cache = {} self.registered_base_handlers = [] self.max_upload_size = config.getint('max_upload_size', 200) self.max_upload_size *= 1024 * 1024 # Set Up Websocket and Authorization Managers self.wsm = WebsocketManager(self.server) self.auth = Authorization(config['authorization']) mimetypes.add_type('text/plain', '.log') mimetypes.add_type('text/plain', '.gcode') mimetypes.add_type('text/plain', '.cfg') debug = config.getboolean('enable_debug_logging', True) # Set up HTTP only requests self.mutable_router = MutableRouter(self) app_handlers = [(AnyMatches(), self.mutable_router), (r"/websocket", WebSocket), (r"/api/version", EmulateOctoprintHandler)] self.app = tornado.web.Application(app_handlers, serve_traceback=debug, websocket_ping_interval=10, websocket_ping_timeout=30, parent=self) self.get_handler_delegate = self.app.get_handler_delegate # Register handlers logfile = config['cmd_args'].get('logfile') self.register_static_file_handler("moonraker.log", logfile) self.auth.register_handlers(self)
def __init__(self, config: ConfigHelper) -> None: self.server = config.get_server() self.http_server: Optional[HTTPServer] = None self.secure_server: Optional[HTTPServer] = None self.api_cache: Dict[str, APIDefinition] = {} self.registered_base_handlers: List[str] = [] self.max_upload_size = config.getint('max_upload_size', 1024) self.max_upload_size *= 1024 * 1024 # SSL config self.cert_path: str = self._get_path_option(config, 'ssl_certificate_path') self.key_path: str = self._get_path_option(config, 'ssl_key_path') # Set Up Websocket and Authorization Managers self.wsm = WebsocketManager(self.server) mimetypes.add_type('text/plain', '.log') mimetypes.add_type('text/plain', '.gcode') mimetypes.add_type('text/plain', '.cfg') self.debug = config.getboolean('enable_debug_logging', False) log_level = logging.DEBUG if self.debug else logging.INFO logging.getLogger().setLevel(log_level) app_args: Dict[str, Any] = { 'serve_traceback': self.debug, 'websocket_ping_interval': 10, 'websocket_ping_timeout': 30, 'parent': self, 'default_handler_class': AuthorizedErrorHandler, 'default_handler_args': {}, 'log_function': self.log_request } # Set up HTTP only requests self.mutable_router = MutableRouter(self) app_handlers: List[Any] = [(AnyMatches(), self.mutable_router), (r"/websocket", WebSocket), (r"/server/redirect", RedirectHandler)] self.app = tornado.web.Application(app_handlers, **app_args) self.get_handler_delegate = self.app.get_handler_delegate # Register handlers logfile = config['system_args'].get('logfile') if logfile: self.register_static_file_handler("moonraker.log", logfile, force=True) self.register_static_file_handler("klippy.log", DEFAULT_KLIPPY_LOG_PATH, force=True)
def __init__(self, config): self.server = config.get_server() self.tornado_server = None self.api_cache = {} self.registered_base_handlers = [] self.max_upload_size = config.getint('max_upload_size', 1024) self.max_upload_size *= 1024 * 1024 # Set Up Websocket and Authorization Managers self.wsm = WebsocketManager(self.server) self.auth = Authorization(config['authorization']) mimetypes.add_type('text/plain', '.log') mimetypes.add_type('text/plain', '.gcode') mimetypes.add_type('text/plain', '.cfg') debug = config.getboolean('enable_debug_logging', False) log_level = logging.DEBUG if debug else logging.INFO logging.getLogger().setLevel(log_level) app_args = { 'serve_traceback': debug, 'websocket_ping_interval': 10, 'websocket_ping_timeout': 30, 'parent': self, 'default_handler_class': AuthorizedErrorHandler, 'default_handler_args': {} } if not debug: app_args['log_function'] = self.log_release_mode # Set up HTTP only requests self.mutable_router = MutableRouter(self) app_handlers = [(AnyMatches(), self.mutable_router), (r"/websocket", WebSocket)] self.app = tornado.web.Application(app_handlers, **app_args) self.get_handler_delegate = self.app.get_handler_delegate # Register handlers logfile = config['system_args'].get('logfile') if logfile: self.register_static_file_handler("moonraker.log", logfile, force=True) self.register_static_file_handler("klippy.log", DEFAULT_KLIPPY_LOG_PATH, force=True) self.auth.register_handlers(self)
def __init__(self, server, args): self.server = server self.tornado_server = None self.api_cache = {} self.registered_base_handlers = [] # Set Up Websocket and Authorization Managers self.wsm = WebsocketManager(server) self.auth = Authorization(args.apikey) mimetypes.add_type('text/plain', '.log') mimetypes.add_type('text/plain', '.gcode') mimetypes.add_type('text/plain', '.cfg') # Set up HTTP only requests self.mutable_router = MutableRouter(self) app_handlers = [(AnyMatches(), self.mutable_router), (r"/websocket", WebSocket, { 'wsm': self.wsm, 'auth': self.auth }), (r"/api/version", EmulateOctoprintHandler, { 'server': server, 'auth': self.auth })] self.app = tornado.web.Application(app_handlers, serve_traceback=args.debug, websocket_ping_interval=10, websocket_ping_timeout=30, enable_cors=False) self.get_handler_delegate = self.app.get_handler_delegate # Register handlers self.register_static_file_handler("moonraker.log", args.logfile) self.auth.register_handlers(self)
class MoonrakerApp: def __init__(self, config): self.server = config.get_server() self.tornado_server = None self.api_cache = {} self.registered_base_handlers = [] self.max_upload_size = config.getint('max_upload_size', 200) self.max_upload_size *= 1024 * 1024 # Set Up Websocket and Authorization Managers self.wsm = WebsocketManager(self.server) self.auth = Authorization(config['authorization']) mimetypes.add_type('text/plain', '.log') mimetypes.add_type('text/plain', '.gcode') mimetypes.add_type('text/plain', '.cfg') debug = config.getboolean('enable_debug_logging', True) # Set up HTTP only requests self.mutable_router = MutableRouter(self) app_handlers = [(AnyMatches(), self.mutable_router), (r"/websocket", WebSocket), (r"/api/version", EmulateOctoprintHandler)] self.app = tornado.web.Application(app_handlers, serve_traceback=debug, websocket_ping_interval=10, websocket_ping_timeout=30, parent=self) self.get_handler_delegate = self.app.get_handler_delegate # Register handlers logfile = config['cmd_args'].get('logfile') self.register_static_file_handler("moonraker.log", logfile) self.auth.register_handlers(self) def listen(self, host, port): self.tornado_server = self.app.listen( port, address=host, max_body_size=self.max_upload_size, xheaders=True) def get_server(self): return self.server def get_auth(self): return self.auth def get_websocket_manager(self): return self.wsm async def close(self): if self.tornado_server is not None: self.tornado_server.stop() await self.tornado_server.close_all_connections() await self.wsm.close() self.auth.close() def register_remote_handler(self, endpoint): if endpoint in RESERVED_ENDPOINTS: return api_def = self._create_api_definition(endpoint) if api_def.uri in self.registered_base_handlers: # reserved handler or already registered return logging.info( f"Registering remote endpoint - " f"HTTP: ({' '.join(api_def.request_methods)}) {api_def.uri}; " f"Websocket: {', '.join(api_def.ws_methods)}") self.wsm.register_remote_handler(api_def) params = {} params['arg_parser'] = api_def.parser params['remote_callback'] = api_def.endpoint self.mutable_router.add_handler(api_def.uri, RemoteRequestHandler, params) self.registered_base_handlers.append(api_def.uri) def register_local_handler(self, uri, request_methods, callback, protocol=["http", "websocket"]): if uri in self.registered_base_handlers: return api_def = self._create_api_definition(uri, request_methods, is_remote=False) msg = "Registering local endpoint" if "http" in protocol: msg += f" - HTTP: ({' '.join(request_methods)}) {uri}" params = {} params['methods'] = request_methods params['arg_parser'] = api_def.parser params['callback'] = callback self.mutable_router.add_handler(uri, LocalRequestHandler, params) self.registered_base_handlers.append(uri) if "websocket" in protocol: msg += f" - Websocket: {', '.join(api_def.ws_methods)}" self.wsm.register_local_handler(api_def, callback) logging.info(msg) def register_static_file_handler(self, pattern, file_path): if pattern[0] != "/": pattern = "/server/files/" + pattern if os.path.isfile(file_path): pattern += '()' elif os.path.isdir(file_path): if pattern[-1] != "/": pattern += "/" pattern += "(.*)" else: logging.info(f"Invalid file path: {file_path}") return logging.debug(f"Registering static file: ({pattern}) {file_path}") params = {'path': file_path} self.mutable_router.add_handler(pattern, FileRequestHandler, params) def register_upload_handler(self, pattern): self.mutable_router.add_handler(pattern, FileUploadHandler, {}) def remove_handler(self, endpoint): api_def = self.api_cache.get(endpoint) if api_def is not None: self.wsm.remove_handler(api_def.uri) self.mutable_router.remove_handler(api_def.ws_method) def _create_api_definition(self, endpoint, request_methods=[], is_remote=True): if endpoint in self.api_cache: return self.api_cache[endpoint] if endpoint[0] == '/': uri = endpoint elif is_remote: uri = "/printer/" + endpoint else: uri = "/server/" + endpoint ws_methods = [] if is_remote: # Remote requests accept both GET and POST requests. These # requests execute the same callback, thus they resolve to # only a single websocket method. ws_methods.append(uri[1:].replace('/', '.')) request_methods = ['GET', 'POST'] else: name_parts = uri[1:].split('/') if len(request_methods) > 1: for req_mthd in request_methods: func_name = req_mthd.lower() + "_" + name_parts[-1] ws_methods.append(".".join(name_parts[:-1] + [func_name])) else: ws_methods.append(".".join(name_parts)) if not is_remote and len(request_methods) != len(ws_methods): raise self.server.error( "Invalid API definition. Number of websocket methods must " "match the number of request methods") if endpoint.startswith("objects/"): parser = _status_parser else: parser = _default_parser api_def = APIDefinition(endpoint, uri, ws_methods, request_methods, parser) self.api_cache[endpoint] = api_def return api_def
class MoonrakerApp: def __init__(self, config: ConfigHelper) -> None: self.server = config.get_server() self.http_server: Optional[HTTPServer] = None self.secure_server: Optional[HTTPServer] = None self.api_cache: Dict[str, APIDefinition] = {} self.registered_base_handlers: List[str] = [] self.max_upload_size = config.getint('max_upload_size', 1024) self.max_upload_size *= 1024 * 1024 # SSL config self.cert_path: str = self._get_path_option(config, 'ssl_certificate_path') self.key_path: str = self._get_path_option(config, 'ssl_key_path') # Set Up Websocket and Authorization Managers self.wsm = WebsocketManager(self.server) mimetypes.add_type('text/plain', '.log') mimetypes.add_type('text/plain', '.gcode') mimetypes.add_type('text/plain', '.cfg') self.debug = config.getboolean('enable_debug_logging', False) log_level = logging.DEBUG if self.debug else logging.INFO logging.getLogger().setLevel(log_level) app_args: Dict[str, Any] = { 'serve_traceback': self.debug, 'websocket_ping_interval': 10, 'websocket_ping_timeout': 30, 'parent': self, 'default_handler_class': AuthorizedErrorHandler, 'default_handler_args': {}, 'log_function': self.log_request } # Set up HTTP only requests self.mutable_router = MutableRouter(self) app_handlers: List[Any] = [(AnyMatches(), self.mutable_router), (r"/websocket", WebSocket), (r"/server/redirect", RedirectHandler)] self.app = tornado.web.Application(app_handlers, **app_args) self.get_handler_delegate = self.app.get_handler_delegate # Register handlers logfile = config['system_args'].get('logfile') if logfile: self.register_static_file_handler("moonraker.log", logfile, force=True) self.register_static_file_handler("klippy.log", DEFAULT_KLIPPY_LOG_PATH, force=True) def _get_path_option(self, config: ConfigHelper, option: str) -> str: path: Optional[str] = config.get(option, None) if path is None: return "" expanded = os.path.abspath(os.path.expanduser(path)) if not os.path.exists(expanded): raise self.server.error(f"Invalid path for option '{option}', " f"{path} does not exist") return expanded def listen(self, host: str, port: int, ssl_port: int) -> None: self.http_server = self.app.listen(port, address=host, max_body_size=MAX_BODY_SIZE, xheaders=True) if os.path.exists(self.cert_path) and os.path.exists(self.key_path): logging.info(f"Starting secure server on port {ssl_port}") ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) ssl_ctx.load_cert_chain(self.cert_path, self.key_path) self.secure_server = self.app.listen(ssl_port, address=host, max_body_size=MAX_BODY_SIZE, xheaders=True, ssl_options=ssl_ctx) else: logging.info("SSL Certificate/Key not configured, " "aborting HTTPS Server startup") def log_request(self, handler: tornado.web.RequestHandler) -> None: status_code = handler.get_status() if not self.debug and status_code in [200, 204, 206, 304]: # don't log successful requests in release mode return if status_code < 400: log_method = access_log.info elif status_code < 500: log_method = access_log.warning else: log_method = access_log.error request_time = 1000.0 * handler.request.request_time() user = handler.current_user username = "******" if user is not None and 'username' in user: username = user['username'] log_method(f"{status_code} {handler._request_summary()} " f"[{username}] {request_time:.2f}ms") def get_server(self) -> Server: return self.server def get_websocket_manager(self) -> WebsocketManager: return self.wsm async def close(self) -> None: if self.http_server is not None: self.http_server.stop() await self.http_server.close_all_connections() if self.secure_server is not None: self.secure_server.stop() await self.secure_server.close_all_connections() await self.wsm.close() def register_remote_handler(self, endpoint: str) -> None: if endpoint in RESERVED_ENDPOINTS: return api_def = self._create_api_definition(endpoint) if api_def.uri in self.registered_base_handlers: # reserved handler or already registered return logging.info( f"Registering remote endpoint - " f"HTTP: ({' '.join(api_def.request_methods)}) {api_def.uri}; " f"Websocket: {', '.join(api_def.ws_methods)}") self.wsm.register_remote_handler(api_def) params: Dict[str, Any] = {} params['methods'] = api_def.request_methods params['callback'] = api_def.endpoint params['need_object_parser'] = api_def.need_object_parser self.mutable_router.add_handler(api_def.uri, DynamicRequestHandler, params) self.registered_base_handlers.append(api_def.uri) def register_local_handler(self, uri: str, request_methods: List[str], callback: Callable[[WebRequest], Coroutine], protocol: List[str] = ["http", "websocket"], wrap_result: bool = True) -> None: if uri in self.registered_base_handlers: return api_def = self._create_api_definition(uri, request_methods, is_remote=False) msg = "Registering local endpoint" if "http" in protocol: msg += f" - HTTP: ({' '.join(request_methods)}) {uri}" params: dict[str, Any] = {} params['methods'] = request_methods params['callback'] = callback params['wrap_result'] = wrap_result params['is_remote'] = False self.mutable_router.add_handler(uri, DynamicRequestHandler, params) self.registered_base_handlers.append(uri) if "websocket" in protocol: msg += f" - Websocket: {', '.join(api_def.ws_methods)}" self.wsm.register_local_handler(api_def, callback) logging.info(msg) def register_static_file_handler(self, pattern: str, file_path: str, force: bool = False) -> None: if pattern[0] != "/": pattern = "/server/files/" + pattern if os.path.isfile(file_path) or force: pattern += '()' elif os.path.isdir(file_path): if pattern[-1] != "/": pattern += "/" pattern += "(.*)" else: logging.info(f"Invalid file path: {file_path}") return logging.debug(f"Registering static file: ({pattern}) {file_path}") params = {'path': file_path} self.mutable_router.add_handler(pattern, FileRequestHandler, params) def register_upload_handler(self, pattern: str) -> None: self.mutable_router.add_handler( pattern, FileUploadHandler, {'max_upload_size': self.max_upload_size}) def remove_handler(self, endpoint: str) -> None: api_def = self.api_cache.get(endpoint) if api_def is not None: self.mutable_router.remove_handler(api_def.uri) for ws_method in api_def.ws_methods: self.wsm.remove_handler(ws_method) def _create_api_definition(self, endpoint: str, request_methods: List[str] = [], is_remote=True) -> APIDefinition: if endpoint in self.api_cache: return self.api_cache[endpoint] if endpoint[0] == '/': uri = endpoint elif is_remote: uri = "/printer/" + endpoint else: uri = "/server/" + endpoint ws_methods = [] if is_remote: # Remote requests accept both GET and POST requests. These # requests execute the same callback, thus they resolve to # only a single websocket method. ws_methods.append(uri[1:].replace('/', '.')) request_methods = ['GET', 'POST'] else: name_parts = uri[1:].split('/') if len(request_methods) > 1: for req_mthd in request_methods: func_name = req_mthd.lower() + "_" + name_parts[-1] ws_methods.append(".".join(name_parts[:-1] + [func_name])) else: ws_methods.append(".".join(name_parts)) if not is_remote and len(request_methods) != len(ws_methods): raise self.server.error( "Invalid API definition. Number of websocket methods must " "match the number of request methods") need_object_parser = endpoint.startswith("objects/") api_def = APIDefinition(endpoint, uri, ws_methods, request_methods, need_object_parser) self.api_cache[endpoint] = api_def return api_def
class MoonrakerApp: def __init__(self, server, args): self.server = server self.tornado_server = None self.api_cache = {} self.registered_base_handlers = [] # Set Up Websocket and Authorization Managers self.wsm = WebsocketManager(server) self.auth = Authorization(args.apikey) mimetypes.add_type('text/plain', '.log') mimetypes.add_type('text/plain', '.gcode') mimetypes.add_type('text/plain', '.cfg') # Set up HTTP only requests self.mutable_router = MutableRouter(self) app_handlers = [(AnyMatches(), self.mutable_router), (r"/websocket", WebSocket, { 'wsm': self.wsm, 'auth': self.auth }), (r"/api/version", EmulateOctoprintHandler, { 'server': server, 'auth': self.auth })] self.app = tornado.web.Application(app_handlers, serve_traceback=args.debug, websocket_ping_interval=10, websocket_ping_timeout=30, enable_cors=False) self.get_handler_delegate = self.app.get_handler_delegate # Register handlers self.register_static_file_handler("moonraker.log", args.logfile) self.auth.register_handlers(self) def listen(self, host, port): self.tornado_server = self.app.listen(port, address=host, max_body_size=MAX_UPLOAD_SIZE, xheaders=True) async def close(self): if self.tornado_server is not None: self.tornado_server.stop() await self.wsm.close() self.auth.close() def load_config(self, config): if 'enable_cors' in config: self.app.settings['enable_cors'] = config['enable_cors'] self.auth.load_config(config) def register_remote_handler(self, endpoint): if endpoint in RESERVED_ENDPOINTS: return api_def = self.api_cache.get(endpoint, self._create_api_definition(endpoint)) if api_def.uri in self.registered_base_handlers: # reserved handler or already registered return logging.info("Registering remote endpoint: (%s) %s" % (" ".join(api_def.request_methods), api_def.uri)) self.wsm.register_handler(api_def) params = {} params['server'] = self.server params['auth'] = self.auth params['methods'] = api_def.request_methods params['arg_parser'] = api_def.parser params['remote_callback'] = api_def.endpoint self.mutable_router.add_handler(api_def.uri, RemoteRequestHandler, params) self.registered_base_handlers.append(api_def.uri) def register_local_handler(self, uri, ws_method, request_methods, callback, http_only=False): if uri in self.registered_base_handlers: return api_def = self._create_api_definition(uri, ws_method, request_methods) logging.info("Registering local endpoint: (%s) %s" % (" ".join(request_methods), uri)) if not http_only: self.wsm.register_handler(api_def, callback) params = {} params['server'] = self.server params['auth'] = self.auth params['methods'] = request_methods params['arg_parser'] = api_def.parser params['callback'] = callback self.mutable_router.add_handler(uri, LocalRequestHandler, params) self.registered_base_handlers.append(uri) def register_static_file_handler(self, pattern, file_path, can_delete=False, op_check_cb=None): if pattern[0] != "/": pattern = "/server/files/" + pattern if os.path.isfile(file_path): pattern += '()' elif os.path.isdir(file_path): if pattern[-1] != "/": pattern += "/" pattern += "(.*)" else: logging.info("Invalid file path: %s" % (file_path)) return methods = ['GET'] if can_delete: methods.append('DELETE') params = { 'server': self.server, 'auth': self.auth, 'path': file_path, 'methods': methods, 'op_check_cb': op_check_cb } self.mutable_router.add_handler(pattern, FileRequestHandler, params) def register_upload_handler(self, pattern): params = {'server': self.server, 'auth': self.auth} self.mutable_router.add_handler(pattern, FileUploadHandler, params) def remove_handler(self, endpoint): api_def = self.api_cache.get(endpoint) if api_def is not None: self.wsm.remove_handler(api_def.uri) self.mutable_router.remove_handler(api_def.ws_method) def _create_api_definition(self, endpoint, ws_method=None, request_methods=['GET', 'POST']): if endpoint in self.api_cache: return self.api_cache[endpoint] if endpoint[0] == '/': uri = endpoint else: uri = "/printer/" + endpoint if ws_method is None: ws_method = uri[1:].replace('/', '_') if endpoint.startswith("objects/"): parser = _status_parser else: parser = _default_parser api_def = APIDefinition(endpoint, uri, ws_method, request_methods, parser) self.api_cache[endpoint] = api_def return api_def
class MoonrakerApp: def __init__(self, config): self.server = config.get_server() self.tornado_server = None self.api_cache = {} self.registered_base_handlers = [] self.max_upload_size = config.getint('max_upload_size', 1024) self.max_upload_size *= 1024 * 1024 # Set Up Websocket and Authorization Managers self.wsm = WebsocketManager(self.server) self.auth = Authorization(config['authorization']) mimetypes.add_type('text/plain', '.log') mimetypes.add_type('text/plain', '.gcode') mimetypes.add_type('text/plain', '.cfg') debug = config.getboolean('enable_debug_logging', False) log_level = logging.DEBUG if debug else logging.INFO logging.getLogger().setLevel(log_level) app_args = { 'serve_traceback': debug, 'websocket_ping_interval': 10, 'websocket_ping_timeout': 30, 'parent': self, 'default_handler_class': AuthorizedErrorHandler, 'default_handler_args': {} } if not debug: app_args['log_function'] = self.log_release_mode # Set up HTTP only requests self.mutable_router = MutableRouter(self) app_handlers = [(AnyMatches(), self.mutable_router), (r"/websocket", WebSocket)] self.app = tornado.web.Application(app_handlers, **app_args) self.get_handler_delegate = self.app.get_handler_delegate # Register handlers logfile = config['system_args'].get('logfile') if logfile: self.register_static_file_handler("moonraker.log", logfile, force=True) self.register_static_file_handler("klippy.log", DEFAULT_KLIPPY_LOG_PATH, force=True) self.auth.register_handlers(self) def listen(self, host, port): self.tornado_server = self.app.listen(port, address=host, max_body_size=MAX_BODY_SIZE, xheaders=True) def log_release_mode(self, handler): status_code = handler.get_status() if status_code in [200, 204]: # don't log OK and No Content return if status_code < 400: log_method = access_log.info elif status_code < 500: log_method = access_log.warning else: log_method = access_log.error request_time = 1000.0 * handler.request.request_time() log_method("%d %s %.2fms", status_code, handler._request_summary(), request_time) def get_server(self): return self.server def get_auth(self): return self.auth def get_websocket_manager(self): return self.wsm async def close(self): if self.tornado_server is not None: self.tornado_server.stop() await self.tornado_server.close_all_connections() await self.wsm.close() self.auth.close() def register_remote_handler(self, endpoint): if endpoint in RESERVED_ENDPOINTS: return api_def = self._create_api_definition(endpoint) if api_def.uri in self.registered_base_handlers: # reserved handler or already registered return logging.info( f"Registering remote endpoint - " f"HTTP: ({' '.join(api_def.request_methods)}) {api_def.uri}; " f"Websocket: {', '.join(api_def.ws_methods)}") self.wsm.register_remote_handler(api_def) params = {} params['methods'] = api_def.request_methods params['callback'] = api_def.endpoint params['need_object_parser'] = api_def.need_object_parser self.mutable_router.add_handler(api_def.uri, DynamicRequestHandler, params) self.registered_base_handlers.append(api_def.uri) def register_local_handler(self, uri, request_methods, callback, protocol=["http", "websocket"], wrap_result=True): if uri in self.registered_base_handlers: return api_def = self._create_api_definition(uri, request_methods, is_remote=False) msg = "Registering local endpoint" if "http" in protocol: msg += f" - HTTP: ({' '.join(request_methods)}) {uri}" params = {} params['methods'] = request_methods params['callback'] = callback params['wrap_result'] = wrap_result params['is_remote'] = False self.mutable_router.add_handler(uri, DynamicRequestHandler, params) self.registered_base_handlers.append(uri) if "websocket" in protocol: msg += f" - Websocket: {', '.join(api_def.ws_methods)}" self.wsm.register_local_handler(api_def, callback) logging.info(msg) def register_static_file_handler(self, pattern, file_path, force=False): if pattern[0] != "/": pattern = "/server/files/" + pattern if os.path.isfile(file_path) or force: pattern += '()' elif os.path.isdir(file_path): if pattern[-1] != "/": pattern += "/" pattern += "(.*)" else: logging.info(f"Invalid file path: {file_path}") return logging.debug(f"Registering static file: ({pattern}) {file_path}") params = {'path': file_path} self.mutable_router.add_handler(pattern, FileRequestHandler, params) def register_upload_handler(self, pattern): self.mutable_router.add_handler( pattern, FileUploadHandler, {'max_upload_size': self.max_upload_size}) def remove_handler(self, endpoint): api_def = self.api_cache.get(endpoint) if api_def is not None: self.wsm.remove_handler(api_def.uri) self.mutable_router.remove_handler(api_def.ws_method) def _create_api_definition(self, endpoint, request_methods=[], is_remote=True): if endpoint in self.api_cache: return self.api_cache[endpoint] if endpoint[0] == '/': uri = endpoint elif is_remote: uri = "/printer/" + endpoint else: uri = "/server/" + endpoint ws_methods = [] if is_remote: # Remote requests accept both GET and POST requests. These # requests execute the same callback, thus they resolve to # only a single websocket method. ws_methods.append(uri[1:].replace('/', '.')) request_methods = ['GET', 'POST'] else: name_parts = uri[1:].split('/') if len(request_methods) > 1: for req_mthd in request_methods: func_name = req_mthd.lower() + "_" + name_parts[-1] ws_methods.append(".".join(name_parts[:-1] + [func_name])) else: ws_methods.append(".".join(name_parts)) if not is_remote and len(request_methods) != len(ws_methods): raise self.server.error( "Invalid API definition. Number of websocket methods must " "match the number of request methods") need_object_parser = endpoint.startswith("objects/") api_def = APIDefinition(endpoint, uri, ws_methods, request_methods, need_object_parser) self.api_cache[endpoint] = api_def return api_def
def __init__(self, config: ConfigHelper) -> None: self.server = config.get_server() self.http_server: Optional[HTTPServer] = None self.secure_server: Optional[HTTPServer] = None self.api_cache: Dict[str, APIDefinition] = {} self.registered_base_handlers: List[str] = [] self.max_upload_size = config.getint('max_upload_size', 1024) self.max_upload_size *= 1024 * 1024 # SSL config self.cert_path: str = self._get_path_option( config, 'ssl_certificate_path') self.key_path: str = self._get_path_option( config, 'ssl_key_path') # Set Up Websocket and Authorization Managers self.wsm = WebsocketManager(self.server) self.internal_transport = InternalTransport(self.server) self.api_transports: Dict[str, APITransport] = { "websocket": self.wsm, "internal": self.internal_transport } mimetypes.add_type('text/plain', '.log') mimetypes.add_type('text/plain', '.gcode') mimetypes.add_type('text/plain', '.cfg') self.debug = self.server.is_debug_enabled() app_args: Dict[str, Any] = { 'serve_traceback': self.debug, 'websocket_ping_interval': 10, 'websocket_ping_timeout': 30, 'server': self.server, 'default_handler_class': AuthorizedErrorHandler, 'default_handler_args': {}, 'log_function': self.log_request, 'compiled_template_cache': False, } # Set up HTTP only requests self.mutable_router = MutableRouter(self) app_handlers: List[Any] = [ (AnyMatches(), self.mutable_router), (r"/", WelcomeHandler), (r"/websocket", WebSocket), (r"/server/redirect", RedirectHandler) ] self.app = tornado.web.Application(app_handlers, **app_args) self.get_handler_delegate = self.app.get_handler_delegate # Register handlers logfile = self.server.get_app_args().get('log_file') if logfile: self.register_static_file_handler( "moonraker.log", logfile, force=True) self.register_static_file_handler( "klippy.log", DEFAULT_KLIPPY_LOG_PATH, force=True) self.register_upload_handler("/server/files/upload") # Register Server Components self.server.register_component("application", self) self.server.register_component("websockets", self.wsm) self.server.register_component("internal_transport", self.internal_transport)