Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
erp5
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
Romain Courteaud
erp5
Commits
49400d40
Commit
49400d40
authored
Oct 07, 2013
by
Kazuhiko Shiozaki
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
we don't use ClockServer. we use TimerService instead.
parent
07a136ec
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
0 additions
and
401 deletions
+0
-401
product/ClockServer/ClockServer.py
product/ClockServer/ClockServer.py
+0
-108
product/ClockServer/OriginalClockServer.py
product/ClockServer/OriginalClockServer.py
+0
-162
product/ClockServer/README
product/ClockServer/README
+0
-45
product/ClockServer/__init__.py
product/ClockServer/__init__.py
+0
-0
product/ClockServer/component.xml
product/ClockServer/component.xml
+0
-52
product/ClockServer/datatypes.py
product/ClockServer/datatypes.py
+0
-34
No files found.
product/ClockServer/ClockServer.py
deleted
100644 → 0
View file @
07a136ec
##############################################################################
#
# Copyright (c) 2008 Nexedi SARL and Contributors. All Rights Reserved.
# Vincent Pelletier <vincent@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from
OriginalClockServer
import
ClockServer
as
OriginalClockServer
from
OriginalClockServer
import
DummyChannel
from
ZServer.medusa.http_server
import
http_request
from
ZServer.HTTPResponse
import
make_response
from
ZPublisher.HTTPRequest
import
HTTPRequest
import
StringIO
import
thread
wait_for_close_lock
=
thread
.
allocate_lock
()
class
ClockServer
(
OriginalClockServer
):
running
=
True
def
__init__
(
self
,
*
args
,
**
kw
):
self
.
shutdown_method
=
kw
.
pop
(
'shutdown_method'
)
OriginalClockServer
.
__init__
(
self
,
*
args
,
**
kw
)
if
self
.
shutdown_method
is
None
:
self
.
log_info
(
'ClockServer shutdown_method is not set in configuration'
\
'file. Unclean shutdown can happen.'
,
type
=
'warning'
)
def
readable
(
self
):
"""
Avoid starting a new tic if shutdown started.
"""
if
self
.
running
:
OriginalClockServer
.
readable
(
self
)
return
False
def
clean_shutdown_control
(
self
,
_shutdown_phase
,
time_in_this_phase
):
"""
Inform invoked method that a shutdown is in progress.
Here we:
- Prevent regular tics from being sent. This does not prevent
already-issued tics from running.
- Issue a special tic, ran asynchronously from regular tics and
asynchronously from this thread.
- Wait for that special tic to return, so that we know all clean
shutdown handlers have completely run.
- Return control to caller.
To wait for shutdown handler to return, it has been chosen to use a
semaphore scheme. It has the following drawbacks:
- It is intrusive: we need to hook foreign classes, since it's not
the way things happen with regular zope data exchange.
- We can't get what the shutdown handler returned (http return code,
page content, ...) so we will never take Lifetime's veto. So shutdown
handler must block until shutdown is complete, which is not how
clean_shutdown_control is supposed to work. Note though that it is a
design weakness in clean_shutdown_control, since some shutdown
handlers might not have finshed their job at the time process gets
closed.
"""
self
.
running
=
False
if
self
.
shutdown_method
is
not
None
:
# XXX: should use a float for time representation
method
=
'%s?phase:int=%i&time_in_phase:float=%f'
%
\
(
self
.
shutdown_method
,
_shutdown_phase
,
time_in_this_phase
)
stdin
=
StringIO
.
StringIO
()
request_string
=
'GET %s HTTP/1.0'
%
(
method
,
)
request
=
http_request
(
DummyChannel
(
self
),
request_string
,
'GET'
,
method
,
'1.0'
,
self
.
headers
)
environment
=
self
.
get_env
(
request
)
response
=
make_response
(
request
,
environment
)
# Hook response._finish to get a notification when request is over.
def
_finish
():
response
.
__class__
.
_finish
(
response
)
wait_for_close_lock
.
release
()
response
.
_finish
=
_finish
# (end of hook)
zope_request
=
HTTPRequest
(
stdin
,
environment
,
response
)
wait_for_close_lock
.
acquire
()
self
.
zhandler
(
'Zope2'
,
zope_request
,
response
)
self
.
log_info
(
'ClockServer: Waiting for shutdown handler.'
)
wait_for_close_lock
.
acquire
()
self
.
log_info
(
'ClockServer: Going on.'
)
wait_for_close_lock
.
release
()
return
0
# TODO: detect an error to allow taking the veto.
product/ClockServer/OriginalClockServer.py
deleted
100644 → 0
View file @
07a136ec
##############################################################################
#
# Copyright (c) 2005 Chris McDonough. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (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
posixpath
import
os
import
socket
import
time
import
StringIO
import
asyncore
from
ZServer.medusa.http_server
import
http_request
from
ZServer.medusa.default_handler
import
unquote
from
ZServer.PubCore
import
handle
from
ZServer.HTTPResponse
import
make_response
from
ZPublisher.HTTPRequest
import
HTTPRequest
def
timeslice
(
period
,
when
=
None
,
t
=
time
.
time
):
if
when
is
None
:
when
=
t
()
return
when
-
(
when
%
period
)
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
):
# prototype request environment
_ENV
=
dict
(
REQUEST_METHOD
=
'GET'
,
SERVER_PORT
=
'Clock'
,
SERVER_NAME
=
'Zope Clock Server'
,
SERVER_SOFTWARE
=
'Zope'
,
SERVER_PROTOCOL
=
'HTTP/1.0'
,
SCRIPT_NAME
=
''
,
GATEWAY_INTERFACE
=
'CGI/1.1'
,
REMOTE_ADDR
=
'0'
)
# required by ZServer
SERVER_IDENT
=
'Zope Clock'
def
__init__
(
self
,
method
,
period
=
60
,
user
=
None
,
password
=
None
,
host
=
None
,
logger
=
None
,
handler
=
None
):
self
.
period
=
period
self
.
method
=
method
self
.
last_slice
=
timeslice
(
period
)
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
=
(
'%s:%s'
%
(
user
,
password
)).
encode
(
'base64'
)
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
))
if
handler
is
None
:
# for unit testing
handler
=
handle
self
.
zhandler
=
handler
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
=
self
.
_ENV
.
copy
()
(
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
[
'PATH_INFO'
]
=
'/'
+
path
env
[
'PATH_TRANSLATED'
]
=
posixpath
.
normpath
(
posixpath
.
join
(
os
.
getcwd
(),
env
[
'PATH_INFO'
]))
if
query
:
env
[
'QUERY_STRING'
]
=
query
env
[
'channel.creation_time'
]
=
time
.
time
()
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
!=
self
.
last_slice
:
# no need for threadsafety here, as we're only ever in one thread
self
.
last_slice
=
slice
req
,
zreq
,
resp
=
self
.
get_requests_and_response
()
self
.
zhandler
(
'Zope2'
,
zreq
,
resp
)
return
False
def
handle_read
(
self
):
return
True
def
handle_write
(
self
):
self
.
log_info
(
'unexpected write event'
,
'warning'
)
return
True
def
writable
(
self
):
return
False
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'
)
product/ClockServer/README
deleted
100644 → 0
View file @
07a136ec
This is an unnoficial Zope 2.8 backport of official Zope's ClockServer.
Status of initial checkin compared to official version:
__init__.py
Locally created.
ClockServer.py
Locally created.
component.xml
Fix component prefix.
datatypes.py
Import ServerFactory (originaly locally defined).
Fix ClockServer class import.
OriginalClockServer.py
Unchanged original ClockServer.py.
README
Locally created.
To enable it, add (and adapt) the following to your zope.conf:
%import Products.ClockServer
<clock-server>
# starts a clock which calls /foo/bar every 30 seconds
method /foo/bar
period 30
user admin
password 123
</clock-server>
ERP5 users: You are strongly encouraged to kee TimerService (but to stop using
timerserver) and use the following configuration:
method /Control_Panel/timer_service/process_timer?interval:int=5
shutdown_method /Control_Panel/timer_service/process_shutdown
period 5
Note: Because ClockServer uses asyncore's "readable" method polling,
configured frequency is only a maximum value. Minimum freqency depends on
asyncore configuration (one wakeup every 30s on my machine). If there is
activity on Zope's sockets, frequency will increase.
This ClockServer is extended (see ClockServer.py) to propagate shutdown
notification to configured method, by pasing it extra parameters.
This allows method to put shutdown sequence on hold (but not interrupt it).
Also, note that it must not be abused: it's both bad to make user wait, and
there are some timeouts killing Zope if it takes too long to stop.
product/ClockServer/__init__.py
deleted
100644 → 0
View file @
07a136ec
product/ClockServer/component.xml
deleted
100644 → 0
View file @
07a136ec
<component
prefix=
"Products.ClockServer.datatypes"
>
<sectiontype
name=
"clock-server"
datatype=
".ClockServerFactory"
implements=
"ZServer.server"
>
<key
name=
"method"
datatype=
"string"
>
<description>
The traversal path (from the Zope root) to an
executable Zope method (Python Script, external method, product
method, etc). The method must take no arguments. Ex: "/site/methodname"
</description>
</key>
<key
name=
"shutdown_method"
datatype=
"string"
>
<description>
The traversal path (from the Zope root) to an
executable Zope method (Python Script, external method, product
method, etc). The method must take the following arguments:
phase (number)
Shutdown phase number.
See Lifetime.py .
time_in_phase (number)
Time spent in current phase, in seconds.
Given method path must not contain any argument. Ex: "/site/methodname"
</description>
</key>
<key
name=
"period"
datatype=
"integer"
default=
"60"
>
<description>
The number of seconds between each clock "tick" (and
thus each call to the above "method"). The lowest number
providable here is typically 30 (this is the asyncore mainloop
"timeout" value). The default is 60. Ex: "30"
</description>
</key>
<key
name=
"user"
datatype=
"string"
>
<description>
A zope username. Ex: "admin"
</description>
</key>
<key
name=
"password"
datatype=
"string"
>
<description>
The password for the zope username provided above. Careful: this
is obviously not encrypted in the config file. Ex: "123"
</description>
</key>
<key
name=
"host"
datatype=
"string"
>
<description>
The hostname passed in via the "Host:" header in the
faux request. Could be useful if you have virtual host rules
set up inside Zope itself. Ex: "www.example.com"
</description>
</key>
</sectiontype>
</component>
product/ClockServer/datatypes.py
deleted
100644 → 0
View file @
07a136ec
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (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.
#
##############################################################################
from
ZServer.datatypes
import
ServerFactory
class
ClockServerFactory
(
ServerFactory
):
def
__init__
(
self
,
section
):
ServerFactory
.
__init__
(
self
)
self
.
method
=
section
.
method
self
.
shutdown_method
=
section
.
shutdown_method
self
.
period
=
section
.
period
self
.
user
=
section
.
user
self
.
password
=
section
.
password
self
.
hostheader
=
section
.
host
self
.
host
=
None
# appease configuration machinery
def
create
(
self
):
from
Products.ClockServer.ClockServer
import
ClockServer
from
ZServer.AccessLogger
import
access_logger
return
ClockServer
(
self
.
method
,
self
.
period
,
self
.
user
,
self
.
password
,
self
.
hostheader
,
access_logger
,
shutdown_method
=
self
.
shutdown_method
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment