[Zope-Checkins] CVS: Zope/lib/python/ZServer -
ClockServer.py:1.1.2.1 component.xml:1.3.38.1 datatypes.py:1.3.16.1
Chris McDonough
chrism at plope.com
Thu Dec 25 04:08:16 EST 2003
Update of /cvs-repository/Zope/lib/python/ZServer
In directory cvs.zope.org:/tmp/cvs-serv22553/lib/python/ZServer
Modified Files:
Tag: chrism-scheduling-branch
component.xml datatypes.py
Added Files:
Tag: chrism-scheduling-branch
ClockServer.py
Log Message:
Initial clock server implementation. The clock server generates a faux http request to a traversable method at a regular interval using arbitrary authentication credentials without the aid of an external process (it uses ZServer internals to schedule the request like any other Zope request). The method, the interval, and the credentials are configurable via the Zope config file. More than one clock server can be caused to run per instance.
=== Added File Zope/lib/python/ZServer/ClockServer.py ===
##############################################################################
#
# 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
#
##############################################################################
""" Zope clock server. Generate a faux HTTP request on a regular basis
by coopting the asyncore API. """
import sys, string, os, socket, time, StringIO, base64
import asyncore
from medusa.thread.select_trigger import trigger
from medusa.http_server import http_request
from medusa.default_handler import unquote
from Lifetime.timeslice import timeslice
from PubCore import handle
from HTTPResponse import make_response
from ZPublisher.HTTPRequest import HTTPRequest
_last_slices = {} # one entry will be in this map per clock server
class LogHelper:
def __init__(self, logger):
self.logger = logger
def log(self, ip, msg, **kw):
self.logger.log(ip + ' ' + msg)
class DummyChannel:
# we need this minimal do-almost-nothing channel class to appease medusa
addr = ['127.0.0.1']
closed = 1
def __init__(self, server):
self.server = server
def push_with_producer(self):
pass
def close_when_done(self):
pass
class ClockServer(asyncore.dispatcher):
SERVER_IDENT = 'Zope Clock' # required by ZServer
def __init__ (self, method, period=60, user=None, password=None,
host=None, logger=None):
self.myid = id(self)
_last_slices[self.myid] = timeslice(period)
self.period = period
self.method = method
h = self.headers = []
h.append('User-Agent: Zope Clock Server Client')
h.append('Accept: text/html,text/plain')
if not host:
host = socket.gethostname()
h.append('Host: %s' % host)
auth = False
if user and password:
encoded = base64.encodestring('%s:%s' % (user, password))
encoded = encoded.replace('\012', '')
h.append('Authorization: Basic %s' % encoded)
auth = True
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.logger = LogHelper(logger)
self.log_info('Clock server for "%s" started (user: %s, period: %s)'
% (method, auth and user or 'Anonymous', self.period))
def get_requests_and_response(self):
out = StringIO.StringIO()
s_req = '%s %s HTTP/%s' % ('GET', self.method, '1.0')
req = http_request(DummyChannel(self), s_req, 'GET', self.method,
'1.0', self.headers)
env = self.get_env(req)
resp = make_response(req, env)
zreq = HTTPRequest(out, env, resp)
return req, zreq, resp
def get_env(self, req):
env = {}
(path, params, query, fragment) = req.split_uri()
if params:
path = path + params # undo medusa bug
while path and path[0] == '/':
path = path[1:]
if '%' in path:
path = unquote(path)
if query:
# ZPublisher doesn't want the leading '?'
query = query[1:]
env['REQUEST_METHOD']='GET'
env['SERVER_PORT']='Clock'
env['SERVER_NAME']='Zope Clock Server'
env['SERVER_SOFTWARE']='Zope'
env['SERVER_PROTOCOL']='HTTP/1.0'
env['channel.creation_time']=time.time()
env['SCRIPT_NAME']=''
env['PATH_INFO']= '/' + path
env['PATH_TRANSLATED']= os.path.normpath(
os.path.join(os.getcwd(), env['PATH_INFO']))
if query:
env['QUERY_STRING'] = query
env['GATEWAY_INTERFACE']='CGI/1.1'
env['REMOTE_ADDR']='0'
for header in req.header:
key,value=header.split(":",1)
key=key.upper()
value=value.strip()
key='HTTP_%s' % ("_".join(key.split( "-")))
if value:
env[key]=value
return env
def readable(self):
# generate a request at most once every self.period seconds
slice = timeslice(self.period)
if slice != _last_slices.get(self.myid):
# no need for threadsafety here, as we're only ever in one thread
_last_slices[self.myid] = slice
req, zreq, resp = self.get_requests_and_response()
handle('Zope', zreq, resp)
return 0
def handle_read(self):
pass
def handle_write (self):
self.log_info ('unexpected write event', 'warning')
def writable(self):
return 0
def handle_error (self): # don't close the socket on error
(file,fun,line), t, v, tbinfo = asyncore.compact_traceback()
self.log_info('Problem in Clock (%s:%s %s)' % (t, v, tbinfo),
'error')
=== Zope/lib/python/ZServer/component.xml 1.3 => 1.3.38.1 ===
--- Zope/lib/python/ZServer/component.xml:1.3 Mon Mar 24 17:32:39 2003
+++ Zope/lib/python/ZServer/component.xml Thu Dec 25 04:07:45 2003
@@ -58,4 +58,14 @@
<key name="address" datatype="inet-address"/>
</sectiontype>
+ <sectiontype name="clock-server"
+ datatype=".ClockServerFactory"
+ implements="ZServer.server">
+ <key name="method" datatype="string"/>
+ <key name="period" datatype="integer" default="60"/>
+ <key name="user" datatype="string" />
+ <key name="password" datatype="string"/>
+ <key name="host" datatype="string"/>
+ </sectiontype>
+
</component>
=== Zope/lib/python/ZServer/datatypes.py 1.3 => 1.3.16.1 ===
--- Zope/lib/python/ZServer/datatypes.py:1.3 Wed Oct 1 13:23:03 2003
+++ Zope/lib/python/ZServer/datatypes.py Thu Dec 25 04:07:45 2003
@@ -168,3 +168,19 @@
def create(self):
from ZServer.ICPServer import ICPServer
return ICPServer(self.host, self.port)
+
+class ClockServerFactory(ServerFactory):
+ def __init__(self, section):
+ ServerFactory.__init__(self)
+ self.method = section.method
+ self.period = section.period
+ self.user = section.user
+ self.password = section.password
+ self.host = section.host
+
+ def create(self):
+ from ZServer.ClockServer import ClockServer
+ from ZServer.AccessLogger import access_logger
+ return ClockServer(self.method, self.period, self.user,
+ self.password, self.host, access_logger)
+
More information about the Zope-Checkins
mailing list