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