Roundup Tracker - Issues

Message3250

Author gilesbrown
Recipients
Date 2003-09-03.15:01:26
Message-id
In-reply-to
The NT service handling in roundup 0.6.0, apart from not 
working properly (was incorrectly doing EventSelect 
within "while 1:") also does not allow parameters (port, 
etc) to be set for service.

I have hacked out the following code from 
roundup_server.py into a file (which I called 
roundup_service.py).
Benefits:
    -   It works.
    -   It lets you store server/service parameters in 
registry.

Perhaps this is of use to you.

Regards,
Giles Brown


"""
import os
import sys
import socket
from   BaseHTTPServer import HTTPServer

import win32service
import win32serviceutil
import win32event
import win32file

from   roundup_server import RoundupRequestHandler

class SvcShutdown(Exception): pass

class RoundupService
(win32serviceutil.ServiceFramework, HTTPServer):
    '''A Roundup standalone server for Win32 by Ewout 
Prangsma.
       Modified by Giles Brown.
    '''

    _svc_name_ = "Roundup Bug Tracker"
    _svc_display_name_ = "Roundup Bug Tracker"

    # Default options.
    # Sub-set of roundup_server.py options that make 
sense for NT service.
    options = {
        'hostname' : '',
        'port'  : 8080,
        'logfile' : None,
        'log_ipaddress' : 1,
        }


    def __init__(self, args):

        options = dict(RoundupService.options)

        # Read options from registry
        for name, val in options.items():
            options[name] = 
win32serviceutil.GetServiceCustomOption(
                RoundupService, name, val)

        RoundupRequestHandler.LOG_IPADDRESS = options
['log_ipaddress']

        numtrackers = 
win32serviceutil.GetServiceCustomOption(
                RoundupService, 'numtrackers', 0)
        RoundupRequestHandler.TRACKER_HOMES.clear()
        for i in range(numtrackers):
            trackername = 
win32serviceutil.GetServiceCustomOption(
                RoundupService, 'trackername%d' % 
i, '<missing registry value>')
            trackerhome = 
win32serviceutil.GetServiceCustomOption(
                RoundupService, 'trackerhome%d' % 
i, '<missing registry value>')
            RoundupRequestHandler.TRACKER_HOMES
[trackername] = trackerhome

        win32serviceutil.ServiceFramework.__init__(self, 
args)
        HTTPServer.__init__(self, (options['hostname'], 
options['port']),
            RoundupRequestHandler)

        # redirect stdout/stderr to our logfile
        if options['logfile']:
            # appending, unbuffered
            sys.stdout = sys.stderr = open(options
['logfile'], 'a', 0)
        else:
            # Re-direct standard output so PythonWin 
Trace Collection can read
            import win32traceutil

        # Create the necessary NT Event synchronization 
objects...
        # hevSvcStop is signaled when the SCM sends us 
a notification
        # to shutdown the service.
        self.hevSvcStop = win32event.CreateEvent(None, 
0, 0, None)

        # hevConn is signaled when we have a new 
incomming connection.
        self.hevConn    = win32event.CreateEvent(None, 
0, 0, None)

        # Hang onto this module for other people to use 
for logging
        # purposes.
        import servicemanager
        self.servicemanager = servicemanager

    def SvcStop(self):
        # Before we do anything, tell the SCM we are 
starting the
        # stop process.
        self.ReportServiceStatus
(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hevSvcStop)

    def SvcDoRun(self):
        try:
            self.serve_forever()
        except SvcShutdown:
            pass

    def get_request(self):
        '''Return (blocking until) next HTTP request.'''

        # Call WSAEventSelect to enable self.socket to be 
waited on.
        win32file.WSAEventSelect(self.socket, 
self.hevConn, win32file.FD_ACCEPT)

        # Loop until either:
        #     - we accept a socket connection, or
        #     - we raise an exception because we have 
been asked to stop

        while 1:

            try:
                rv = self.socket.accept()
                break
            except socket.error, why:
                if why[0] != win32file.WSAEWOULDBLOCK:
                    raise

            # Use WaitForMultipleObjects instead of select
() because
            # on NT select() is only good for sockets, and 
not general
            # NT synchronization objects.
            rc = win32event.WaitForMultipleObjects
((self.hevSvcStop, 
                self.hevConn), 0, win32event.INFINITE)

            if rc == win32event.WAIT_OBJECT_0:

                # self.hevSvcStop was signaled, this means:
                # Stop the service!
                # So we throw the shutdown exception, 
which gets
                # caught by self.SvcDoRun
                raise SvcShutdown
                # Otherwise, rc == WAIT_OBJECT_0 + 1 
which means
                # self.hevConn was signaled, which means 
when we call 
                # self.socket.accept(), we'll have our 
incoming connection
                # socket!
                # Loop back to the top, and let that accept 
do its thing...


        # yay! we have a connection
        # However... the new socket is non-blocking, we 
need to
        # set it back into blocking mode. (The socket that 
accept()
        # returns has the same properties as the listening 
sockets,
        # this includes any properties set by 
WSAAsyncSelect, or 
        # WSAEventSelect, and whether its a blocking 
socket or not.)
        #
        # So if you yank the following line, the setblocking
() call 
        # will be useless. The socket will still be in non-
blocking
        # mode.
        win32file.WSAEventSelect(rv[0], self.hevConn, 0)
        rv[0].setblocking(1)

        return rv

if __name__ == '__main__':

    # 
    # Ugly hack to override win32serviceutil usage()
    origusage = win32serviceutil.usage

    def usage():
        # Catch call to sys.exit(1) so we can tack our 
message on the end
        try:
            origusage()
        except SystemExit, e:
            pass
        print " -n hostname :  sets the host name"
        print " -p port : sets the port to listen on"
        print " -l path : sets path of log file"
        print " -N : log names in access log not IP 
addresses (much slower)"
        print " -t <tracker name>=<tracker home> : add 
track to service"
        print
        print "Cannot change tracker options 
using 'update'."
        print "Instead use 'remove' then 'install'."
        sys.exit(1)

    win32serviceutil.usage = usage

    def customOptionHandler(optlist):

        options = dict(RoundupService.options)

        trackers = []

        # Override default values
        for (opt, arg) in optlist:
            if opt == '-n': 
                options['hostname'] = arg
            elif opt == '-p': 
                options['port'] = int(arg)
            elif opt == '-l': 
                options['logfile'] = os.path.abspath(arg)
            elif opt == '-N': 
                options['log_ipaddress'] = 0
            elif opt == '-t': 
                trackers.append(arg.split('='))

        # Save settings
        for name, val in options.iteritems():
            win32serviceutil.SetServiceCustomOption
(RoundupService, name, val) 

        # XXX: would use 'enumerate' in python 2.3 
onwards
        for index, (name, home) in zip(range(len
(trackers)), trackers):
            win32serviceutil.SetServiceCustomOption
(RoundupService, 
                'trackername%d' % index, name)
            win32serviceutil.SetServiceCustomOption
(RoundupService, 
                'trackerhome%d' % index, home) 

        win32serviceutil.SetServiceCustomOption
(RoundupService, 
                'numtrackers', len(trackers)) 


    win32serviceutil.HandleCommandLine(RoundupService,
        customInstallOptions='t:n:p:l:N', 
        customOptionHandler=customOptionHandler)

# Uncomment this for debugging first part 
of 'RoundupService.__init__'
#else:
#    import win32traceutil
"""
History
Date User Action Args
2009-02-03 14:23:46adminlinkissue799854 messages
2009-02-03 14:23:46admincreate