comparison roundup/scripts/roundup_server.py @ 2840:a212699c21f2

windows service part rewritten to take in account command line options; require logfile for windows service; log service startup and shutdown in windows event log
author Alexander Smishlajev <a1s@users.sourceforge.net>
date Fri, 29 Oct 2004 20:39:31 +0000
parents 91b2d50f0b1a
children 98e2e7b57101
comparison
equal deleted inserted replaced
2839:f965de0c1e75 2840:a212699c21f2
15 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 15 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
16 # 16 #
17 17
18 """Command-line script that runs a server over roundup.cgi.client. 18 """Command-line script that runs a server over roundup.cgi.client.
19 19
20 $Id: roundup_server.py,v 1.68 2004-10-29 17:57:17 a1s Exp $ 20 $Id: roundup_server.py,v 1.69 2004-10-29 20:39:31 a1s Exp $
21 """ 21 """
22 __docformat__ = 'restructuredtext' 22 __docformat__ = 'restructuredtext'
23 23
24 import errno, cgi, getopt, os, socket, sys, traceback, urllib 24 import errno, cgi, getopt, os, socket, sys, traceback, urllib
25 import ConfigParser, BaseHTTPServer, SocketServer, StringIO 25 import ConfigParser, BaseHTTPServer, SocketServer, StringIO
426 import win32file 426 import win32file
427 427
428 class SvcShutdown(Exception): 428 class SvcShutdown(Exception):
429 pass 429 pass
430 430
431 class RoundupService(win32serviceutil.ServiceFramework, 431 class RoundupService(win32serviceutil.ServiceFramework):
432 BaseHTTPServer.HTTPServer): 432
433 ''' A Roundup standalone server for Win32 by Ewout Prangsma
434 '''
435 _svc_name_ = "Roundup Bug Tracker" 433 _svc_name_ = "Roundup Bug Tracker"
436 _svc_display_name_ = "Roundup Bug Tracker" 434 _svc_display_name_ = "Roundup Bug Tracker"
437 def __init__(self, args): 435
438 # redirect stdout/stderr to our logfile 436 running = 0
439 if LOGFILE: 437 server = None
440 # appending, unbuffered 438
441 sys.stdout = sys.stderr = open(LOGFILE, 'a', 0) 439 def SvcDoRun(self):
442 win32serviceutil.ServiceFramework.__init__(self, args)
443 BaseHTTPServer.HTTPServer.__init__(self, self.address,
444 RoundupRequestHandler)
445
446 # Create the necessary NT Event synchronization objects...
447 # hevSvcStop is signaled when the SCM sends us a notification
448 # to shutdown the service.
449 self.hevSvcStop = win32event.CreateEvent(None, 0, 0, None)
450
451 # hevConn is signaled when we have a new incomming connection.
452 self.hevConn = win32event.CreateEvent(None, 0, 0, None)
453
454 # Hang onto this module for other people to use for logging
455 # purposes.
456 import servicemanager 440 import servicemanager
457 self.servicemanager = servicemanager 441 self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
442 config = ServerConfig()
443 (optlist, args) = config.getopt(sys.argv[1:])
444 if not config["LOGFILE"]:
445 servicemanager.LogMsg(servicemanager.EVENTLOG_ERROR_TYPE,
446 servicemanager.PYS_SERVICE_STOPPED,
447 (self._svc_display_name_, "\r\nMissing logfile option"))
448 self.ReportServiceStatus(win32service.SERVICE_STOPPED)
449 return
450 self.server = config.get_server()
451 self.running = 1
452 self.ReportServiceStatus(win32service.SERVICE_RUNNING)
453 servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
454 servicemanager.PYS_SERVICE_STARTED, (self._svc_display_name_,
455 " at %s:%s" % (config["HOST"], config["PORT"])))
456 while self.running:
457 self.server.handle_request()
458 servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
459 servicemanager.PYS_SERVICE_STOPPED,
460 (self._svc_display_name_, ""))
461 self.ReportServiceStatus(win32service.SERVICE_STOPPED)
458 462
459 def SvcStop(self): 463 def SvcStop(self):
460 # Before we do anything, tell the SCM we are starting the 464 self.running = 0
461 # stop process. 465 # make dummy connection to self to terminate blocking accept()
466 addr = self.server.socket.getsockname()
467 if addr[0] == "0.0.0.0":
468 addr = ("127.0.0.1", addr[1])
469 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
470 sock.connect(addr)
471 sock.close()
462 self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 472 self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
463 win32event.SetEvent(self.hevSvcStop)
464
465 def SvcDoRun(self):
466 try:
467 self.serve_forever()
468 except SvcShutdown:
469 pass
470
471 def get_request(self):
472 # Call WSAEventSelect to enable self.socket to be waited on.
473 win32file.WSAEventSelect(self.socket, self.hevConn,
474 win32file.FD_ACCEPT)
475 while 1:
476 try:
477 rv = self.socket.accept()
478 except socket.error, why:
479 if why[0] != win32file.WSAEWOULDBLOCK:
480 raise
481 # Use WaitForMultipleObjects instead of select() because
482 # on NT select() is only good for sockets, and not general
483 # NT synchronization objects.
484 rc = win32event.WaitForMultipleObjects(
485 (self.hevSvcStop, self.hevConn),
486 0, win32event.INFINITE)
487 if rc == win32event.WAIT_OBJECT_0:
488 # self.hevSvcStop was signaled, this means:
489 # Stop the service!
490 # So we throw the shutdown exception, which gets
491 # caught by self.SvcDoRun
492 raise SvcShutdown
493 # Otherwise, rc == win32event.WAIT_OBJECT_0 + 1 which means
494 # self.hevConn was signaled, which means when we call
495 # self.socket.accept(), we'll have our incoming connection
496 # socket!
497 # Loop back to the top, and let that accept do its thing...
498 else:
499 # yay! we have a connection
500 # However... the new socket is non-blocking, we need to
501 # set it back into blocking mode. (The socket that accept()
502 # returns has the same properties as the listening sockets,
503 # this includes any properties set by WSAAsyncSelect, or
504 # WSAEventSelect, and whether its a blocking socket or not.)
505 #
506 # So if you yank the following line, the setblocking() call
507 # will be useless. The socket will still be in non-blocking
508 # mode.
509 win32file.WSAEventSelect(rv[0], self.hevConn, 0)
510 rv[0].setblocking(1)
511 break
512 return rv
513 473
514 def usage(message=''): 474 def usage(message=''):
515 if RoundupService: 475 if RoundupService:
516 os_part = \ 476 os_part = \
517 ""''' -c <Command> Windows Service options. 477 ""''' -c <Command> Windows Service options.
619 usage(str(e)) 579 usage(str(e))
620 return 580 return
621 581
622 # if running in windows service mode, don't do any other stuff 582 # if running in windows service mode, don't do any other stuff
623 if ("-c", "") in optlist: 583 if ("-c", "") in optlist:
584 # acquire command line options recognized by service
585 short_options = "c:C:"
586 long_options = ["config"]
587 for (long_name, short_name) in config.OPTIONS.items():
588 short_options += short_name
589 long_name = long_name.lower().replace("_", "-")
590 if short_name[-1] == ":":
591 long_name += "="
592 long_options.append(long_name)
593 optlist = getopt.getopt(sys.argv[1:], short_options, long_options)[0]
594 svc_args = []
595 for (opt, arg) in optlist:
596 if opt in ("-C", "-l"):
597 # make sure file name is absolute
598 svc_args.extend((opt, os.path.abspath(arg)))
599 elif opt in ("--config", "--logfile"):
600 # ditto, for long options
601 svc_args.append("=".join(opt, os.path.abspath(arg)))
602 elif opt != "-c":
603 svc_args.extend(opt)
604 RoundupService._exe_args_ = " ".join(svc_args)
605 # pass the control to serviceutil
624 win32serviceutil.HandleCommandLine(RoundupService, 606 win32serviceutil.HandleCommandLine(RoundupService,
625 argv=sys.argv[:1] + args) 607 argv=sys.argv[:1] + args)
626 return 608 return
627 609
628 # add tracker names from command line. 610 # add tracker names from command line.

Roundup Issue Tracker: http://roundup-tracker.org/