def start(self): self.log.debug("ZuulWeb starting") self.stream_manager.start() self.wsplugin = WebSocketPlugin(cherrypy.engine) self.wsplugin.subscribe() cherrypy.engine.start()
if __name__ == "__main__": parser = argparse.ArgumentParser( description= 'HTTP proxy between two clients using websockets. To connect the target, visit http://domain:targetport/runproxy or include http://domain:targetport/proxy.js' ) parser.add_argument('--targetport', default='18082', type=int) parser.add_argument('--proxyport', default='18083', type=int) args = parser.parse_args() cherrypy.config.update({ 'server.socket_host': '0.0.0.0', 'server.socket_port': args.targetport }) WebSocketPlugin(cherrypy.engine).subscribe() cherrypy.tools.websocket = WebSocketTool() cherrypy.tree.mount(Root(), '/', config={ '/ws': { 'tools.websocket.on': True, 'tools.websocket.handler_cls': ProxyWebSocket } }) httpd = BaseHTTPServer.HTTPServer(('', args.proxyport), ProxyHandler) cherrypy.engine.start() try:
def _setup_websocket_plugin(self): WebSocketPlugin(cherrypy.engine).subscribe() cherrypy.tools.websocket = WebSocketTool()
def run(): MEDIA_DIR = os.path.join(DATADIR, 'Pellmonweb', 'media') argparser = argparse.ArgumentParser(prog='pellmonweb') argparser.add_argument('-D', '--DAEMONIZE', action='store_true', help='Run as daemon') argparser.add_argument('-P', '--PIDFILE', default='/tmp/pellmonweb.pid', help='Full path to pidfile') argparser.add_argument('-U', '--USER', help='Run as USER') argparser.add_argument('-G', '--GROUP', default='nogroup', help='Run as GROUP') argparser.add_argument('-C', '--CONFIG', default='pellmon.conf', help='Full path to config file') argparser.add_argument('-d', '--DBUS', default='SESSION', choices=['SESSION', 'SYSTEM'], help='which bus to use, SESSION is default') argparser.add_argument('-V', '--version', action='version', version='%(prog)s version ' + __version__) args = argparser.parse_args() global dbus dbus = Dbus_handler(args.DBUS) #Look for temlates in this directory global lookup lookup = myLookup( directories=[os.path.join(DATADIR, 'Pellmonweb', 'html')], dbus=dbus) config_file = args.CONFIG pidfile = args.PIDFILE if pidfile: plugins.PIDFile(cherrypy.engine, pidfile).subscribe() if args.USER: config_file = os.path.join(CONFDIR, 'pellmon.conf') try: parser.read(config_file) except: cherrypy.log("can not parse config file") sys.exit(1) try: config_dir = parser.get('conf', 'config_dir') walk_config_dir(config_dir, parser) except ConfigParser.NoOptionError: pass try: accesslog = parser.get('weblog', 'accesslog') logdir = os.path.dirname(accesslog) if not os.path.isdir(logdir): os.mkdir(logdir) uid = pwd.getpwnam(args.USER).pw_uid gid = grp.getgrnam(args.GROUP).gr_gid os.chown(logdir, uid, gid) if os.path.isfile(accesslog): os.chown(accesslog, uid, gid) except: pass try: errorlog = parser.get('weblog', 'errorlog') logdir = os.path.dirname(errorlog) if not os.path.isdir(logdir): os.mkdir(logdir) uid = pwd.getpwnam(args.USER).pw_uid gid = grp.getgrnam(args.GROUP).gr_gid os.chown(logdir, uid, gid) if os.path.isfile(errorlog): os.chown(errorlog, uid, gid) except: pass uid = pwd.getpwnam(args.USER).pw_uid gid = grp.getgrnam(args.GROUP).gr_gid plugins.DropPrivileges(cherrypy.engine, uid=uid, gid=gid, umask=033).subscribe() # Load the configuration file try: parser.read(config_file) config_dir = parser.get('conf', 'config_dir') walk_config_dir(config_dir, parser) except ConfigParser.NoOptionError: pass except ConfigParser.NoSectionError: cherrypy.log("can not parse config file") except: cherrypy.log("Config file not found") # The RRD database, updated by pellMon global polling, db try: polling = True db = parser.get('conf', 'database') graph_file = os.path.join(os.path.dirname(db), 'graph.png') except: polling = False db = '' # the colors to use when drawing the graph global colorsDict try: colors = parser.items('graphcolors') colorsDict = {} for key, value in colors: colorsDict[key] = value except: colorsDict = {} # Get the names of the polled data global polldata try: polldata = parser.items("pollvalues") # Get the names of the polled data rrd_ds_names = parser.items("rrd_ds_names") ds_names = {} for key, value in rrd_ds_names: ds_names[key] = value except: ds_names = {} polldata = [] try: # Get the optional scales scales = parser.items("scaling") scale_data = {} for key, value in scales: scale_data[key] = value except: scale_data = {} global graph_lines graph_lines = [] global logtick logtick = None for key, value in polldata: if key in colorsDict and key in ds_names: graph_lines.append({ 'name': value, 'color': colorsDict[key], 'ds_name': ds_names[key] }) if key in scale_data: graph_lines[-1]['scale'] = scale_data[key] if value == '_logtick' and key in ds_names: logtick = ds_names[key] global credentials try: credentials = parser.items('authentication') except: credentials = [('testuser', '12345')] global logfile try: logfile = parser.get('conf', 'logfile') except: logfile = None try: webroot = parser.get('conf', 'webroot') except: webroot = '/' global system_image try: system_image = os.path.join(os.path.join(MEDIA_DIR, 'img'), parser.get('conf', 'system_image')) except: system_image = os.path.join(MEDIA_DIR, 'img/system.svg') global frontpage_widgets frontpage_widgets = [] try: for row, widgets in parser.items('frontpage_widgets'): frontpage_widgets.append([s.strip() for s in widgets.split(',')]) except ConfigParser.NoSectionError: frontpage_widgets = [['systemimage', 'events'], ['graph'], ['consumption7d', 'silolevel']] global timeChoices timeChoices = ['time1h', 'time3h', 'time8h', 'time24h', 'time3d', 'time1w'] global timeNames timeNames = [ t.replace(' ', ' ') for t in ['1 hour', '3 hours', '8 hours', '24 hours', '3 days', '1 week'] ] global timeSeconds timeSeconds = [ 3600, 3600 * 3, 3600 * 8, 3600 * 24, 3600 * 24 * 3, 3600 * 24 * 7 ] ft = False fc = False for a, b in polldata: if b == 'feeder_capacity': fc = True if b == 'feeder_time': ft = True if fc and ft: consumption_graph = True consumption_file = os.path.join(os.path.dirname(db), 'consumption.png') else: consumption_graph = False if websockets: #make sure WebSocketPlugin runs after daemonizer plugin (priority 65) #see cherrypy plugin documentation for default plugin priorities WebSocketPlugin.start.__func__.priority = 66 WebSocketPlugin(cherrypy.engine).subscribe() cherrypy.tools.websocket = WebSocketTool() try: port = int(parser.get('conf', 'port')) except: port = 8081 global_conf = { 'global': { #w'server.environment': 'debug', 'tools.sessions.on' : True, 'tools.sessions.timeout': 7200, 'tools.auth.on': True, 'server.socket_host': '0.0.0.0', 'server.socket_port': port, #'engine.autoreload.on': False, #'checker.on': False, #'tools.log_headers.on': False, #'request.show_tracebacks': False, 'request.show_mismatched_params': False, #'log.screen': False, 'engine.SIGHUP': None, 'engine.SIGTERM': None, } } app_conf = { '/media': { 'tools.staticdir.on': True, 'tools.staticdir.dir': MEDIA_DIR }, } if websockets: ws_conf = { '/ws': { 'tools.websocket.on': True, 'tools.websocket.handler_cls': WebSocket } } current_dir = os.path.dirname(os.path.abspath(__file__)) cherrypy.config.update(global_conf) # Only daemonize if asked to. if args.DAEMONIZE: # Don't print anything to stdout/sterr. cherrypy.config.update({ 'log.screen': False, 'engine.autoreload.on': False }) plugins.Daemonizer(cherrypy.engine).subscribe() cherrypy.tree.mount(PellMonWeb(), webroot, config=app_conf) if websockets: cherrypy.tree.mount(WsHandler(), os.path.join(webroot, 'websocket'), config=ws_conf) try: cherrypy.config.update({'log.access_file': accesslog}) except: pass try: cherrypy.config.update({'log.error_file': errorlog}) except: pass GObject.threads_init() # Always start the engine; this will start all other services try: cherrypy.engine.start() except: # Assume the error has been logged already via bus.log. sys.exit(1) else: # Needed to be able to use threads with a glib main loop running # A main loop is needed for dbus "name watching" to work main_loop = GLib.MainLoop() # cherrypy has it's own mainloop, cherrypy.engine.block, that # regularly calls engine.publish every 100ms. The most reliable # way to run dbus and cherrypy together seems to be to use the # glib mainloop for both, ie call engine.publish from the glib # mainloop instead of calling engine.block. def publish(): try: cherrypy.engine.publish('main') if cherrypy.engine.execv: main_loop.quit() cherrypy.engine._do_execv() except KeyboardInterrupt: pass return True # Use our own signal handler to stop on ctrl-c, seems to be simpler # than subscribing to cherrypy's signal handler def signal_handler(signal, frame): cherrypy.engine.exit() main_loop.quit() signal.signal(signal.SIGINT, signal_handler) # Handle cherrypy's main loop needs from here GLib.timeout_add(100, publish) dbus.start() try: main_loop.run() except KeyboardInterrupt: pass
def run(self, host="127.0.0.1", port=8000, dir='.', mode=0, csiDevice=-1): dir = os.path.abspath(dir) Path(dir).mkdir(parents=True, exist_ok=True) CP_CONF = { '/vendor': { 'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.abspath('./vendor') }, '/css': { 'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.abspath('./css') }, '/webfonts': { 'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.abspath('./webfonts') }, '/ws': { 'tools.websocket.on': True, 'tools.websocket.handler_cls': WebSocketHandler } } accessLogFile = os.path.join(os.getcwd(), "access.log") errorLogFile = os.path.join(os.getcwd(), "error.log") cherrypy.config.update({ 'server.socket_host': host, 'server.socket_port': port, 'engine.autoreload.on': False, 'log.error_file': errorLogFile, 'log.access_file': accessLogFile }) cherrypy.log("Recording to: " + dir) zedStatus = False if csiDevice == -1: csiDevice, zedStatus = selfTest() else: _, zedStatus = selfTest() csiStatus = True if csiDevice != -1 else False csiStreamer = CSIStreamer(dir, params["csiStreamer"]["recordingInterval"], csiDevice, params["csiStreamer"]["stdResolution"], params["csiStreamer"]["hdResolution"], params["csiStreamer"]["recordingResolution"], params["csiStreamer"]["framerate"]) # threading.Thread(None, csiStreamer.run).start() zedStreamer = None if ZED_ENABLED: zedFrameLock = threading.Lock() zedStreamer = ZEDStreamer( dir, params["zedStreamer"]["recordingInterval"], params["zedStreamer"]["resolution"], params["zedStreamer"]["depth"], params["zedStreamer"]["framerate"]) zedStreamThread = threading.Thread(None, zedStreamer.run, daemon=True) zedStreamThread.start() WebSocketPlugin(cherrypy.engine).subscribe() cherrypy.tools.websocket = WebSocketTool() cherrypy.tree.mount(RecordingHandler( dir, csiStreamer, zedStreamer, csiStatus, zedStatus, mode, params["recordingHandler"]["previewResolution"], params["recordingHandler"]["zedPreviewResolution"]), '/', config=CP_CONF) if mode == 0: cherrypy.log("All modules enabled") cherrypy.tree.mount(BarcodeHandler( dir, params["barcodeHandler"]["crop"], params["barcodeHandler"]["timeout"], params["barcodeHandler"]["previewResolution"], params["barcodeHandler"]["recordingResolution"]), '/barcode', config=CP_CONF) cherrypy.tree.mount(DetectionHandler( dir, params["detectionHandler"]["framerate"], params["detectionHandler"]["recordingResolution"], params["detectionHandler"]["enginepath"], params["detectionHandler"]["H"], params["detectionHandler"]["L0"]), '/detection', config=CP_CONF) else: cherrypy.log("Barcode detection and object detection disabled.") cherrypy.tree.mount(DisabledHandler(), '/barcode', config=CP_CONF) cherrypy.tree.mount(DisabledHandler(), '/detection', config=CP_CONF) cherrypy.tree.mount(FilesHandler(dir), '/files', config=CP_CONF) cherrypy.tree.mount(TestHandler(), '/test') cherrypy.tree.mount(DocuHandler(), '/documentation', config=CP_CONF) cherrypy.engine.start() cherrypy.engine.block()
def start(self): config = { 'global': { "engine.autoreload.on":False, 'server.socket_host': '0.0.0.0', 'server.socket_port': self.httpPort, 'server.show_tracebacks': False, 'request.show_tracebacks': False, 'tools.sessions.on': True, } } if self.certs: config['global'].update({ 'server.ssl_module': 'builtin', 'server.ssl_certificate':self.certs.cert, 'server.ssl_private_key':self.certs.key, 'server.ssl_certificate_chain':self.certs.chain }) cherrypy.config.update(config) cherrypy.tools.websocket = WebSocketTool() logging.info("STARTING HTTP SERVER") current_dir = os.path.dirname(__file__) path_to_source_root = os.path.abspath(os.path.join(current_dir, "..", "..")) temp_dir_for_tarball = tempfile.mkdtemp() logging.info("Serving test-looper tarball and related downloads from %s", temp_dir_for_tarball) SubprocessRunner.callAndAssertSuccess( ["tar", "cvfz", os.path.join(temp_dir_for_tarball, "test_looper.tar.gz"), "--directory", path_to_source_root, "test_looper" ]) if not self.linuxOnly: with DirectoryScope.DirectoryScope(path_to_source_root): SubprocessRunner.callAndAssertSuccess( ["zip", "-r", os.path.join(temp_dir_for_tarball, "test_looper.zip"), "test_looper", "-x", "*.pyc", "*.js"] ) with DirectoryScope.DirectoryScope(temp_dir_for_tarball): SubprocessRunner.callAndReturnOutput( ["curl", "-L", "https://bootstrap.pypa.io/get-pip.py", "-O", os.path.join(temp_dir_for_tarball, "get-pip.py")] ) assert os.path.exists(os.path.join(temp_dir_for_tarball, "get-pip.py")) with DirectoryScope.DirectoryScope(temp_dir_for_tarball): SubprocessRunner.callAndReturnOutput( ["curl", "-L", "http://www.python.org/ftp/python/2.7.14/python-2.7.14.amd64.msi", "-O", os.path.join(temp_dir_for_tarball, "python-2.7.14.amd64.msi")] ) assert os.path.exists(os.path.join(temp_dir_for_tarball, "python-2.7.14.amd64.msi")) with DirectoryScope.DirectoryScope(temp_dir_for_tarball): SubprocessRunner.callAndReturnOutput( ["curl", "-L", "https://github.com/git-for-windows/git/releases/download/v2.15.1.windows.2/Git-2.15.1.2-64-bit.exe", "-O", os.path.join(temp_dir_for_tarball, "Git-2.15.1.2-64-bit.exe")] ) assert os.path.exists(os.path.join(temp_dir_for_tarball, "Git-2.15.1.2-64-bit.exe")) cherrypy.tree.mount(self, '/', { '/favicon.ico': { 'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(current_dir, 'content', 'favicon.ico') }, '/get-pip.py': { 'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(temp_dir_for_tarball, 'get-pip.py') }, '/test_looper.tar.gz': { 'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(temp_dir_for_tarball, 'test_looper.tar.gz') }, '/test_looper.zip': { 'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(temp_dir_for_tarball, 'test_looper.zip') }, '/test_looper.zip': { 'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(temp_dir_for_tarball, 'test_looper.zip') }, '/python-2.7.14.amd64.msi': { 'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(temp_dir_for_tarball, 'python-2.7.14.amd64.msi') }, '/Git-2.15.1.2-64-bit.exe': { 'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(temp_dir_for_tarball, 'Git-2.15.1.2-64-bit.exe') }, '/css': { 'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(current_dir, 'css') }, '/js': { 'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(current_dir, 'content', 'js') }, '/interactive_socket': { 'tools.websocket.on': True, 'tools.websocket.handler_cls': MakeWebsocketHandler(self), 'tools.websocket.protocols': ['protocol'] } }) cherrypy.server.socket_port = self.httpPort cherrypy.engine.autoreload.on = False cherrypy.engine.signals.subscribe() WebSocketPlugin(cherrypy.engine).subscribe() cherrypy.engine.start()
def webRoot(): # We don't want Cherrypy writing temp files for no reason cherrypy._cpreqbody.Part.maxrambytes = 64 * 1024 from cherrypy import _cperror logging.getLogger("cherrypy.access").propagate = False from . import tagpoints from . import builtintags def tagErrorHandler(tag, f, val): try: from . import newevt if f.__module__ in newevt.eventsByModuleName: newevt.eventsByModuleName[f.__module__]._handle_exception() else: if not hasattr(f, "_kaithemFirstErrorMarker"): f._kaithemFirstErrorMarker = True messagebus.postMessage( "/system/notifications/errors", "First err in tag subscriber " + str(f) + " from " + str(f.__module__) + " to " + tag.name) except: print(traceback.format_exc(chain=True)) tagpoints.subscriberErrorHandlers = [tagErrorHandler] tagpoints.loadAllConfiguredTags(os.path.join(directories.vardir, "tags")) # We want a notification anytime every first error in a scheduled event. # This can stay even with real python logging, we want the front page notificaton. from . import scheduling def handleFirstError(f): "Callback to deal with the first error from any given event" m = f.__module__ messagebus.postMessage( "/system/notifications/errors", "Problem in scheduled event function: " + repr(f) + " in module: " + m + ", check logs for more info.") scheduling.handleFirstError = handleFirstError from . import logviewer try: from . import timesync except: logger.exception("Could not start time sync module") messagebus.postMessage( '/system/notifications/errors', """Failed to initialize the time sync module or zeroconf discovery This may be because you are using a python version older than 3.3, or because netifaces is not installed. Some features may not work correctly. """) from . import pages from . import weblogin from . import pages from . import ManageUsers from . import newevt from . import registry from . import persist persist.registry = registry from . import modules from . import modules_interface from . import settings from . import usrpages from . import systasks from . import widgets from . import alerts logger.info("Loaded core python code") from . import config as cfgmodule if not config['host'] == 'default': bindto = config['host'] else: if config['local-access-only']: bindto = '127.0.0.1' else: bindto = '::' mode = int( cfgmodule.argcmd.nosecurity) if cfgmodule.argcmd.nosecurity else None # limit nosecurity to localhost if mode == 1: bindto = '127.0.0.1' #cherrypy.process.servers.check_port(bindto, config['http-port'], timeout=1.0) #cherrypy.process.servers.check_port(bindto, config['https-port'], timeout=1.0) logger.info("Ports are free") MyExternalIPAdress = util.updateIP() if config['change-process-title']: try: import setproctitle setproctitle.setproctitle("kaithem") logger.info("setting process title") except: logger.warning("error setting process title") from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool from ws4py.websocket import EchoWebSocket, WebSocket WebSocketPlugin(cherrypy.engine).subscribe() cherrypy.tools.websocket = WebSocketTool() logger.info("activated websockets") sys.modules['kaithem'] = sys.modules['__main__'] # Load all modules from the active modules directory modules.initModules() logger.info("Loaded modules") def save(): if config['save-before-shutdown']: messagebus.postMessage('/system/notifications/important/', "System saving before shutting down") util.SaveAllState() # let the user choose to have the server save everything before a shutdown if config['save-before-shutdown']: atexit.register(save) cherrypy.engine.subscribe("exit", save) import collections # Super simple hacky cache. Maybe we should # Just mostly eliminate zips and use files directly? zipcache = collections.OrderedDict() # This class represents the "/" root of the web app class webapproot(): # This lets users mount stuff at arbitrary points, so long # As it doesn't conflict with anything. # foo.bar.com/foo maps to foo,bar,/,foo # bar.com/foo is just foo def _cp_dispatch(self, vpath): sdpath = pages.getSubdomain() vpath2 = vpath[:] # For binding the root of subdomains while vpath2: # Check for any subdomain specific handling. if tuple(sdpath + ['/'] + vpath2) in pages.nativeHandlers: # found match, remove N elements from the beginning of the path, # where n is the length of the "mountpoint", becsause the mountpoint # already consumed those. # Don't do it for the fake one we add just to make this loop work though for i in vpath2: vpath.pop(0) x = pages.nativeHandlers[tuple(sdpath + ['/'] + vpath2)] # Traverse to the actual function, if there is a match, else return the index. if vpath and hasattr(x, vpath[0]): x2 = getattr(x, vpath[0]) if hasattr(x2, 'exposed') and x2.exposed: vpath.pop(0) x = x2 if not isinstance(x, Exception): return x else: raise x if tuple(vpath2) in pages.nativeHandlers: # found match, remove N elements from the beginning of the path, # where n is the length of the "mountpoint", because the mountpoint # already consumed those for i in range(len(vpath2)): vpath.pop(0) x = pages.nativeHandlers[tuple(vpath2)] if vpath and hasattr(x, vpath[0]): x2 = getattr(x, vpath[0]) if vpath and hasattr(x2, 'exposed') and x2.exposed: vpath.pop(0) x = x2 if not isinstance(x, Exception): return x else: raise x if None in pages.nativeHandlers: return pages.nativeHandlers[None] # Successively remove things from the end till we get a # prefix match vpath2.pop(-1) return None @cherrypy.expose def default(self, *path, **data): return self._cp_dispatch(list(path))(*path, **data) # Keep the dispatcher from freaking out. The actual handling # Is done by a cherrypy tool. These just keeo cp_dispatch from being called # I have NO clue why the favicon doesn't have this issue. @cherrypy.expose def static(self, *path, **data): pass @cherrypy.expose def usr(self, *path, **data): pass @cherrypy.expose def index(self, *path, **data): pages.require("/admin/mainpage.view") cherrypy.response.cookie['LastSawMainPage'] = time.time() return pages.get_template('index.html').render( api=notifications.api, alertsapi=alerts.api) @cherrypy.expose def dropdownpanel(self, *path, **data): pages.require("/admin/mainpage.view") return pages.get_template('dropdownpanel.html').render( api=notifications.api, alertsapi=alerts.api) # @cherrypy.expose # def alerts(self, *path, **data): # pages.require("/admin/mainpage.view") # return pages.get_template('alerts.html').render(api=notifications.api, alertsapi=alerts.api) @cherrypy.expose def tagpoints(self, *path, show_advanced='', **data): # This page could be slow because of the db stuff, so we restrict it more pages.require("/admin/settings.edit") if "new_numtag" in data: pages.postOnly() return pages.get_template('settings/tagpoint.html').render( new_numtag=data['new_numtag'], tagname=data['new_numtag'], show_advanced=True) if "new_strtag" in data: pages.postOnly() return pages.get_template('settings/tagpoint.html').render( new_strtag=data['new_strtag'], tagname=data['new_strtag'], show_advanced=True) if data: pages.postOnly() if path: if not path[0] in tagpoints.allTags: raise ValueError("This tag does not exist") return pages.get_template('settings/tagpoint.html').render( tagName=path[0], data=data, show_advanced=show_advanced) else: return pages.get_template('settings/tagpoints.html').render( data=data) @cherrypy.expose def tagpointlog(self, *path, **data): # This page could be slow because of the db stuff, so we restrict it more pages.require("/admin/settings.edit") pages.postOnly() if not 'exportRows' in data: return pages.get_template('settings/tagpointlog.html').render( tagName=path[0], data=data) else: import pytz import datetime import dateutil.parser for i in tagpoints.allTags[path[0]]().configLoggers: if i.accumType == data['exportType']: tz = pytz.timezone( auth.getUserSetting(pages.getAcessingUser(), 'timezone')) logtime = tz.localize( dateutil.parser.parse( data['logtime'])).timestamp() raw = i.getDataRange(logtime, time.time() + 10000000, int(data['exportRows'])) if data['exportFormat'] == "csv.iso": cherrypy.response.headers[ 'Content-Disposition'] = 'attachment; filename="%s"' % path[ 0].replace( "/", "_").replace(".", "_").replace( ":", "_")[1:] + "_" + data[ 'exportType'] + tz.localize( dateutil.parser.parse( data['logtime']) ).isoformat() + ".csv" cherrypy.response.headers[ 'Content-Type'] = 'text/csv' d = [ "Time(ISO), " + path[0].replace(",", '') + ' <accum ' + data['exportType'] + '>' ] for i in raw: dt = datetime.datetime.fromtimestamp(i[0]) d.append(dt.isoformat() + "," + str(i[1])[:128]) return '\r\n'.join(d) + '\r\n' @cherrypy.expose def zipstatic(self, *path, **data): """ take everything but the last path element, use it as a path relative to static dir open as a zip, use the last as filename in the zip, return it. """ if ".." in path: return try: if path in zipcache: zipcache.move_to_end(path) return zipcache[path] except: print("err in cache for zip") cherrypy.response.headers['Cache-Control'] = "max-age=28800" m = mimetypes.guess_type(path[-1]) cherrypy.response.headers['Content-Type'] = m[0] p = os.path.join(ddn, 'static', *path[:-1]) with zipfile.ZipFile(p) as f: d = f.read(path[-1]) zipcache[path] = d if len(zipcache) > 64: zipcache.pop(last=False) return d @cherrypy.expose def pagelisting(self, *path, **data): # Pagelisting knows to only show pages if you have permissions return pages.get_template('pagelisting.html').render_unicode( modules=modules.ActiveModules) # docs, helpmenu, and license are just static pages. @cherrypy.expose def docs(self, *path, **data): if path: if path[0] == "thirdparty": p = os.path.normpath( os.path.join(directories.srcdir, "docs", "/".join(path))) if not p.startswith( os.path.join(directories.srcdir, "docs")): raise RuntimeError("Invalid URL") cherrypy.response.headers[ 'Content-Type'] = mimetypes.guess_type(p)[0] with open(p, "rb") as f: return (f.read()) return pages.get_template('help/' + path[0] + '.html').render( path=path, data=data) return pages.get_template('help/help.html').render() @cherrypy.expose def makohelp(self, *path, **data): return pages.get_template('help/makoreference.html').render() @cherrypy.expose def about(self, *path, **data): return pages.get_template('help/about.html').render( myip=MyExternalIPAdress) @cherrypy.expose def changelog(self, *path, **data): return pages.get_template('help/changes.html').render( myip=MyExternalIPAdress) @cherrypy.expose def helpmenu(self, *path, **data): return pages.get_template('help/index.html').render() @cherrypy.expose def license(self, *path, **data): return pages.get_template('help/license.html').render() @cherrypy.expose def aerolabs_blockrain(self, *path, **data): # There is no reason to be particularly concerned here, I have no reason not to trust # Aerolabs, this is just for the people that hate hidden games and such. cherrypy.response.headers[ 'Content-Security-Policy'] = "connect-src none" return pages.get_template('blockrain.html').render() class Errors(): @cherrypy.expose def permissionerror(self, ): cherrypy.response.status = 403 return pages.get_template('errors/permissionerror.html').render() @cherrypy.expose def alreadyexists(self, ): cherrypy.response.status = 400 return pages.get_template('errors/alreadyexists.html').render() @cherrypy.expose def gosecure(self, ): cherrypy.response.status = 426 return pages.get_template('errors/gosecure.html').render() @cherrypy.expose def loginerror(self, ): cherrypy.response.status = 400 return pages.get_template('errors/loginerror.html').render() @cherrypy.expose def nofoldermoveerror(self, ): cherrypy.response.status = 400 return pages.get_template('errors/nofoldermove.html').render() @cherrypy.expose def wrongmethod(self, ): cherrypy.response.status = 405 return pages.get_template('errors/wrongmethod.html').render() @cherrypy.expose def error(self, ): cherrypy.response.status = 500 return pages.get_template('errors/error.html').render( info="An Error Occurred") def cpexception(): cherrypy.response.status = 500 try: cherrypy.response.body = bytes( pages.get_template('errors/cperror.html').render( e=_cperror.format_exc(), mk=mako.exceptions.html_error_template().render().decode( )), 'utf8') except: cherrypy.response.body = bytes( pages.get_template('errors/cperror.html').render( e=_cperror.format_exc(), mk=""), 'utf8') import zipfile from . import devices, btadmin # There are lots of other objects ad classes represeting subfolders of the website so we attatch them root = webapproot() root.login = weblogin.LoginScreen() root.auth = ManageUsers.ManageAuthorization() root.modules = modules_interface.WebInterface() root.settings = settings.Settings() root.settings.bt = btadmin.WebUI() root.errors = Errors() root.pages = usrpages.KaithemPage() root.logs = messagelogging.WebInterface() root.notifications = notifications.WI() root.widgets = widgets.WebInterface() root.syslog = logviewer.WebInterface() root.devices = devices.WebDevices() if not os.path.abspath(__file__).startswith("/usr/bin"): sdn = os.path.join( os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "src") ddn = os.path.join( os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "data") else: sdn = "/usr/lib/kaithem/src" ddn = "/usr/share/kaithem" def allow_upload(*args, **kwargs): # Only do the callback if needed. Assume it's really big if no header. if int(cherrypy.request.headers.get( "Content-Length", 2**32)) > cherrypy.request.body.maxbytes: cherrypy.request.body.maxbytes = cherrypy.request.config[ 'tools.allow_upload.f']() cherrypy.tools.allow_upload = cherrypy.Tool('before_request_body', allow_upload) site_config = { "request.body.maxbytes": 64 * 1024, "tools.encode.on": True, "tools.encode.encoding": 'utf-8', "tools.decode.on": True, "tools.decode.encoding": 'utf-8', 'request.error_response': cpexception, 'log.screen': config['cherrypy-log-stdout'], 'server.socket_host': bindto, 'server.socket_port': config['https-port'], 'server.ssl_module': 'builtin', 'server.ssl_certificate': os.path.join(directories.ssldir, 'certificate.cert'), 'server.ssl_private_key': os.path.join(directories.ssldir, 'certificate.key'), 'server.thread_pool': config['https-thread-pool'], 'engine.autoreload.frequency': 5, 'engine.autoreload.on': False, 'tools.allow_upload.on': True, 'tools.allow_upload.f': lambda: auth.getUserLimit(pages.getAcessingUser(), "web.maxbytes") or 64 * 1024, } wscfg = { 'tools.websocket.on': True, 'tools.websocket.handler_cls': widgets.websocket } wscfg_raw = { 'tools.websocket.on': True, 'tools.websocket.handler_cls': widgets.rawwebsocket } try: from hardline import ws4py_drayer wscfg3 = { 'tools.websocket.on': True, 'tools.websocket.handler_cls': ws4py_drayer.DrayerAPIWebSocket } root.drayer_api = ws4py_drayer.WebInterface() except Exception as e: wscfg3 = {} logging.exception("Could not load the Drayer WS API") messagebus.postMessage( "/system/notifications/errors", "Drayer Server API disabled due to loading error, see logs") cnf = { '/static': { 'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(ddn, 'static'), "tools.sessions.on": False, "tools.addheader.on": True, 'tools.expires.on': True, 'tools.expires.secs': 3600 + 48 # expire in 48 hours }, '/static/js': { 'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(sdn, 'js'), "tools.sessions.on": False, "tools.addheader.on": True }, '/static/vue': { 'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(sdn, 'vue'), "tools.sessions.on": False, "tools.addheader.on": True }, '/static/css': { 'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(sdn, 'css'), "tools.sessions.on": False, "tools.addheader.on": True }, '/static/docs': { 'tools.staticdir.on': True, 'tools.staticdir.dir': os.path.join(sdn, 'docs'), "tools.sessions.on": False, "tools.addheader.on": True }, '/static/zip': { 'request.dispatch': cherrypy.dispatch.MethodDispatcher(), "tools.addheader.on": True }, '/pages': { 'tools.allow_upload.on': True, 'tools.allow_upload.f': lambda: auth.getUserLimit(pages.getAcessingUser(), "web.maxbytes") or 64 * 1024, 'request.dispatch': cherrypy.dispatch.MethodDispatcher() }, '/widgets/ws': wscfg, '/widgets/wsraw': wscfg_raw, '/drayer_api': wscfg3 } if not config['favicon-png'] == "default": cnf['/favicon.png'] = { 'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(directories.datadir, "static", config['favicon-png']), 'tools.expires.on': True, 'tools.expires.secs': 3600 # expire in an hour } if not config['favicon-ico'] == "default": cnf['/favicon.ico'] = { 'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(directories.datadir, "static", config['favicon-ico']), 'tools.expires.on': True, 'tools.expires.secs': 3600 # expire in an hour } # Let the user create additional static directories for i in config['serve-static']: if i not in cnf: cnf["/usr/static/" + i] = { 'tools.staticdir.on': True, 'tools.staticdir.dir': config['serve-static'][i], "tools.sessions.on": False, "tools.addheader.on": True } def addheader(*args, **kwargs): "This function's only purpose is to tell the browser to cache requests for an hour" cherrypy.response.headers['Cache-Control'] = "max-age=28800" cherrypy.response.headers["Access-Control-Allow-Origin"] = "*" #del cherrypy.response.headers['Expires'] def pageloadnotify(*args, **kwargs): systasks.aPageJustLoaded() # As far as I can tell, this second server inherits everything from the "implicit" server # except what we override. server2 = cherrypy._cpserver.Server() server2.socket_port = config['http-port'] server2._socket_host = bindto server2.thread_pool = config['http-thread-pool'] server2.subscribe() cherrypy.config.update(site_config) cherrypy.tools.pageloadnotify = cherrypy.Tool('on_start_resource', pageloadnotify) cherrypy.config['tools.pageloadnotify.on'] = True cherrypy.tools.addheader = cherrypy.Tool('before_finalize', addheader) if hasattr(cherrypy.engine, 'signal_handler'): del cherrypy.engine.signal_handler.handlers['SIGUSR1'] cherrypy.engine.signal_handler.subscribe() cherrypy.tree.mount(root, config=cnf) if time.time() < 1420070400: messagebus.postMessage( '/system/notifications/errors', "System Clock is wrong, some features may not work properly.") if time.time() < util.min_time: messagebus.postMessage( '/system/notifications/errors', "System Clock may be wrong, or time has been set backwards at some point. If system clock is correct and this error does not go away, you can fix it manually be correcting folder name timestamps in the var dir." ) cherrypy.engine.start() # Unlike other shm stuff that only gets used after startup, this # Can be used both before and after we are fully loaded. # So we need to hand off everything to the user we will actually run as. # This is also useful for when someone directly modifies config # Over SSH and we want to adopt those changes to the kaithem usr. # It's even useful if we ever change the user for some reason. # We only do this if we start as root though. if not config['run-as-user'] == 'root' and getpass.getuser() == 'root': try: d = "/dev/shm/kaithem_pyx_" + config['run-as-user'] directories.rchown(d, config['run-as-user']) directories.rchown(directories.vardir, config['run-as-user']) directories.rchown(directories.logdir, config['run-as-user']) # Might as well own our own SSL dir, that way we can change certs via the webUI. directories.rchown(directories.ssldir, config['run-as-user']) directories.rchown(directories.usersdir, config['run-as-user']) directories.rchown(directories.regdir, config['run-as-user']) except: logger.exception("This is normal on non-unix") # If configured that way on unix, check if we are root and drop root. util.drop_perms(config['run-as-user'], config['run-as-group']) pylogginghandler.onUserChanged() messagebus.postMessage('/system/startup', 'System Initialized') messagebus.postMessage('/system/notifications/important', 'System Initialized') r = util.zeroconf import zeroconf # Register an NTP service desc = {} if cfg.config['advertise-webui']: try: import socket if not cfg.config['webui-servicename'] == "default": localserver_name = cfg.config['webui-servicename'] else: localserver_name = "kaithem_" + socket.gethostname() info = zeroconf.ServiceInfo( "_http._tcp.local.", localserver_name + "._http._tcp.local.", [None], cfg.config['http-port'], 0, 0, desc) r.register_service(info) info2 = zeroconf.ServiceInfo( "_https._tcp.local.", localserver_name + "._https._tcp.local.", [None], cfg.config['https-port'], 0, 0, desc) r.register_service(info2) except: logger.exception("Error advertising MDNS service") # Open a port to the outside world. Note that this can only be enabled through the webUI, # You are safe unless someone turns it on.. workers.do(systasks.doUPnP)
def start_server(cls, visibility=False, ao="alsa:device=[plughw:1,0]"): if os.path.isfile(PLAYLIST_FILE): f = open(PLAYLIST_FILE, "r") try: cls.playlist = json.loads(f.read()) except: pass finally: f.close() else: cls.playlist = [] cls.currently_playing = None cls.user_selected_flag = False cls.shutdown_flag = False cls.lock = threading.Lock() cls.play_lock = threading.Lock() cls.mpv = mpv.MPV(None, no_video="", ao=ao) cls.volume = 100.0 cls.play_queue = queue.Queue(maxsize=50) # threaded debug if DEBUG: cls._thread_debug = threading.Thread(target=cls._debug) cls._thread_debug.start() # threaded broadcast of position cls._thread_broadcast_pos = threading.Thread(target=cls._broadcast_position) cls._thread_broadcast_pos.start() # threaded play cls._thread_play = threading.Thread(target=cls._play) cls._thread_play.start() # start mpv listeners cls.mpv.register_event_callback(mpv.MpvEventID.END_FILE, cls._mpv_eof) # set mpv to paused initially cls.mpv.pause = True cherrypy_config = { "/rq": { "tools.websocket.on": True, "tools.websocket.handler_cls": JukeboxWebWorker, "tools.secureheaders.on": True, } } cherrypy.config.update({ "log.access_file": "access_log", "log.error_file": "error_log" }) cherrypy.config.update({"server.socket_port": WS_PORT}) if visibility: cherrypy.config.update({"server.socket_host": "0.0.0.0"}) # set the priority according to your needs if you are hooking something # else on the 'before_finalize' hook point. cherrypy.tools.secureheaders = cherrypy.Tool('before_finalize', secureheaders, priority=60) cls._wsp = WebSocketPlugin(cherrypy.engine) cls._wsp.subscribe() cherrypy.tools.websocket = WebSocketTool() cherrypy.engine.subscribe("stop", cls.stop_server) cherrypy.quickstart(JukeboxWebService(), "/", config=cherrypy_config)
def main(argv: list): # Get study parameters from the command-line parser = argparse.ArgumentParser() parser.add_argument('-f', '--finger_count', type=int, default=2, help='Number of fingers acquired per user') parser.add_argument('-e', '--enrollment_count', type=int, default=20, help='Number of enrollment images per finger') parser.add_argument('-v', '--verification_count', type=int, default=15, help='Number of verification images per finger') parser.add_argument('-p', '--port', type=int, default=9000, help='The port for the webserver') parser.add_argument('-d', '--picture_dir', default='./fingers', help='Directory for the fingerprint captures') parser.add_argument('-l', '--log_dir', help='Log files directory') parser.add_argument('-s', '--syslog', action='store_true', help='Log to syslog') args = parser.parse_args(argv) # Configure cherrypy server cherrypy.config.update({'server.socket_port': args.port}) if args.log_dir: log_name = 'server-%s.log' % (datetime.now().strftime('%Y%m%d_%H%M%S')) cherrypy.config.update({ 'log.access_file': os.path.join(args.log_dir, 'access.log'), 'log.error_file': os.path.join(args.log_dir, log_name), 'log.screen': False }) if args.syslog: h = logging.handlers.SysLogHandler( address='/dev/log', facility=logging.handlers.SysLogHandler.LOG_LOCAL1) h.setLevel(logging.DEBUG) h.setFormatter(cherrypy._cplogging.logfmt) logger = logging.getLogger('cherrypy.access') logger.setLevel(logging.DEBUG) logger.addHandler(h) logger = logging.getLogger('cherrypy.error') logger.setLevel(logging.DEBUG) logger.addHandler(h) cherrypy.config.update({'log.screen': False}) WebSocketPlugin(cherrypy.engine).subscribe() cherrypy.tools.websocket = WebSocketTool() cherrypy.quickstart(Root(args), '/', config={ '/finger': { 'tools.websocket.on': True, 'tools.websocket.handler_cls': FingerWebSocket }, '/static': { 'tools.staticdir.on': True, 'tools.staticdir.dir': HTML_DIR } })
def startFrontendThread(): template.initializeTemplateSystem() cherrypy.config.update({ 'server.socket_host': config.getLocalConfigValue('server.ipAddress'), 'server.socket_port': config.getLocalConfigValue('server.port'), 'log.screen': False, 'log.access_file': '', 'log.error_file': '' }) cherrypy.engine.unsubscribe('graceful', cherrypy.log.reopen_files) distping.configureLogging() # Configure SSL if (config.getLocalConfigValue('server.ssl.enabled')): cherrypy.config.update({ 'server.ssl_certificate': config.getLocalConfigValue('server.ssl.certificate'), 'server.ssl_private_key': config.getLocalConfigValue('server.ssl.privateKey') }) if (config.getLocalConfigValue('server.ssl.certificateChain') != ''): cherrypy.config.update({ 'server.ssl_certificate_chain': config.getLocalConfigValue('server.ssl.certificateChain') }) distPingFrontend = DistPingFrontend() WebSocketPlugin(cherrypy.engine).subscribe() cherrypy.tools.websocket = WebSocketTool() cherrypy.quickstart( distPingFrontend, '/', config={ '/': { 'tools.staticdir.on': True, 'tools.staticdir.root': distping.getRootDirectory() + '/web', 'tools.staticdir.dir': '', # Auth 'tools.auth_basic.on': True, 'tools.auth_basic.realm': 'DistPing', 'tools.auth_basic.checkpassword': validateUsernameAndPassword }, '/ws': { 'tools.websocket.on': True, 'tools.websocket.handler_cls': DistPingServer, # Auth 'tools.auth_basic.on': False, }, '/favicon.ico': { 'tools.staticfile.on': True, 'tools.staticfile.filename': distping.getRootDirectory() + '/web/resources/img/favicon.ico' } })
@login_required def socket(self): handler = cp.request.ws_handler handler.session_id = cp.request.cookie['session_id'].value def _cp_dispatch(self, vpath): if vpath[0] == 'profile': cp.request.params['username'] = vpath.pop() return vpath def error_404(status, message, traceback, version): return serve_file(cwd + '/static/error_404.html') WebSocketPlugin(cp.engine).subscribe() cp.tools.websocket = WebSocketTool() cfg = { '/favicon.ico': { 'tools.staticfile.on': True, 'tools.staticfile.filename': cwd + '/static/favicon.ico', }, '/apple-touch-icon.png': { 'tools.staticfile.on': True, 'tools.staticfile.filename': cwd + '/static/apple-touch-icon.png' }, '/manifest.json': { 'tools.staticfile.on': True, 'tools.staticfile.filename': cwd + '/static/manifest.json', },
self._priority = cherrypy.tools.sessions._priority + 1 # must be initialized after the sessions tool def upgrade(self, **kwargs): try: kwargs['handler_cls'].check_authentication() except WebSocketAuthError: raise cherrypy.HTTPError( 401, 'You must be logged in to establish a websocket connection.') except: log.error('unexpected websocket authentication error', exc_info=True) raise cherrypy.HTTPError(401, 'unexpected authentication error') else: return WebSocketTool.upgrade(self, **kwargs) cherrypy.tools.websockets = WebSocketChecker() websocket_plugin = WebSocketPlugin(cherrypy.engine) if hasattr(WebSocketPlugin.start, '__func__'): WebSocketPlugin.start.__func__.priority = 66 else: WebSocketPlugin.start.priority = 66 websocket_plugin.subscribe() local_broadcaster = Caller(local_broadcast) broadcaster = Caller(WebSocketDispatcher.broadcast) responder = Caller(WebSocketDispatcher.handle_message, threads=config['ws.thread_pool'])
ch.setLevel(logging.DEBUG) formatter = logging.Formatter('%(name)s - %(asctime)s - %(levelname)s' ' - %(message)s') ch.setFormatter(formatter) interface_logger.addHandler(ch) # create the preset folder if it does not exist: preset_dir = os.path.abspath(args.presetdir) if (not os.path.isdir(preset_dir)): print("Preset folder {} did not exist, creating.".format(preset_dir)) os.makedirs(preset_dir) # Add the websocket requirements. cherrypy.tools.websocket = WebSocketTool() a = WebSocketPlugin(cherrypy.engine) a.manager = WebSocketManager() a.subscribe() stack_interface = interface.StackInterface() stack_interface.daemon = True stack_interface.start() server_tree = FocusStackRoot(stack_interface, preset_dir=preset_dir) # create a broadcast function which relays messages received over the # serial port to the websockets via the websocketmanager. def broadcaster(): m = stack_interface.get_message() if m: payload = dict(m) payload["msg_type"] = message.msg_type_name[payload["msg_type"]]