1
# -*- test-case-name: twisted.test.test_application,twisted.test.test_cooperator -*-
3
# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
4
# See LICENSE for details.
9
Here are services to run clients, servers and periodic services using
12
This module (dynamically) defines various Service subclasses that let
13
you represent clients and servers in a Service hierarchy.
18
UNIXServer, UNIXClient,
21
UNIXDatagramServer, UNIXDatagramClient,
24
These classes take arbitrary arguments in their constructors and pass
25
them straight on to their respective reactor.listenXXX or
26
reactor.connectXXX calls.
28
For example, the following service starts a web server on port 8080:
29
C{TCPServer(8080, server.Site(r))}. See the documentation for the
30
reactor.listen/connect* methods for more information.
32
Maintainer: Moshe Zadka
35
from twisted.python import log
36
from twisted.application import service
37
from twisted.internet import task
40
class _VolatileDataService(service.Service):
44
def __getstate__(self):
45
d = service.Service.__getstate__(self)
46
for attr in self.volatile:
53
class _AbstractServer(_VolatileDataService):
55
@cvar volatile: list of attribute to remove from pickling.
56
@type volatile: C{list}
58
@ivar method: the type of method to call on the reactor, one of B{TCP},
59
B{UDP}, B{SSL} or B{UNIX}.
62
@ivar reactor: the current running reactor.
63
@type reactor: a provider of C{IReactorTCP}, C{IReactorUDP},
64
C{IReactorSSL} or C{IReactorUnix}.
66
@ivar _port: instance of port set when the service is started.
67
@type _port: a provider of C{IListeningPort}.
76
def __init__(self, *args, **kwargs):
78
if 'reactor' in kwargs:
79
self.reactor = kwargs.pop("reactor")
83
def privilegedStartService(self):
84
service.Service.privilegedStartService(self)
85
self._port = self._getPort()
88
def startService(self):
89
service.Service.startService(self)
90
if self._port is None:
91
self._port = self._getPort()
94
def stopService(self):
95
service.Service.stopService(self)
96
# TODO: if startup failed, should shutdown skip stopListening?
98
if self._port is not None:
99
d = self._port.stopListening()
106
Wrapper around the appropriate listen method of the reactor.
108
@return: the port object returned by the listen method.
109
@rtype: an object providing L{IListeningPort}.
111
if self.reactor is None:
112
from twisted.internet import reactor
114
reactor = self.reactor
115
return getattr(reactor, 'listen%s' % (self.method,))(
116
*self.args, **self.kwargs)
120
class _AbstractClient(_VolatileDataService):
122
@cvar volatile: list of attribute to remove from pickling.
123
@type volatile: C{list}
125
@ivar method: the type of method to call on the reactor, one of B{TCP},
126
B{UDP}, B{SSL} or B{UNIX}.
129
@ivar reactor: the current running reactor.
130
@type reactor: a provider of C{IReactorTCP}, C{IReactorUDP},
131
C{IReactorSSL} or C{IReactorUnix}.
133
@ivar _connection: instance of connection set when the service is started.
134
@type _connection: a provider of C{IConnector}.
136
volatile = ['_connection']
142
def __init__(self, *args, **kwargs):
144
if 'reactor' in kwargs:
145
self.reactor = kwargs.pop("reactor")
149
def startService(self):
150
service.Service.startService(self)
151
self._connection = self._getConnection()
154
def stopService(self):
155
service.Service.stopService(self)
156
if self._connection is not None:
157
self._connection.disconnect()
161
def _getConnection(self):
163
Wrapper around the appropriate connect method of the reactor.
165
@return: the port object returned by the connect method.
166
@rtype: an object providing L{IConnector}.
168
if self.reactor is None:
169
from twisted.internet import reactor
171
reactor = self.reactor
172
return getattr(reactor, 'connect%s' % (self.method,))(
173
*self.args, **self.kwargs)
179
"""Connect to %(tran)s
181
Call reactor.connect%(method)s when the service starts, with the
182
arguments given to the constructor.
185
"""Serve %(tran)s clients
187
Call reactor.listen%(method)s when the service starts, with the
188
arguments given to the constructor. When the service stops,
189
stop listening. See twisted.internet.interfaces for documentation
190
on arguments to the reactor method.
195
for tran in 'Generic TCP UNIX SSL UDP UNIXDatagram Multicast'.split():
196
for side in 'Server Client'.split():
197
if tran == "Multicast" and side == "Client":
199
base = globals()['_Abstract'+side]
200
method = {'Generic': 'With'}.get(tran, tran)
201
doc = _doc[side]%vars()
202
klass = new.classobj(tran+side, (base,),
203
{'method': method, '__doc__': doc})
204
globals()[tran+side] = klass
207
class TimerService(_VolatileDataService):
209
"""Service to periodically call a function
211
Every C{step} seconds call the given function with the given arguments.
212
The service starts the calls when it starts, and cancels them
218
def __init__(self, step, callable, *args, **kwargs):
220
self.call = (callable, args, kwargs)
222
def startService(self):
223
service.Service.startService(self)
224
callable, args, kwargs = self.call
225
# we have to make a new LoopingCall each time we're started, because
226
# an active LoopingCall remains active when serialized. If
227
# LoopingCall were a _VolatileDataService, we wouldn't need to do
229
self._loop = task.LoopingCall(callable, *args, **kwargs)
230
self._loop.start(self.step, now=True).addErrback(self._failed)
232
def _failed(self, why):
233
# make a note that the LoopingCall is no longer looping, so we don't
234
# try to shut it down a second time in stopService. I think this
235
# should be in LoopingCall. -warner
236
self._loop.running = False
239
def stopService(self):
240
if self._loop.running:
242
return service.Service.stopService(self)
246
class CooperatorService(service.Service):
248
Simple L{service.IService} which starts and stops a L{twisted.internet.task.Cooperator}.
251
self.coop = task.Cooperator(started=False)
254
def coiterate(self, iterator):
255
return self.coop.coiterate(iterator)
258
def startService(self):
262
def stopService(self):
267
__all__ = (['TimerService', 'CooperatorService'] +
269
for tran in 'Generic TCP UNIX SSL UDP UNIXDatagram Multicast'.split()
270
for side in 'Server Client'.split()])