#!/usr/bin/env python
"""
ThreadedAppServerService
For general notes, see ThreadedAppServer.py.
This version of the app server is a threaded app server that runs as
a Windows NT Service. This means it can be started and stopped from
the Control Panel or from the command line using "net start" and
"net stop", and it can be configured in the Control Panel to
auto-start when the machine boots.
This requires the win32all package to have been installed.
To see the options for installing, removing, starting, and stopping
the service, just run this program with no arguments. Typical usage is
to install the service to run under a particular user account and startup
automatically on reboot with
python ThreadedAppServerService.py --username mydomain\myusername --password mypassword --startup auto install
Then, you can start the service from the Services applet in the Control Panel,
where it will be listed as "WebKit Threaded Application Server". Or, from
the command line, it can be started with either of the following commands:
net start WebKit
python ThreadedAppServerService.py start
The service can be stopped from the Control Panel or with:
net stop WebKit
python ThreadedAppServerService.py stop
And finally, to uninstall the service, stop it and then run:
python ThreadedAppServerService.py remove
FUTURE
* This shares a lot of code with ThreadedAppServer.py --
instead it should inherit from ThreadedAppServer and have
very little code of its own.
* Have an option for sys.stdout and sys.stderr to go to a logfile instead
of going nowhere.
* Optional NT event log messages on start, stop, and errors.
* Allow the option of installing multiple copies of WebKit with
different configurations and different service names.
* Figure out why I need the Python service hacks marked with ### below.
* Allow it to work with wkMonitor, or some other fault tolerance
mechanism.
"""
import time
startTime = time.time()
import win32serviceutil
import win32service
import os, sys, cStringIO
class ThreadedAppServerService(win32serviceutil.ServiceFramework):
_svc_name_ = 'WebKit'
_svc_display_name_ = 'WebKit Threaded Application Server'
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.server = None
# Fix the current working directory -- this gets initialized incorrectly
# for some reason when run as an NT service.
try:
os.chdir(os.path.abspath(os.path.dirname(__file__)))
except:
pass
def SvcStop(self):
# Before we do anything, tell the SCM we are starting the stop process
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
# And set running to 0 in the server. If it hasn't started yet, we'll
# have to wait until it does.
while self.server is None:
time.sleep(1.0)
self.server.initiateShutdown()
def SvcDoRun(self):
try:
# Temporarily suck up stdout and stderr into a cStringIO
stdoutAndStderr = cStringIO.StringIO()
sys.stdout = sys.stderr = stdoutAndStderr
# Import the ThreadedAppServer
if '' not in sys.path:
sys.path = [''] + sys.path
os.chdir(os.pardir)
from WebKit import Profiler
Profiler.startTime = startTime
from WebKit.ThreadedAppServer import ThreadedAppServer
self.server = ThreadedAppServer(self.workDir())
# Now switch the output to the logfile specified in the appserver's config
# setting "NTServiceLogFilename"
if self.server.hasSetting('NTServiceLogFilename'):
sys.stdout = sys.stderr = open(self.server.setting('NTServiceLogFilename'), 'a+')
sys.stdout.write('-' * 68 + '\n')
sys.stdout.write(stdoutAndStderr.getvalue())
else:
# Make all output go nowhere. Otherwise, print statements cause
# the service to crash, believe it or not.
sys.stdout = sys.stderr = open('nul', 'w')
del stdoutAndStderr
self.server.mainloop()
self.server._closeThread.join()
except Exception, e: #Need to kill the Sweeper thread somehow
print e
print "Exiting AppServer"
if 0: #See the traceback from an exception
tb = sys.exc_info()
print tb[0]
print tb[1]
import traceback
traceback.print_tb(tb[2])
if self.server:
self.server.running=0
self.server.shutDown()
raise
def workDir(self):
return None
if __name__=='__main__':
win32serviceutil.HandleCommandLine(ThreadedAppServerService)