root/sandbox/therve/erlang.xhtml

Revision 22738, 7.5 KB (checked in by therve, 2 years ago)

Add missing argument

Line 
1<?xml version="1.0"?>
2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4
5<html xmlns="http://www.w3.org/1999/xhtml">
6  <head>
7    <title>Twisted as an Erlang node</title>
8  </head>
9
10  <body>
11    <h1>Twisted as an Erlang node</h1>
12
13    <h2>Prequesites</h2>
14
15    <p>
16        In this document, we'll assume that you have a basic knowledge of
17        Twisted (how to create a client, how to create a server, what is
18        the protocol/factory mechanism, what is a deferred), and of Erlang
19        (what is a node, what is the EPMD, what are the basic types). Please
20        refer to the respective documentation if it's not the case.
21    </p>
22
23    <h2>Invoking methods on an Erlang node</h2>
24
25    <p>
26        To create connection to an erlang node, you'll need to get the cookie
27        and create a node name. The utility functions
28        <code class="API" base="erlange.node">readCookie</code>
29        and  <code class="API" base="erlang.node">buildNodeName</code>
30        are here to help you out: the first read the cookie at the usual
31        place ($HOME/.erlang.cookie), the second append the name of the
32        host to the name you have chosen.
33    </p>
34
35    <p>
36        Then, instantiate the class
37        <code class="API" base="erlang.epmd">OneShotPortMapperFactory</code>
38        with the infos, and call connectionToNode on it. This method will:
39        <ul>
40            <li>create a connection with the EPMD</li>
41            <li>ask for the port info of the node</li>
42            <li>connect to the node</li>
43            <li>return the connected node client protocol</li>
44        </ul>
45        Once you get back the protocol instance, you can use the callRemote
46        method on its factory to make calls to the node.
47    </p>
48
49    <p>
50        If you have to make several calls to a node, don't bother keep a
51        reference to it: OneShotPortMapperFactory will keep a cache of connected
52        instances for you.
53    </p>
54
55    <pre class="python">
56from twisted.internet import reactor
57from erlang import OneShotPortMapperFactory, readCookie, buildNodeName
58
59def gotConnection(inst):
60    return inst.factory.callRemote(inst, "file", "get_cwd"
61        ).addCallback(gotResult)
62
63def gotResult(resp):
64    print "Got response", resp
65    reactor.stop()
66
67def eb(error):
68    print "Got error", error
69    reactor.stop()
70
71cookie = readCookie()
72nodeName = buildNodeName('nodename')
73epmd = OneShotPortMapperFactory(nodeName, cookie)
74epmd.connectToNode("foo").addCallback(gotConnection).addErrback(eb)
75reactor.run()
76    </pre>
77
78    <h2>Instantiating a node</h2>
79
80    <p>
81        The process for creating a node is relatively straightforward. First
82        you  create a node server factory, and make it listen on an arbitrary
83        port. Then you create client connection to the EPMD, giving the server
84        port as argument. This process is simplified by the method publish
85        of the EPMD factory.
86
87        The EPMD should be started outside Twisted. It is
88        started automatically when you start an erlang application.
89    </p>
90
91    <pre class="python">
92from twisted.internet import reactor
93from erlang import PersistentPortMapperFactory, readCookie, buildNodeName
94
95cookie = readCookie()
96nodeName = buildNodeName('nodename')
97epmd = PersistentPortMapperFactory(nodeName, cookie)
98epmd.publish()
99reactor.run()
100    </pre>
101
102    <p>
103        Once you have the node name and the cookie (see above to understand
104        how), you create a
105        <code class="API" base="erlang.epmd">PersistentPortMapperFactory</code>
106        instance, and call publish on it: it will create the node, make it
107        listen on an arbitrary port, and connect to the EPMD to publish the
108        information.
109    </p>
110
111    <p>
112        Of course, for now it does nothing useful, so we now see how to
113        get data from an erlang nodes.
114    </p>
115
116
117    <h2>Receiving method calls from an Erlang node</h2>
118
119    <p>
120        The key method here is the method publish you've seen above: this method
121        takes a hash table of name/object. The key for this table is the
122        module used when making a call from Erlang. The value is an instance
123        of a class with methods prefixed by <code>remote_</code>.
124    </p>
125
126    <pre class="python">
127class Proxy(object):
128    def remote_bar(self, arg):
129        return arg * 2
130
131from twisted.internet import reactor
132from erlang import PersistentPortMapperFactory, readCookie, buildNodeName
133
134cookie = readCookie()
135nodeName = buildNodeName('nodename')
136epmd = PersistentPortMapperFactory(nodeName, cookie)
137epmd.publish(foo=Proxy())
138reactor.run()
139    </pre>
140
141    <p>
142        The script above define a <code>Proxy</code> with a
143        <code>remote_bar</code> method. We can publish with the keyword
144        foo, which creates a module named foo with the method bar. We can now
145        call this method in an Erlang console:
146    </p>
147
148    <pre>
149(erlang@node)1> rpc:call('nodename@node', foo, bar, [3]).
150{ok,6}
151    </pre>
152
153    <h2>An example: using a Mnesia database</h2>
154
155    <p>
156        To try the communication as client, we'll set up a mnesia database to
157        be used within a Twisted application. Please refer to the mnesia
158        documentation for further information. Note that there is nothing new
159        here: it's just a concrete example to put the things together.
160    </p>
161
162    <p>
163        First create a file named twisted.hrl with following record:
164    </p>
165
166    <pre class="erlang">
167-record(user, {id, name}).
168    </pre>
169
170    <p>
171        Then create a file named twisted.erl
172    </p>
173
174    <pre class="erlang">
175-module(twisted).
176-export([init/0, insert_user/2, get_user/1]).
177-include("twisted.hrl").
178
179init() ->
180    mnesia:create_table(user,
181                        [{attributes, record_info(fields, user)}]).
182
183insert_user(UserName, UserId) ->
184    User = #user{id=UserId, name=UserName},
185    Fun = fun() ->
186            mnesia:write(User)
187        end,
188    mnesia:transaction(Fun).
189
190get_user(UserId) ->
191    Fun = fun() ->
192            [User] = mnesia:read(user, UserId, read),
193            User
194        end,
195    case mnesia:transaction(Fun) of
196        {atomic, User} ->
197            User
198    end.
199    </pre>
200
201    <p>
202        Now fire an erlang interpreter. We'll compile the twisted file, start
203        the mnesia database, create the table, and insert a test user.
204    </p>
205
206    <pre class="shell">
207$ erl -sname twisted_mnesia
208
209(twisted_mnesia@localhost)1> c(twisted).
210{ok,twisted}
211(twisted_mnesia@localhost)2> mnesia:start().
212ok
213(twisted_mnesia@localhost)3> twisted:init().
214{atomic,ok}
215(twisted_mnesia@localhost)4> twisted:insert_user(test1, 1).
216{atomic,ok}
217(twisted_mnesia@localhost)5> twisted:get_user(1).
218{user,1,test1}
219    </pre>
220
221    <p>
222        The node is ready to accept our python calls.
223    </p>
224
225    <pre class="python">
226from twisted.internet import reactor
227from erlang import OneShotPortMapperFactory, readCookie, buildNodeName
228
229def gotConnection(inst):
230    return inst.factory.callRemote(inst, "twisted", "get_user", 1
231        ).addCallback(gotResult)
232
233def gotResult(resp):
234    print "Got response", resp
235    reactor.stop()
236
237def eb(error):
238    print "Got error", error
239    reactor.stop()
240
241cookie = readCookie()
242nodeName = buildNodeName('nodename')
243epmd = OneShotPortMapperFactory(nodeName, cookie)
244epmd.connectToNode("twisted_mnesia").addCallback(gotConnection).addErrback(eb)
245reactor.run()
246    </pre>
247
248    <p>
249        If everything is fine, you should get the following response:
250    </p>
251
252    <pre class="shell">
253Got response (&lt;Atom at -0x48806e54, text 'user'&gt;, 1, &lt;Atom at -0x48806e74, text 'test1'&gt;)
254    </pre>
255
256  </body>
257</html>
Note: See TracBrowser for help on using the browser.