--- /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)