~landscape/zope3/ztk-1.1.3

« back to all changes in this revision

Viewing changes to src/twisted/application/internet.py

  • Committer: Andreas Hasenack
  • Date: 2009-07-20 17:49:16 UTC
  • Revision ID: andreas@canonical.com-20090720174916-g2tn6qmietz2hn0u
Revert twisted removal, it breaks several dozen tests [trivial]

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.test.test_application,twisted.test.test_cooperator -*-
 
2
 
 
3
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
 
4
# See LICENSE for details.
 
5
 
 
6
#
 
7
 
 
8
"""Reactor-based Services
 
9
 
 
10
Here are services to run clients, servers and periodic services using
 
11
the reactor.
 
12
 
 
13
This module (dynamically) defines various Service subclasses that let
 
14
you represent clients and servers in a Service hierarchy.
 
15
 
 
16
They are as follows::
 
17
 
 
18
  TCPServer, TCPClient,
 
19
  UNIXServer, UNIXClient,
 
20
  SSLServer, SSLClient,
 
21
  UDPServer, UDPClient,
 
22
  UNIXDatagramServer, UNIXDatagramClient,
 
23
  MulticastServer
 
24
 
 
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.
 
28
 
 
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.
 
32
 
 
33
API Stability: unstable
 
34
 
 
35
Maintainer: U{Moshe Zadka<mailto:moshez@twistedmatrix.com>}
 
36
"""
 
37
 
 
38
from twisted.python import log
 
39
from twisted.application import service
 
40
from twisted.internet import task
 
41
 
 
42
 
 
43
class _VolatileDataService(service.Service):
 
44
 
 
45
    volatile = []
 
46
 
 
47
    def __getstate__(self):
 
48
        d = service.Service.__getstate__(self)
 
49
        for attr in self.volatile:
 
50
            if d.has_key(attr):
 
51
                del d[attr]
 
52
        return d
 
53
 
 
54
class _AbstractServer(_VolatileDataService):
 
55
 
 
56
    privileged = True
 
57
    volatile = ['_port']
 
58
    method = None
 
59
 
 
60
    _port = None
 
61
 
 
62
    def __init__(self, *args, **kwargs):
 
63
        self.args = args
 
64
        self.kwargs = kwargs
 
65
 
 
66
    def privilegedStartService(self):
 
67
        service.Service.privilegedStartService(self)
 
68
        self._port = self._getPort()
 
69
 
 
70
    def startService(self):
 
71
        service.Service.startService(self)
 
72
        if self._port is None:
 
73
            self._port = self._getPort()
 
74
 
 
75
    def stopService(self):
 
76
        service.Service.stopService(self)
 
77
        # TODO: if startup failed, should shutdown skip stopListening?
 
78
        # _port won't exist
 
79
        if self._port is not None:
 
80
            d = self._port.stopListening()
 
81
            del self._port
 
82
            return d
 
83
 
 
84
    def _getPort(self):
 
85
        from twisted.internet import reactor
 
86
        return getattr(reactor, 'listen'+self.method)(*self.args, **self.kwargs)
 
87
 
 
88
class _AbstractClient(_VolatileDataService):
 
89
 
 
90
    volatile = ['_connection']
 
91
    method = None
 
92
 
 
93
    _connection = None
 
94
 
 
95
    def __init__(self, *args, **kwargs):
 
96
        self.args = args
 
97
        self.kwargs = kwargs
 
98
 
 
99
    def startService(self):
 
100
        service.Service.startService(self)
 
101
        self._connection = self._getConnection()
 
102
 
 
103
    def stopService(self):
 
104
        service.Service.stopService(self)
 
105
        if self._connection is not None:
 
106
            self._connection.disconnect()
 
107
            del self._connection
 
108
 
 
109
    def _getConnection(self):
 
110
        from twisted.internet import reactor
 
111
        return getattr(reactor, 'connect'+self.method)(*self.args,
 
112
                                                       **self.kwargs)
 
113
 
 
114
 
 
115
 
 
116
_doc={
 
117
'Client':
 
118
"""Connect to %(tran)s
 
119
 
 
120
Call reactor.connect%(method)s when the service starts, with the
 
121
arguments given to the constructor.
 
122
""",
 
123
'Server':
 
124
"""Serve %(tran)s clients
 
125
 
 
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.
 
130
""",
 
131
}
 
132
 
 
133
import new
 
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":
 
137
            continue
 
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
 
144
 
 
145
 
 
146
class TimerService(_VolatileDataService):
 
147
 
 
148
    """Service to periodically call a function
 
149
 
 
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
 
152
    when it stops.
 
153
    """
 
154
 
 
155
    volatile = ['_loop']
 
156
 
 
157
    def __init__(self, step, callable, *args, **kwargs):
 
158
        self.step = step
 
159
        self.call = (callable, args, kwargs)
 
160
 
 
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
 
167
        # this.
 
168
        self._loop = task.LoopingCall(callable, *args, **kwargs)
 
169
        self._loop.start(self.step, now=True).addErrback(self._failed)
 
170
 
 
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
 
176
        log.err(why)
 
177
 
 
178
    def stopService(self):
 
179
        if self._loop.running:
 
180
            self._loop.stop()
 
181
        return service.Service.stopService(self)
 
182
 
 
183
 
 
184
 
 
185
class CooperatorService(service.Service):
 
186
    """
 
187
    Simple L{service.IService} which starts and stops a L{twisted.internet.task.Cooperator}.
 
188
    """
 
189
    def __init__(self):
 
190
        self.coop = task.Cooperator(started=False)
 
191
 
 
192
 
 
193
    def coiterate(self, iterator):
 
194
        return self.coop.coiterate(iterator)
 
195
 
 
196
 
 
197
    def startService(self):
 
198
        self.coop.start()
 
199
 
 
200
 
 
201
    def stopService(self):
 
202
        self.coop.stop()
 
203
 
 
204
 
 
205
 
 
206
__all__ = (['TimerService', 'CooperatorService'] +
 
207
           [tran+side
 
208
         for tran in 'Generic TCP UNIX SSL UDP UNIXDatagram Multicast'.split()
 
209
         for side in 'Server Client'.split()])