Esempio n. 1
0
        print(f"Delegate: exception reported in task {task}")
        traceback.print_exception(etype, evalue, etb)
        
    def taskEnded(self, queue, task):
        print(f"Delegate: task ended: {task}")
        
        
d = Delegate()

q1 = TaskQueue(2)
q2 = TaskQueue(2, delegate = d)
tok = TaskOK()
terr = TaskError()


print("-------- Queue without delegae --------")
for _ in range(100):
    q1 << tok << terr
q1.join()

print("-------- Queue with delegae --------")
for _ in range(100):
    q2 << tok << terr
q2.join()





        
Esempio n. 2
0
class Service(Primitive, Logged):
    def __init__(self, config, logger=None):
        name = config["name"]
        #print("Service(): config:", config)
        self.ServiceName = name
        Primitive.__init__(self, name=f"[service {name}]")
        Logged.__init__(self, f"[app {name}]", logger, debug=True)
        self.Config = None
        self.Initialized = self.initialize(config)

    @synchronized
    def initialize(self, config=None):
        config = config or self.Config
        self.Config = config

        reload_files = config.get("touch_reload", [])
        if isinstance(reload_files, str):
            reload_files = [reload_files]

        self.ReloadFileTimestamps = {
            path: self.mtime(path)
            for path in reload_files
        }

        self.Prefix = config.get("prefix", "/")
        self.ReplacePrefix = config.get("replace_prefix")
        self.Timeout = config.get("timeout", 10)

        saved_path = sys.path[:]
        saved_modules = set(sys.modules.keys())
        saved_environ = os.environ.copy()
        try:
            args = None
            if "file" in config:
                print(
                    '*** Use of "file" parameter is deprecated. Use "module" instead'
                )
            self.ScriptFileName = fname = config.get("module",
                                                     config.get("file"))
            g = {}

            extra_path = config.get("python_path")
            if extra_path is not None:
                if isinstance(extra_path, str):
                    extra_path = [extra_path]
                sys.path = extra_path + sys.path

            if "env" in config:
                os.environ.update(config["env"])

            try:
                exec(open(fname, "r").read(), g)
            except:
                tb = traceback.format_exc()
                self.log_error(f"Error importing module {fname}:\n{tb}")
                return False

            if "create" in config:
                # deprecated
                print(
                    '*** Use of "create" parameter is deprecated. Use "application: function()" instead'
                )
                application = config["create"] + "()"
            else:
                application = config.get("application", "application")
            if application.endswith("()"):
                args = config.get("args")
                fcn_name = application[:-2]
                fcn = g.get(fcn_name)
                if fcn is None:
                    self.log_error(
                        f"Application creation function {fcn_name} not found in module {fname}"
                    )
                    return False

                try:
                    if isinstance(args, dict):
                        app = fcn(**args)
                    elif isinstance(args, (list, tuple)):
                        app = fcn(*args)
                    elif args is None:
                        app = fcn()
                    else:
                        app = fcn(args)
                except:
                    tb = traceback.format_exc()
                    self.log_error(
                        f"Error calling the application initialization function:\n{tb}"
                    )
                    return False

                if app is None:
                    self.log_error(
                        f'Application creation function {fcn_name} returned None'
                    )
                    return False

            else:
                app = g.get(application)
                if app is None:
                    self.log_error(
                        f'Application object "{application}" not found in {fname}'
                    )
                    return False

            self.AppArgs = args
            self.WSGIApp = app

            max_workers = config.get("max_workers", 5)
            queue_capacity = config.get("queue_capacity", 10)
            self.RequestQueue = TaskQueue(max_workers,
                                          capacity=queue_capacity,
                                          delegate=self)
            self.log("initiaized")

        except:
            tb = traceback.format_exc()
            self.log_error(f"Error initializing application:\n{tb}")
            return False

        finally:
            sys.path = saved_path
            extra_modules = set(sys.modules.keys()) - set(saved_modules)
            #print("loadApp: removing modules:", sorted(list(extra_modules)))
            for m in extra_modules:
                del sys.modules[m]
            for n in set(os.environ.keys()) - set(saved_environ.keys()):
                del os.environ[n]
            os.environ.update(saved_environ)

        return True

    def taskFailed(self, queue, task, exc_type, exc_value, tb):
        self.log_error(
            "request failed:",
            "".join(traceback.format_exception(exc_type, exc_value, tb)))
        try:
            task.Request.close()
        except:
            pass

    def accept(self, request):
        #print(f"Service {self}: accept()")
        if not self.Initialized:
            return False
        header = request.HTTPHeader
        uri = header.URI
        self.debug("accept: uri:", uri, " prefix:", self.Prefix)
        #print("Sevice", self,"   accept: uri:", uri, " prefix:", self.Prefix)
        if uri.startswith(self.Prefix):
            uri = uri[len(self.Prefix):]
            if not uri.startswith("/"): uri = "/" + uri
            if self.ReplacePrefix:
                uri = self.ReplacePrefix + uri
            header.replaceURI(uri)
            request.AppName = self.ServiceName
            script_path = self.Prefix
            while script_path and script_path.endswith("/"):
                script_path = script_path[:-1]
            request.Environ["SCRIPT_NAME"] = script_path
            request.Environ["SCRIPT_FILENAME"] = self.ScriptFileName
            self.RequestQueue.addTask(
                RequestTask(self.WSGIApp, request, self.Logger))
            #print("Service", self, "   accepted")
            return True
        else:
            #print("Service", self, "   rejected")
            return False

    def close(self):
        self.RequestQueue.hold()

    def join(self):
        self.RequestQueue.join()

    def mtime(self, path):
        try:
            return os.path.getmtime(path)
        except:
            return None

    def reloadIfNeeded(self):
        for path, old_timestamp in self.ReloadFileTimestamps.items():
            mt = self.mtime(path)
            if mt is not None and mt != old_timestamp:
                ct = time.ctime(mt)
                self.log(f"file {path} was modified at {ct}")
                break
        else:
            return False
        self.Initialized = self.initialize()
