-
Notifications
You must be signed in to change notification settings - Fork 0
/
README
182 lines (135 loc) · 5.85 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
eixx - Erlang C++ Interface Library
===================================
This library provides a set of classes for convenient marshaling
of Erlang terms between processes as well as connecting to other
distributed Erlang nodes from a C++ application.
The marshaling classes are built on top of ei library included in
{@link http://www.erlang.org/doc/apps/erl_interface erl_interface}.
It is largely inspired by the {@link http://code.google.com/p/epi epi}
project, but is a complete rewrite with many new features and
optimization enhancements.
This library adds on the following features:
- Use of reference-counted smart pointers for complex terms and
by-value copied simple terms (e.i. integers, doubles, bool, atoms).
- Ability to provide custom memory allocators.
- Encoding/decoding of nested terms using a single function call
(eterm::encode() and eterm::eterm() constructor).
- Global atom table for fast manipulation of atoms.
The library consists of two separate parts:
- Term marshaling (included by marshal.hpp or eixx.hpp)
- Distributed node connectivity (included by connect.hpp or eixx.hpp)
The connectivity library implements a richer set of features than
what's available in erl_interface - it fully supports process
linking and monitoring. The library is fully asynchronous and allows
handling many connections and mailboxes in one OS thread.
Ths library is dependend on {@link http://www.boost.org BOOST}
project and erl_interface, which is a part of the
{@link www.erlang.org Erlang} distribution.
Downloading
===========
Repository location: http://github.com/saleyn/eixx
$ git clone [email protected]:saleyn/eixx.git
Building
========
Make sure that you have autoconf-archive package installed:
http://www.gnu.org/software/autoconf-archive
Run:
$ ./bootstrap
$ ./configure --with-boost="/path/to/boost" [--with-erlang="/path/to/erlang"] \
[--prefix="/target/install/path"]
$ make
$ make install # Default install path is ./install
Author
======
Serge Aleynikov <saleyn at gmail dot com>
LICENSE
=======
GNU Lesser General Public License
Example
=======
Here's an example use of the eixx library:
void on_message(otp_mailbox& a_mbox, boost::system::error_code& ec) {
// On timeout ec == boost::asio::error::timeout
if (ec == boost::asio::error::timeout) {
std::cout << "Mailbox " << a_mbox.self() << " timeout: "
<< ec.message() << std::endl;
} else {
// The mailbox has a queue of transport messages.
// Dequeue next message from the mailbox.
boost::scoped_ptr<transport_msg> dist_msg;
while (dist_msg.reset(a_mbox.receive())) {
std::cout << "Main mailbox got a distributed transport message:\n "
<< *p << std::endl;
// Use the following pattern for a pattern match on the message.
static const eterm s_pattern = eterm::format("{From, {command, Cmd}}");
varbind binding;
if (s_pattern.match(dist_msg->msg(), &binding)) {
const eterm* cmd = binding->find("Cmd");
std::cout << "Got a command " << *cmd << std::endl;
// Process command, e.g.:
// process_command(binding["From"]->to_pid(), *cmd);
}
}
}
// Schedule next async receive of a message (can also provide a timeout).
a_mbox.async_receive(&on_message);
}
void on_connect(otp_connection* a_con, const std::string& a_error) {
if (!a_error.empty()) {
std::cout << a_error << std::endl;
return;
}
// Illustrate creation of Erlang terms.
eterm t1 = eterm::format("{ok, ~i}", 10);
eterm t2 = tuple::make(10, 1.0, atom("test"), "abc");
eterm t3("This is a string");
eterm t4(tuple::make(t1, t2, t3));
otp_node* node = a_con->node();
otp_mailbox* mbox = node->get_mailbox("main");
// Send a message: {{ok, 10}, {10, 1.0, 'test', "abc"}, "This is a string"}
// to an Erlang process named 'test' running
// on node "abc@myhost"
node->send(mbox.self(), a_con->remote_node(), atom("test"), t4);
}
int main() {
use namespace eixx;
otp_node node("abc");
otp_mailbox* mbox = node.create_mailbox("main");
node.connect(&on_connect, "abc@myhost");
// Asynchronously receive a message with a deadline of 10s:
mbox->async_receive(&on_message, 10000);
node.run();
}
Testing distributed transport
=============================
$ make
Run tests:
$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./test_eterm
Test distributed transport:
$ cd src
# In this example we assume the host name of "fc12".
[Shell A]$ erl -sname abc
(abc@fc12)1> register(test, self()).
[Shell B]$ ./test_node -n a@fc12 -r abc@fc12
Connected to node: abc@fc12
I/O server got a message:
#DistMsg{
type=SEND,
cntrl={2,'',#Pid<[email protected]>},
msg={io_request,#Pid<[email protected]>,#Pid<[email protected]>,
{put_chars,<<"This is a test string">>}}}
The message above is a result of the on_connect() handler in test_node.cpp
issuing an rpc call to the abc@fc12 node of `io:put_chars("This is a test
string")'. This the call selects a locally registered process called
'io_server' as the group leader for this rpc call, the I/O output is sent
to that mailbox.
Now you can try to send a message from Erlang to the 'main' mailbox
registered on the C++ node:
[Shell A]
(abc@fc12)2> {main, a@fc12} ! "This is a test!".
[Shell B]
Main mailbox got a message:
#DistMsg{
type=REG_SEND,
cntrl={6,#Pid<[email protected]>,'',main},
msg="This is a test!"}