Initial import to Tizen
[profile/ivi/python-twisted.git] / doc / core / examples / longex2.py
1 """Example of doing arbitarily long calculations nicely in Twisted.
2
3 This is also a simple demonstration of twisted.protocols.basic.LineReceiver.
4 This example uses generators to do the calculation. It also tries to be
5 a good example in division of responsibilities:
6 - The protocol handles the wire layer, reading in lists of numbers
7   and writing out the result.
8 - The factory decides on policy, and has relatively little knowledge
9   of the details of the protocol. Other protocols can use the same
10   factory class by intantiating and setting .protocol
11 - The factory does little job itself: it is mostly a policy maker.
12   The 'smarts' are in free-standing functions which are written
13   for flexibility.
14
15 The goal is for minimal dependencies:
16 - You can use runIterator to run any iterator inside the Twisted
17   main loop.
18 - You can use multiply whenever you need some way of multiplying
19   numbers such that the multiplications will happen asynchronously,
20   but it is your responsibility to schedule the multiplications.
21 - You can use the protocol with other factories to implement other
22   functions that apply to arbitrary lists of longs.
23 - You can use the factory with other protocols for support of legacy
24   protocols. In fact, the factory does not even have to be used as
25   a protocol factory. Here are easy ways to support the operation
26   over XML-RPC and PB.
27
28 class Multiply(xmlrpc.XMLRPC):
29     def __init__(self): self.factory = Multiplication()
30     def xmlrpc_multiply(self, *numbers):
31         return self.factory.calc(map(long, numbers))
32
33 class Multiply(pb.Referencable):
34     def __init__(self): self.factory = Multiplication()
35     def remote_multiply(self, *numbers):
36         return self.factory.calc(map(long, numbers))
37
38 Note:
39 Multiplying zero numbers is a perfectly sensible operation, and the
40 result is 1. In that, this example departs from doc/examples/longex.py,
41 which errors out when trying to do this.
42 """
43 from __future__ import generators
44 from twisted.protocols import basic
45 from twisted.internet import defer, protocol
46
47 def runIterator(reactor, iterator):
48     try:
49         iterator.next()
50     except StopIteration:
51         pass
52     else:
53         reactor.callLater(0, runIterator, reactor, iterator)
54
55 def multiply(numbers):
56     d = defer.Deferred()
57     def _():
58         acc = 1
59         while numbers:
60             acc *= numbers.pop()
61             yield None
62         d.callback(acc)
63     return d, _()
64
65 class Numbers(basic.LineReceiver):
66     """Protocol for reading lists of numbers and manipulating them.
67
68     It receives a list of numbers (seperated by whitespace) on a line, and
69     writes back the answer.  The exact algorithm to use depends on the
70     factory. It should return an str-able Deferred.
71     """
72     def lineReceived(self, line):
73         try:
74             numbers = map(long, line.split())
75         except ValueError:
76             self.sendLine('Error.')
77             return
78         deferred = self.factory.calc(numbers)
79         deferred.addCallback(str)
80         deferred.addCallback(self.sendLine)
81
82 class Multiplication(protocol.ServerFactory):
83     """Factory for multiplying numbers.
84
85     It provides a function which calculates the multiplication
86     of a list of numbers. The function destroys its input.
87     Note that instances of this factory can use other formats
88     for transmitting the number lists, as long as they set
89     correct protoocl values.
90     """
91     protocol = Numbers
92     def calc(self, numbers):
93         deferred, iterator = multiply(numbers)
94         from twisted.internet import reactor
95         runIterator(reactor, iterator)
96         return deferred
97
98 if __name__ == '__main__':
99     from twisted.internet import reactor
100     reactor.listenTCP(1234, Multiplication())
101     reactor.run()