Esempio n. 3
0
class HTTPServer(PyThread, Logged):
    def __init__(self,
                 port,
                 app=None,
                 services=[],
                 sock=None,
                 logger=None,
                 max_connections=100,
                 timeout=20.0,
                 enabled=True,
                 max_queued=100,
                 logging=False,
                 log_file="-",
                 debug=None,
                 certfile=None,
                 keyfile=None,
                 verify="none",
                 ca_file=None,
                 password=None):
        PyThread.__init__(self)
        self.Port = port
        self.Sock = sock
        assert self.Port is not None, "Port must be specified"
        if logger is None and logging:
            logger = Logger(log_file)
            #print("logs sent to:", f)
        Logged.__init__(self, f"[server {self.Port}]", logger, debug=True)
        self.Logger = logger
        self.Timeout = timeout
        max_connections = max_connections
        queue_capacity = max_queued
        self.RequestReaderQueue = TaskQueue(max_connections,
                                            capacity=queue_capacity,
                                            delegate=self)
        self.SocketWrapper = SSLSocketWrapper(
            certfile, keyfile, verify, ca_file, password) if keyfile else None

        if app is not None:
            services = [Service(app, logger)]

        self.Services = services
        self.Stop = False

    def close(self):
        self.Stop = True
        self.RequestReaderQueue.hold()

    def join(self):
        self.RequestReaderQueue.join()

    @staticmethod
    def from_config(config,
                    services,
                    logger=None,
                    logging=False,
                    log_file=None,
                    debug=None):
        port = config["port"]

        timeout = config.get("timeout", 20.0)
        max_connections = config.get("max_connections", 100)
        queue_capacity = config.get("queue_capacity", 100)

        # TLS
        certfile = config.get("cert")
        keyfile = config.get("key")
        verify = config.get("verify", "none")
        ca_file = config.get("ca_file")
        password = config.get("password")

        #print("HTTPServer.from_config: services:", services)

        return HTTPServer(port,
                          services=services,
                          logger=logger,
                          max_connections=max_connections,
                          timeout=timeout,
                          max_queued=queue_capacity,
                          logging=logging,
                          log_file=log_file,
                          debug=debug,
                          certfile=certfile,
                          keyfile=keyfile,
                          verify=verify,
                          ca_file=ca_file,
                          password=password)

    def setServices(self, services):
        self.Services = services

    def connectionCount(self):
        return len(self.Connections)

    def run(self):
        if self.Sock is None:
            # therwise use the socket supplied to the constructior
            self.Sock = socket(AF_INET, SOCK_STREAM)
            self.Sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
            self.Sock.bind(('', self.Port))
            self.Sock.listen(10)
        while not self.Stop:
            self.debug("--- accept loop port=%d start" % (self.Port, ))
            csock = None
            caddr = ('-', '-')
            try:
                csock, caddr = self.Sock.accept()
                self.connection_accepted(csock, caddr)
            except Exception as exc:
                #print(exc)
                if not self.Stop:
                    self.debug("connection processing error: %s" %
                               (traceback.format_exc(), ))
                    self.log_error(caddr,
                                   "Error processing connection: %s" % (exc, ))
                    if csock is not None:
                        try:
                            csock.close()
                        except:
                            pass
                self.debug("--- accept loop port=%d end" % (self.Port, ))
        if self.Stop: self.debug("stopped")
        try:
            self.Sock.close()
        except:
            pass
        self.Sock = None

    def connection_accepted(self, csock,
                            caddr):  # called externally by multiserver
        request = Request(self.Port, csock, caddr)
        self.debug("connection %s accepted from %s:%s" %
                   (request.Id, caddr[0], caddr[1]))
        reader = RequestReader(self, request, self.SocketWrapper, self.Timeout,
                               self.Logger)
        self.RequestReaderQueue << reader

    @synchronized
    def stop(self):
        self.Stop = True
        try:
            self.Sock.close()
        except:
            pass

    @synchronized
    def dispatch(self, request):
        for service in self.Services:
            if service.accept(request):
                return service
        else:
            return None

    def taskFailed(self, queue, task, exc_type, exc, tb):
        traceback.print_exception(exc_type, exc, tb)