server/server.py
changeset 0 b97547f5f1fa
child 1802 d628defebc17
equal deleted inserted replaced
-1:000000000000 0:b97547f5f1fa
       
     1 """Pyro RQL server
       
     2 
       
     3 :organization: Logilab
       
     4 :copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     6 """
       
     7 __docformat__ = "restructuredtext en"
       
     8 
       
     9 import os
       
    10 import sys
       
    11 import select
       
    12 import warnings
       
    13 from time import localtime, mktime
       
    14 
       
    15 from cubicweb.cwconfig import CubicWebConfiguration
       
    16 from cubicweb.server.repository import Repository
       
    17 
       
    18 class Finished(Exception):
       
    19     """raise to remove an event from the event loop"""
       
    20 
       
    21 class TimeEvent:
       
    22     """base event"""
       
    23     # timefunc = staticmethod(localtime)
       
    24     timefunc = localtime
       
    25     
       
    26     def __init__(self, absolute=None, period=None):
       
    27         # local time tuple
       
    28         if absolute is None:
       
    29             absolute = self.timefunc()
       
    30         self.absolute = absolute
       
    31         # optional period in seconds
       
    32         self.period = period
       
    33 
       
    34     def is_ready(self):
       
    35         """return  true if the event is ready to be fired"""
       
    36         now = self.timefunc()
       
    37         if self.absolute < now:
       
    38             return True
       
    39         return False
       
    40 
       
    41     def fire(self, server):
       
    42         """fire the event
       
    43         must be overridden by concrete events
       
    44         """
       
    45         raise NotImplementedError()
       
    46 
       
    47     def update(self):
       
    48         """update the absolute date for the event or raise a finished exception
       
    49         """
       
    50         if self.period is None:
       
    51             raise Finished
       
    52         self.absolute = localtime(mktime(self.absolute) + self.period)
       
    53 
       
    54 
       
    55 class QuitEvent(TimeEvent):
       
    56     """stop the server"""
       
    57     def fire(self, server):
       
    58         server.repo.shutdown()
       
    59         server.quiting = True
       
    60         
       
    61 
       
    62 class RepositoryServer(object):
       
    63     
       
    64     def __init__(self, config, debug=False):
       
    65         """make the repository available as a PyRO object"""
       
    66         self.config = config
       
    67         self.repo = Repository(config, debug=debug)
       
    68         self.ns = None
       
    69         self.quiting = None
       
    70         # event queue
       
    71         self.events = []
       
    72         # start repository looping tasks
       
    73 
       
    74     def add_event(self, event):
       
    75         """add an event to the loop"""
       
    76         self.info('adding event %s', event)
       
    77         self.events.append(event)
       
    78 
       
    79     def trigger_events(self):
       
    80         """trigger ready events"""
       
    81         for event in self.events[:]:
       
    82             if event.is_ready():
       
    83                 self.info('starting event %s', event)
       
    84                 event.fire(self)
       
    85                 try:
       
    86                     event.update()
       
    87                 except Finished:
       
    88                     self.events.remove(event)
       
    89             
       
    90     def run(self, req_timeout=5.0):
       
    91         """enter the service loop"""
       
    92         while self.quiting is None:
       
    93             try:
       
    94                 self.daemon.handleRequests(req_timeout)
       
    95             except select.error:
       
    96                 continue
       
    97             self.trigger_events()
       
    98     
       
    99     def quit(self):
       
   100         """stop the server"""
       
   101         self.add_event(QuitEvent())
       
   102 
       
   103     def connect(self, host='', port=0):
       
   104         """the connect method on the repository only register to pyro if
       
   105         necessary
       
   106         """
       
   107         self.daemon = self.repo.pyro_register(host)
       
   108             
       
   109     # server utilitities ######################################################
       
   110     
       
   111     def install_sig_handlers(self):
       
   112         """install signal handlers"""
       
   113         import signal
       
   114         self.info('installing signal handlers')
       
   115         signal.signal(signal.SIGINT, lambda x, y, s=self: s.quit())
       
   116         signal.signal(signal.SIGTERM, lambda x, y, s=self: s.quit())
       
   117         
       
   118     def daemonize(self, pid_file=None):
       
   119         """daemonize the process"""
       
   120         # fork so the parent can exist
       
   121         if (os.fork()):
       
   122             return -1
       
   123         # deconnect from tty and create a new session
       
   124         os.setsid()
       
   125         # fork again so the parent, (the session group leader), can exit.
       
   126         # as a non-session group leader, we can never regain a controlling
       
   127         # terminal.
       
   128         if (os.fork()):
       
   129             return -1
       
   130         # move to the root to avoit mount pb
       
   131         os.chdir('/')
       
   132         # set paranoid umask
       
   133         os.umask(077)
       
   134         if pid_file is not None:
       
   135             # write pid in a file
       
   136             f = open(pid_file, 'w')
       
   137             f.write(str(os.getpid()))
       
   138             f.close()
       
   139         # filter warnings
       
   140         warnings.filterwarnings('ignore')
       
   141         # close standard descriptors
       
   142         sys.stdin.close()
       
   143         sys.stdout.close()
       
   144         sys.stderr.close()
       
   145 
       
   146 from logging import getLogger
       
   147 from cubicweb import set_log_methods
       
   148 LOGGER = getLogger('cubicweb.reposerver')
       
   149 set_log_methods(CubicWebConfiguration, LOGGER)