#!/usr/bin/env python2.2
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
# 
##############################################################################
"""
$Id: clock.py,v 1.1.1.1 2003/10/06 20:25:11 tseaver Exp $

External clock tick component of Scheduler product.  Requires Python 2.2.

"""
__version__ = "$Revision: 1.1.1.1 $"[11:-2]

import sys
import time
from xmlrpclib import Server
from BasicAuthTransport import BasicAuthTransport
import getopt
import traceback

class Clock:

    def __init__( self
                , scheduler_url
                , period
                , max_tasks
                , userid
                , password
                , logfile=sys.stdout
                , errfile=sys.stderr
                , verbosity=0
                ):

        self._scheduler_url = scheduler_url
        self._period = period
        self._max_tasks = max_tasks
        self._userid = userid
        self._password = password
        self._logfile = logfile
        self._errfile = errfile
        self._verbosity = verbosity

    def run(self):
        """ Loop forever, popping the scheduler and then sleeping.
        """
        scheduler = self._makeScheduler()
        while 1:
            try:
                if self._max_tasks is None:
                    scheduler.notify()
                elif self._max_tasks == 1:
                    scheduler.notifyOne()   # so mapply will work
                else:
                    scheduler.notifyMax( self._max_tasks ) # broken for mapply
            except:
                traceback.print_exc(file=self._errfile)
                self._errfile.write( '\n' )
                self._logfile.write('Clock failure at %s\n'
                                   % time.ctime(time.time()))
            else:
                if self._verbosity:
                    self._logfile.write('Clock succeded at %s\n'
                                       % time.ctime(time.time()))
            time.sleep(self._period)

    def _makeScheduler(self):
        """ Create the XML-RPC connection to the scheduler.
        """
        #   XXX:  Hardwired credentials
        transport = BasicAuthTransport(self._userid, self._password)
        return Server(self._scheduler_url, transport=transport)


def usage():
    USAGE = """clock [options]

Options:

  -?, -h, --help        Print this usage message.

  -q, --quiet           Don't blather about success (default).

  -v, --verbose         Blather about success.

  -n, --nethost         Supply the nethost part of the scheduler URL
                        (defaults to 'http://localhost:8080').

  -s, --scheduler_path  Supply the path part of the scheduler URL
                        (defaults to '/workbench/portal_scheduler').

  -a, --auth            Supply the authentication credentials as a
                        'userid:password' token.

  -p, --period          Supply the period interval, in seconds, at which
                        the clock should notify the schedulre (default 20).

  -t, --max_tasks       Supply the maximum number of tasks to be run
                        (default 1).

  -T, --all_tasks       Dispatch *all* pending tasks.

  -l, --logfile         The logfile used (default: stdout) for reporting.

  -e, --errfile         The error file used for error reporting (def: stderr).
"""
    print USAGE
    sys.exit(2)

def main():

    nethost = 'http://localhost:8080'
    scheduler_path = '/workbench/portal_scheduler'
    userid = 'admin'
    password = '123'
    period = 20
    max_tasks = 1
    verbosity = 0
    logfile = sys.stdout
    errfile = sys.stderr

    try:
        opts, args = getopt.getopt( sys.argv[1:]
                                , '?hqvtTn:s:a:p:l:e:'
                                , [ 'help'
                                  , 'quiet'
                                  , 'verbose'
                                  , 'nethost='
                                  , 'scheduler_path='
                                  , 'auth='
                                  , 'period='
                                  , 'max_tasks='
                                  , 'all_tasks='
                                  , 'errfile='
                                  , 'logfile='
                                  ]
                                )
    except getopt.GetoptError:
        usage()

    if args:
        usage()

    for k, v in opts:

        if k == '-h' or k == '-?' or k == '--help':
            usage()

        if k == '-q' or k == '--quiet':
            verbosity = 0

        if k == '-v' or k == '--verbose':
            verbosity += 1

        if k == '-n' or k == '--nethost':
            nethost = v

        if k == '-s' or k == '--scheduler_path':
            scheduler_path = v

        if k == '-a' or k == '--auth':
            userid, password = v.split( ':' )

        if k == '-p' or k == '--period':
            period = int( v )

        if k == '-t' or k == '--max_tasks':
            max_tasks = int( v )

        if k == '-T' or k == '--all_tasks':
            max_tasks = None

        if k == '-l' or k == '--logfile':
            logfile = open(v, 'a')

        if k == '-e' or k == '--errfile':
            errfile = open(v, 'a')
        

    Clock( scheduler_url='%s/%s' % (nethost, scheduler_path)
         , period=period
         , max_tasks=max_tasks
         , userid=userid
         , password=password
         , logfile=logfile
         , errfile=errfile
         , verbosity=verbosity
         ).run()

if __name__ == '__main__':
    main()
