"""Reactor-based Services
Here are services to run clients, servers and periodic services using
the reactor.
API Stability: unstable
Maintainer: U{Moshe Zadka<mailto:moshez@twistedmatrix.com>}
"""
from twisted.python import log
from twisted.application import service
class _VolatileDataService(service.Service):
volatile = []
def __getstate__(self):
d = service.Service.__getstate__(self)
for attr in self.volatile:
if d.has_key(attr):
del d[attr]
return d
class _AbstractServer(_VolatileDataService):
privileged = True
volatile = ['_port']
method = None
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def privilegedStartService(self):
service.Service.privilegedStartService(self)
self._port = self._getPort()
def startService(self):
service.Service.startService(self)
if not hasattr(self,'_port'):
self._port = self._getPort()
def stopService(self):
service.Service.stopService(self)
d = self._port.stopListening()
del self._port
return d
def _getPort(self):
from twisted.internet import reactor
return getattr(reactor, 'listen'+self.method)(*self.args, **self.kwargs)
class _AbstractClient(_VolatileDataService):
volatile = ['_connection']
method = None
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
def startService(self):
service.Service.startService(self)
self._connection = self._getConnection()
def stopService(self):
service.Service.stopService(self)
def _getConnection(self):
from twisted.internet import reactor
return getattr(reactor, 'connect'+self.method)(*self.args,
**self.kwargs)
_doc={
'Client':
"""Connect to %(tran)s
Call reactor.connect%(method)s when the service starts, with the
arguments given to the constructor.
""",
'Server':
"""Serve %(tran)s clients
Call reactor.listen%(method)s when the service starts, with the
arguments given to the constructor. When the service stops,
stop listening. See twisted.internet.interfaces for documentation
on arguments to the reactor method.
""",
}
import new
for tran in 'Generic TCP UNIX SSL UDP UNIXDatagram Multicast'.split():
for side in 'Server Client'.split():
base = globals()['_Abstract'+side]
method = {'Generic': 'With'}.get(tran, tran)
doc = _doc[side]%vars()
klass = new.classobj(tran+side, (base,),
{'method': method, '__doc__': doc})
globals()[tran+side] = klass
class TimerService(_VolatileDataService):
volatile = ['_call']
"""Service to periodically call a function
Every C{step} seconds call the given function with the given arguments.
The service starts the calls when it starts, and cancels them
when it stops.
"""
def __init__(self, step, callable, *args, **kwargs):
self.step = step
from twisted.internet.task import LoopingCall
self.loop = LoopingCall(callable, *args, **kwargs)
def startService(self):
from twisted.internet import reactor
service.Service.startService(self)
self._call = reactor.callLater(self.step, self._startLoop, self.step)
def _startLoop(self, step):
self._call = None
self.loop.start(step).addBoth(self._cleanupLoop).addErrback(log.err)
def _cleanupLoop(self, result):
self.loop = None
return result
def stopService(self):
service.Service.stopService(self)
if self._call is not None:
_call, self._call = self._call, None
_call.cancel()
elif self.loop is not None:
loop, self.loop = self.loop, None
loop.stop()
__all__ = (['TimerService']+
[tran+side
for tran in 'Generic TCP UNIX SSL UDP UNIXDatagram Multicast'.split()
for side in 'Server Client'.split()])