#!/usr/bin/env python2.5
# -*- coding: utf-8 -*-
__doc__ = """
This script starts a queue server associating it with one or several memcached servers.

* Lookup the command line arguments:
  python queue-server.py --help  

* Start the server as follow:
  python queue-server.py --servers 127.0.0.1:11211

The --port parameter defines on which port the server will be listening. The default value is 9876.

* Stop the server as follow:
  kill -USR1 pid
  kill -15 pid

Where pid is the process identifier.
The first SIGUSR1 signal shutdowns client connections. The SIGTERM signal shutdowns the server.

If the server isn ot closed that way, it may have unexpected behavior. Notably the KeyboardInterrupt exception will not cleanly shutdown the server.
"""
#import gc
#gc.set_debug(gc.DEBUG_LEAK)

import sys
import socket

from cherrypy.process.wspbus import Bus
from cherrypy.process import plugins, servers

from Kamaelia.Chassis.ConnectedServer import SimpleServer

from bucker.provider.memcached import MemcachedQueue, MemcachedQueueProtocol
from bucker.lib.logger import Logger

bus = Bus()

def parse_commandline():
    from optparse import OptionParser
    parser = OptionParser()
    parser.add_option("-s", "--servers", dest="servers",
                      help="comma separated lists of IP:PORT of memcached servers (default=127.0.0.1:11211)")
    parser.set_defaults(servers='127.0.0.1:11211')
    parser.add_option("-p", "--port", dest="port", action="store",
                       type="int", help="queue server port (default=9876)")
    parser.set_defaults(port=9876)
    parser.add_option("-q", "--queue", dest="queue",
                      help="queue identifier (default=None)", action="store")
    parser.set_defaults(queue=None)
    parser.add_option("-t", "--visibility-timeout", type="int",
                      action="store", dest="visibility",
                      help="sets the visibility timeout in seconds for each message when accessed (default=30)")
    parser.set_defaults(visibility=30)
    parser.add_option("-l", "--logger-path", dest="logger_path", action="store",
                      help="absolute path to the log file (default=None)")
    parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
                      help="log every messages to stdout")
    parser.add_option("-i", "--pid-file", dest="pidfile", action="store",
                      help="if set, it must be the path of the file that will contain the PID of the process (default=None)")
    parser.set_defaults(pidfile=None)
    parser.add_option("-d", "--daemon", dest="daemon", action="store_true",
                      help="run server as daemon [UNSUPPORTED FOR NOW]")
    parser.set_defaults(logger_path=None)
    (options, args) = parser.parse_args()

    return options

class Server(object):
    def __init__(self):
        self.options = parse_commandline()

        servers = self.options.servers.split(',')
        self.queue = MemcachedQueue(servers=servers, 
                                    visibility_timeout=int(self.options.visibility),
                                    queue_list_name=self.options.queue)
        
        self.logger = None
        if self.options.logger_path or self.options.verbose:
            self.logger = Logger(self.options.logger_path, 
                                 self.options.verbose)
            self.queue.set_logger(self.logger)
            
        MemcachedQueue.setService(self.queue)

    def start(self):
        self.queue.activate()

        def make_protocol():
            mqp = MemcachedQueueProtocol()
            if self.logger:
                mqp.set_logger(self.logger)
            return mqp

        self.server = SimpleServer(protocol=make_protocol, 
                                   port=self.options.port,
                                   socketOptions=(socket.SOL_SOCKET, 
                                                  socket.SO_REUSEADDR, 1))
        bus.log("Queue server running on port %d" % self.options.port)
        self.server.activate()
    start.priority = 90

    def stop(self):
        from Kamaelia.Util.OneShot import OneShot

        from Kamaelia.IPC import serverShutdown
        o = OneShot(msg=serverShutdown())
        self.server.link((o, 'outbox'), (self.server, 'control'))
        o.activate()

        from Axon.Ipc import shutdownMicroprocess
        service, shutdownservice, queue = MemcachedQueue.getService()
        o = OneShot(msg=shutdownMicroprocess())
        service[0].link((o, 'outbox'), shutdownservice)
        o.activate()

    def exit(self):
        self.server.stop() 

def setup(server):
    plugins.SignalHandler(bus)
    if server.options.pidfile != None:
        plugins.PIDFile(bus, server.options.pidfile)
    bus.subscribe('start', server.start)
    bus.subscribe('graceful', server.stop)
    bus.subscribe('exit', server.exit)

    if 'win' not in sys.platform and server.options.daemon:
        bus.subscribe('start', restsrv.plugins.daemonize)

def serve():
    bus.start()
    #bus.block()
    from Axon.Scheduler import scheduler 
    scheduler.run.runThreads(slowmo=0.1) 

if __name__ == '__main__':
    s = Server()
    setup(s)
    serve()
