1
# -*- test-case-name: twisted.test.test_application,twisted.test.test_cooperator -*-
3
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
4
# See LICENSE for details.
8
"""Reactor-based Services
10
Here are services to run clients, servers and periodic services using
13
This module (dynamically) defines various Service subclasses that let
14
you represent clients and servers in a Service hierarchy.
19
UNIXServer, UNIXClient,
22
UNIXDatagramServer, UNIXDatagramClient,
25
These classes take arbitrary arguments in their constructors and pass
26
them straight on to their respective reactor.listenXXX or
27
reactor.connectXXX calls.
29
For example, the following service starts a web server on port 8080:
30
C{TCPServer(8080, server.Site(r))}. See the documentation for the
31
reactor.listen/connect* methods for more information.
33
API Stability: unstable
35
Maintainer: U{Moshe Zadka<mailto:moshez@twistedmatrix.com>}
38
from twisted.python import log
39
from twisted.application import service
40
from twisted.internet import task
43
class _VolatileDataService(service.Service):
47
def __getstate__(self):
48
d = service.Service.__getstate__(self)
49
for attr in self.volatile:
54
class _AbstractServer(_VolatileDataService):
62
def __init__(self, *args, **kwargs):
66
def privilegedStartService(self):
67
service.Service.privilegedStartService(self)
68
self._port = self._getPort()
70
def startService(self):
71
service.Service.startService(self)
72
if self._port is None:
73
self._port = self._getPort()
75
def stopService(self):
76
service.Service.stopService(self)
77
# TODO: if startup failed, should shutdown skip stopListening?
79
if self._port is not None:
80
d = self._port.stopListening()
85
from twisted.internet import reactor
86
return getattr(reactor, 'listen'+self.method)(*self.args, **self.kwargs)
88
class _AbstractClient(_VolatileDataService):
90
volatile = ['_connection']
95
def __init__(self, *args, **kwargs):
99
def startService(self):
100
service.Service.startService(self)
101
self._connection = self._getConnection()
103
def stopService(self):
104
service.Service.stopService(self)
105
if self._connection is not None:
106
self._connection.disconnect()
109
def _getConnection(self):
110
from twisted.internet import reactor
111
return getattr(reactor, 'connect'+self.method)(*self.args,
118
"""Connect to %(tran)s
120
Call reactor.connect%(method)s when the service starts, with the
121
arguments given to the constructor.
124
"""Serve %(tran)s clients
126
Call reactor.listen%(method)s when the service starts, with the
127
arguments given to the constructor. When the service stops,
128
stop listening. See twisted.internet.interfaces for documentation
129
on arguments to the reactor method.
134
for tran in 'Generic TCP UNIX SSL UDP UNIXDatagram Multicast'.split():
135
for side in 'Server Client'.split():
136
if tran == "Multicast" and side == "Client":
138
base = globals()['_Abstract'+side]
139
method = {'Generic': 'With'}.get(tran, tran)
140
doc = _doc[side]%vars()
141
klass = new.classobj(tran+side, (base,),
142
{'method': method, '__doc__': doc})
143
globals()[tran+side] = klass
146
class TimerService(_VolatileDataService):
148
"""Service to periodically call a function
150
Every C{step} seconds call the given function with the given arguments.
151
The service starts the calls when it starts, and cancels them
157
def __init__(self, step, callable, *args, **kwargs):
159
self.call = (callable, args, kwargs)
161
def startService(self):
162
service.Service.startService(self)
163
callable, args, kwargs = self.call
164
# we have to make a new LoopingCall each time we're started, because
165
# an active LoopingCall remains active when serialized. If
166
# LoopingCall were a _VolatileDataService, we wouldn't need to do
168
self._loop = task.LoopingCall(callable, *args, **kwargs)
169
self._loop.start(self.step, now=True).addErrback(self._failed)
171
def _failed(self, why):
172
# make a note that the LoopingCall is no longer looping, so we don't
173
# try to shut it down a second time in stopService. I think this
174
# should be in LoopingCall. -warner
175
self._loop.running = False
178
def stopService(self):
179
if self._loop.running:
181
return service.Service.stopService(self)
185
class CooperatorService(service.Service):
187
Simple L{service.IService} which starts and stops a L{twisted.internet.task.Cooperator}.
190
self.coop = task.Cooperator(started=False)
193
def coiterate(self, iterator):
194
return self.coop.coiterate(iterator)
197
def startService(self):
201
def stopService(self):
206
__all__ = (['TimerService', 'CooperatorService'] +
208
for tran in 'Generic TCP UNIX SSL UDP UNIXDatagram Multicast'.split()
209
for side in 'Server Client'.split()])