diff -r 000000000000 -r b97547f5f1fa server/server.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/server.py Wed Nov 05 15:52:50 2008 +0100 @@ -0,0 +1,149 @@ +"""Pyro RQL server + +:organization: Logilab +:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +""" +__docformat__ = "restructuredtext en" + +import os +import sys +import select +import warnings +from time import localtime, mktime + +from cubicweb.cwconfig import CubicWebConfiguration +from cubicweb.server.repository import Repository + +class Finished(Exception): + """raise to remove an event from the event loop""" + +class TimeEvent: + """base event""" + # timefunc = staticmethod(localtime) + timefunc = localtime + + def __init__(self, absolute=None, period=None): + # local time tuple + if absolute is None: + absolute = self.timefunc() + self.absolute = absolute + # optional period in seconds + self.period = period + + def is_ready(self): + """return true if the event is ready to be fired""" + now = self.timefunc() + if self.absolute < now: + return True + return False + + def fire(self, server): + """fire the event + must be overridden by concrete events + """ + raise NotImplementedError() + + def update(self): + """update the absolute date for the event or raise a finished exception + """ + if self.period is None: + raise Finished + self.absolute = localtime(mktime(self.absolute) + self.period) + + +class QuitEvent(TimeEvent): + """stop the server""" + def fire(self, server): + server.repo.shutdown() + server.quiting = True + + +class RepositoryServer(object): + + def __init__(self, config, debug=False): + """make the repository available as a PyRO object""" + self.config = config + self.repo = Repository(config, debug=debug) + self.ns = None + self.quiting = None + # event queue + self.events = [] + # start repository looping tasks + + def add_event(self, event): + """add an event to the loop""" + self.info('adding event %s', event) + self.events.append(event) + + def trigger_events(self): + """trigger ready events""" + for event in self.events[:]: + if event.is_ready(): + self.info('starting event %s', event) + event.fire(self) + try: + event.update() + except Finished: + self.events.remove(event) + + def run(self, req_timeout=5.0): + """enter the service loop""" + while self.quiting is None: + try: + self.daemon.handleRequests(req_timeout) + except select.error: + continue + self.trigger_events() + + def quit(self): + """stop the server""" + self.add_event(QuitEvent()) + + def connect(self, host='', port=0): + """the connect method on the repository only register to pyro if + necessary + """ + self.daemon = self.repo.pyro_register(host) + + # server utilitities ###################################################### + + def install_sig_handlers(self): + """install signal handlers""" + import signal + self.info('installing signal handlers') + signal.signal(signal.SIGINT, lambda x, y, s=self: s.quit()) + signal.signal(signal.SIGTERM, lambda x, y, s=self: s.quit()) + + def daemonize(self, pid_file=None): + """daemonize the process""" + # fork so the parent can exist + if (os.fork()): + return -1 + # deconnect from tty and create a new session + os.setsid() + # fork again so the parent, (the session group leader), can exit. + # as a non-session group leader, we can never regain a controlling + # terminal. + if (os.fork()): + return -1 + # move to the root to avoit mount pb + os.chdir('/') + # set paranoid umask + os.umask(077) + if pid_file is not None: + # write pid in a file + f = open(pid_file, 'w') + f.write(str(os.getpid())) + f.close() + # filter warnings + warnings.filterwarnings('ignore') + # close standard descriptors + sys.stdin.close() + sys.stdout.close() + sys.stderr.close() + +from logging import getLogger +from cubicweb import set_log_methods +LOGGER = getLogger('cubicweb.reposerver') +set_log_methods(CubicWebConfiguration, LOGGER)