def serve_forever(port, alineaPackage, configFile): config = Config() config.read_file(configFile) sessionPickle = SessionPickle(sessionsPickleFile) sessions = sessionPickle.loadSessions() sessMgr = SessionManager(session_class=MySession, session_mapping=sessions) def create_publisher(): directory = __import__('%s' % alineaPackage).Directory.AlineaDirectory() pub = Publisher(directory, config=config, session_manager=sessMgr) return pub # we have to give SCGI the script_name of you app, so we extract it # from the site url. script_name = urllib2.urlparse.urlparse(site_url)[2] lock = threading.Lock() try: run(create_publisher, port=port,script_name=script_name,max_children=1) except KeyboardInterrupt: if not lock.locked: sessionPickle.saveSessions(sessMgr.sessions) lock.acquire()
def run(server_start, quixote_conf, app_conf): """ Run this application. server_start -- a function that starts a particular type of server. Specifically, a quixote.server.xxx_server.run function. quixote_conf -- a string of path to the Quixote configuration file. app_conf -- a string of path to the application configuration file. """ app_options = configure(app_conf, schema) ctx = Context() ctx.app_options = app_options ctx.user_mgr = UserManager( CachingDirStore(app_options.get("bookie", "user_store"))) ctx.bookmarksdb = CachingDirStore( app_options.get("bookie", "bookmarks_store")) # Sessions will timed out after 2 days. session_mgr = FixedTimeoutSessionManager(Session, {}) session_mgr.timeout_in_min = 2880 config_obj = Config() config_obj.read_file(quixote_conf) # A background thread to clean up expired session # every 60 mins. SessionReaper(60, session_mgr).start() # The publisher factory function. def create_publisher(): publisher = ThreadedPublisher(RootDirectory(), session_manager=session_mgr, config=config_obj) publisher.context = ctx return publisher server_start(create_publisher, host=app_options.get("server", "host"), port=app_options.get("server", "port"))
def handler(req): opts = req.get_options() try: package = opts['quixote-root-namespace'] except KeyError: package = None try: configfile = opts['quixote-config-file'] config = Config() config.read_file(configfile) except KeyError: config = None if not package: return apache.HTTP_INTERNAL_SERVER_ERROR pub = name2publisher.get(package) if pub is None: pub = ModPythonPublisher(package, config) name2publisher[package] = pub return pub.publish_modpython(req)
def main(): out = sys.stdout sys.stdout = EmptyFile() sys.stderr = EmptyFile() # session handling sessionPickle = SessionPickle(config.sessionsPickleFile) sessions = sessionPickle.loadSessions() sessMgr = SessionManager(session_class=MySession, session_mapping=sessions) directory = AlineaDirectory() conf = Config() conf.read_file(CONFIG) publisher = Publisher(directory, session_manager=sessMgr, config=conf) request = HTTPRequest(sys.stdin, os.environ) response = publisher.process_request(request) response.write(out) sessionPickle.saveSessions(sessMgr.sessions)
def create_publisher(opts): global _publisher if _publisher is None: from quixote.server.mod_python_handler import ModPythonPublisher from quixote.config import Config from Alinea.AlineaLib.Session import MySession from Alinea.AlineaLib.ModPySessionManager import ModPySessionManager from Alinea.Directory import AlineaDirectory sess_manager = ModPySessionManager(session_class=MySession) configFile = opts['alinea-config-file'] config = Config() config.read_file(configFile) _publisher = ModPythonPublisher(AlineaDirectory(), config=config, session_manager=sess_manager) publisher = _publisher return publisher
class Publisher: """ The core of Quixote and of any Quixote application. This class is responsible for converting each HTTP request into a search of Python's package namespace and, ultimately, a call of a Python function/method/callable object. Each invocation of a driver script should have one Publisher instance that lives for as long as the driver script itself. Eg. if your driver script is plain CGI, each Publisher instance will handle exactly one HTTP request; if you have a FastCGI driver, then each Publisher will handle every HTTP request handed to that driver script process. Instance attributes: root_namespace : module | instance | class the Python namespace that will be searched for objects to fulfill each HTTP request exit_now : boolean used for internal state management. If true, the loop in publish_cgi() will terminate at the end of the current request. access_log : file file to which every access will be logged; set by setup_logs() (None if no access log) error_log : file file to which application errors (exceptions caught by Quixote, as well as anything printed to stderr by application code) will be logged; set by setup_logs(). Set to sys.stderr if no ERROR_LOG setting in the application config file. config : Config holds all configuration info for this application. If the application doesn't have a config file, uses the default values from the quixote.config module. _request : HTTPRequest the HTTP request currently being processed. namespace_stack : [ module | instance | class ] """ def __init__(self, root_namespace, config=None): from quixote.config import Config # if more than one publisher in app, need to set_publisher per request set_publisher(self) if type(root_namespace) is types.StringType: self.root_namespace = _get_module(root_namespace) else: # Should probably check that root_namespace is really a # namespace, ie. a module, class, or instance -- but it's # tricky to know if something is really a class or instance # (because of ExtensionClass), and who knows what other # namespaces are lurking out there in the world? self.root_namespace = root_namespace # for PublishError exception handling self.namespace_stack = [self.root_namespace] self.exit_now = 0 self.access_log = None self.error_log = sys.stderr # possibly overridden in setup_logs() sys.stdout = self.error_log # print is handy for debugging # Initialize default config object with all the default values from # the config variables at the top of the config module, ie. if # ERROR_LOG is set to "/var/log/quxiote-error.log", then # config.ERROR_LOG will also be "/var/log/quixote-error.log". If # application FCGI/CGI scripts need to override any of these # defaults, they can do so by direct manipulation of the config # object, or by reading a config file: # app.read_config("myapp.conf") if config is None: self.config = Config() else: self.set_config(config) self._local = threading.local() @property def _request(self): warnings.warn("use get_request instead of _request") return self.get_request() def configure(self, **kwargs): self.config.set_from_dict(kwargs) def read_config(self, filename): self.config.read_file(filename) def set_config(self, config): from quixote.config import Config if not isinstance(config, Config): raise TypeError, "'config' must be a Config instance" self.config = config def setup_logs(self): """ Open all log files specified in the config file. Reassign sys.stderr to go to the error log, and sys.stdout to go to the debug log. """ if self.config.access_log is not None: try: self.access_log = open(self.config.access_log, 'a', 1) except IOError, exc: sys.stderr.write("error opening access log %s: %s\n" % (`self.config.access_log`, exc.strerror)) if self.config.error_log is not None: try: self.error_log = open(self.config.error_log, 'a', 1) sys.stderr = self.error_log except IOError, exc: # leave self.error_log as it was, most likely sys.stderr sys.stderr.write("error opening error log %s: %s\n" % (`self.config.error_log`, exc.strerror))
class Publisher: """ The core of Quixote and of any Quixote application. This class is responsible for converting each HTTP request into a search of Python's package namespace and, ultimately, a call of a Python function/method/callable object. Each invocation of a driver script should have one Publisher instance that lives for as long as the driver script itself. Eg. if your driver script is plain CGI, each Publisher instance will handle exactly one HTTP request; if you have a FastCGI driver, then each Publisher will handle every HTTP request handed to that driver script process. Instance attributes: root_namespace : module | instance | class the Python namespace that will be searched for objects to fulfill each HTTP request exit_now : boolean used for internal state management. If true, the loop in publish_cgi() will terminate at the end of the current request. access_log : file file to which every access will be logged; set by setup_logs() (None if no access log) error_log : file file to which application errors (exceptions caught by Quixote, as well as anything printed to stderr by application code) will be logged; set by setup_logs(). Set to sys.stderr if no ERROR_LOG setting in the application config file. config : Config holds all configuration info for this application. If the application doesn't have a config file, uses the default values from the quixote.config module. _request : HTTPRequest the HTTP request currently being processed. namespace_stack : [ module | instance | class ] """ def __init__(self, root_namespace, config=None): from quixote.config import Config # if more than one publisher in app, need to set_publisher per request set_publisher(self) if type(root_namespace) is types.StringType: self.root_namespace = _get_module(root_namespace) else: # Should probably check that root_namespace is really a # namespace, ie. a module, class, or instance -- but it's # tricky to know if something is really a class or instance # (because of ExtensionClass), and who knows what other # namespaces are lurking out there in the world? self.root_namespace = root_namespace # for PublishError exception handling self.namespace_stack = [self.root_namespace] self.exit_now = 0 self.access_log = None self.error_log = sys.stderr # possibly overridden in setup_logs() sys.stdout = self.error_log # print is handy for debugging # Initialize default config object with all the default values from # the config variables at the top of the config module, ie. if # ERROR_LOG is set to "/var/log/quxiote-error.log", then # config.ERROR_LOG will also be "/var/log/quixote-error.log". If # application FCGI/CGI scripts need to override any of these # defaults, they can do so by direct manipulation of the config # object, or by reading a config file: # app.read_config("myapp.conf") if config is None: self.config = Config() else: self.set_config(config) self._local = threading.local() @property def _request(self): warnings.warn("use get_request instead of _request") return self.get_request() def configure(self, **kwargs): self.config.set_from_dict(kwargs) def read_config(self, filename): self.config.read_file(filename) def set_config(self, config): from quixote.config import Config if not isinstance(config, Config): raise TypeError, "'config' must be a Config instance" self.config = config def setup_logs(self): """ Open all log files specified in the config file. Reassign sys.stderr to go to the error log, and sys.stdout to go to the debug log. """ if self.config.access_log is not None: try: self.access_log = open(self.config.access_log, 'a', 1) except IOError, exc: sys.stderr.write("error opening access log %s: %s\n" % ( ` self.config.access_log `, exc.strerror)) if self.config.error_log is not None: try: self.error_log = open(self.config.error_log, 'a', 1) sys.stderr = self.error_log except IOError, exc: # leave self.error_log as it was, most likely sys.stderr sys.stderr.write("error opening error log %s: %s\n" % ( ` self.config.error_log `, exc.strerror))