1
0
mirror of https://github.com/ubf/ubf.git synced 2026-04-16 17:55:48 +00:00

integrate Thrift binary encoder/decoder; add pbf and abf stubs

This commit is contained in:
Joseph Wayne Norton
2010-04-22 00:12:47 +09:00
parent 5c1d491162
commit d27201734d
23 changed files with 997 additions and 147 deletions

48
edoc/abf.html Normal file
View File

@@ -0,0 +1,48 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Module abf</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module abf</h1>
<ul class="index"><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#decode-3">decode/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode-4">decode/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode_init-0">decode_init/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode-3">encode/3</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="decode-3">decode/3</a></h3>
<div class="spec">
<p><tt>decode(X, Mod, State) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="decode-4">decode/4</a></h3>
<div class="spec">
<p><tt>decode(X, Mod, Cont, State) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="decode_init-0">decode_init/0</a></h3>
<div class="spec">
<p><tt>decode_init() -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="encode-3">encode/3</a></h3>
<div class="spec">
<p><tt>encode(X, Mod, State) -&gt; any()</tt></p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated EDoc, $Id$</i></p>
</body>
</html>

53
edoc/abf_driver.html Normal file
View File

@@ -0,0 +1,53 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Module abf_driver</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module abf_driver</h1>
<ul class="index"><li><a href="#description">Description</a></li><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>Protocol driver process for Avro protocol sessions.
<h2><a name="description">Description</a></h2><p>Protocol driver process for Avro protocol sessions.</p>
The process executing <code>loop()</code> in this module is represented in the
diagram below by the "UBF Driver" circle.
<img src="../priv/doc/ubf-flow-01.png">
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#decode-4">decode/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode-2">encode/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#init-1">init/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#start-1">start/1</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="decode-4">decode/4</a></h3>
<div class="spec">
<p><tt>decode(Contract, Cont, Binary, CallBack) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="encode-2">encode/2</a></h3>
<div class="spec">
<p><tt>encode(Contract, Term) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="init-1">init/1</a></h3>
<div class="spec">
<p><tt>init(Contract) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="start-1">start/1</a></h3>
<div class="spec">
<p><tt>start(Contract) -&gt; any()</tt></p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated EDoc, $Id$</i></p>
</body>
</html>

View File

@@ -1,8 +1,8 @@
{application,ubf}.
{packages,[]}.
{modules,[contract_driver,contract_lex,contract_manager,contract_manager_tlog,
contract_parser,contract_yecc,contracts,contracts_abnf,ebf_driver,
jsf,jsf_driver,jsf_utils,proc_socket_server,proc_utils,tbf,
tbf_driver,ubf,ubf_client,ubf_driver,ubf_plugin_handler,
ubf_plugin_meta_stateful,ubf_plugin_meta_stateless,ubf_server,
ubf_utils]}.
{modules,[abf,abf_driver,contract_driver,contract_lex,contract_manager,
contract_manager_tlog,contract_parser,contract_yecc,contracts,
contracts_abnf,ebf_driver,jsf,jsf_driver,jsf_utils,pbf,pbf_driver,
proc_socket_server,proc_utils,tbf,tbf_driver,ubf,ubf_client,
ubf_driver,ubf_plugin_handler,ubf_plugin_meta_stateful,
ubf_plugin_meta_stateless,ubf_server,ubf_utils]}.

View File

@@ -7,6 +7,8 @@
<body bgcolor="white">
<h2 class="indextitle">Modules</h2>
<table width="100%" border="0" summary="list of modules">
<tr><td><a href="abf.html" target="overviewFrame" class="module">abf</a></td></tr>
<tr><td><a href="abf_driver.html" target="overviewFrame" class="module">abf_driver</a></td></tr>
<tr><td><a href="contract_driver.html" target="overviewFrame" class="module">contract_driver</a></td></tr>
<tr><td><a href="contract_lex.html" target="overviewFrame" class="module">contract_lex</a></td></tr>
<tr><td><a href="contract_manager.html" target="overviewFrame" class="module">contract_manager</a></td></tr>
@@ -19,6 +21,8 @@
<tr><td><a href="jsf.html" target="overviewFrame" class="module">jsf</a></td></tr>
<tr><td><a href="jsf_driver.html" target="overviewFrame" class="module">jsf_driver</a></td></tr>
<tr><td><a href="jsf_utils.html" target="overviewFrame" class="module">jsf_utils</a></td></tr>
<tr><td><a href="pbf.html" target="overviewFrame" class="module">pbf</a></td></tr>
<tr><td><a href="pbf_driver.html" target="overviewFrame" class="module">pbf_driver</a></td></tr>
<tr><td><a href="proc_socket_server.html" target="overviewFrame" class="module">proc_socket_server</a></td></tr>
<tr><td><a href="proc_utils.html" target="overviewFrame" class="module">proc_utils</a></td></tr>
<tr><td><a href="tbf.html" target="overviewFrame" class="module">tbf</a></td></tr>

114
edoc/pbf.html Normal file
View File

@@ -0,0 +1,114 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Module pbf</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module pbf</h1>
<ul class="index"><li><a href="#description">Description</a></li><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>Functions for Google's Protocol Buffers&lt;-&gt;Erlang data conversion.
<h2><a name="description">Description</a></h2><p>Functions for Google's Protocol Buffers&lt;-&gt;Erlang data conversion.</p>
<p>For most purposes, these functions are not called by code outside
of this library: Erlang client &amp; Erlang server application code
usually have no need to use these functions.</p>
<h3><a name="Links">Links</a></h3>
<ul>
<li> http://code.google.com/p/protobuf/ </li>
</ul>
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#atom_to_binary-1">atom_to_binary/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#binary_to_existing_atom-1">binary_to_existing_atom/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#contract_records-0">contract_records/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode-1">decode/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode-2">decode/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode-3">decode/3</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode_init-0">decode_init/0</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode_print-1">decode_print/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#decode_print-2">decode_print/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode-1">encode/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode-2">encode/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode_print-1">encode_print/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode_print-2">encode_print/2</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="atom_to_binary-1">atom_to_binary/1</a></h3>
<div class="spec">
<p><tt>atom_to_binary(X) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="binary_to_existing_atom-1">binary_to_existing_atom/1</a></h3>
<div class="spec">
<p><tt>binary_to_existing_atom(X) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="contract_records-0">contract_records/0</a></h3>
<div class="spec">
<p><tt>contract_records() -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="decode-1">decode/1</a></h3>
<div class="spec">
<p><tt>decode(X) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="decode-2">decode/2</a></h3>
<div class="spec">
<p><tt>decode(X, Mod) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="decode-3">decode/3</a></h3>
<div class="spec">
<p><tt>decode(X, Mod, X3) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="decode_init-0">decode_init/0</a></h3>
<div class="spec">
<p><tt>decode_init() -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="decode_print-1">decode_print/1</a></h3>
<div class="spec">
<p><tt>decode_print(X) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="decode_print-2">decode_print/2</a></h3>
<div class="spec">
<p><tt>decode_print(X, Mod) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="encode-1">encode/1</a></h3>
<div class="spec">
<p><tt>encode(X) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="encode-2">encode/2</a></h3>
<div class="spec">
<p><tt>encode(X, Mod) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="encode_print-1">encode_print/1</a></h3>
<div class="spec">
<p><tt>encode_print(X) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="encode_print-2">encode_print/2</a></h3>
<div class="spec">
<p><tt>encode_print(X, Mod) -&gt; any()</tt></p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated EDoc, $Id$</i></p>
</body>
</html>

55
edoc/pbf_driver.html Normal file
View File

@@ -0,0 +1,55 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Module pbf_driver</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc">
</head>
<body bgcolor="white">
<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<hr>
<h1>Module pbf_driver</h1>
<ul class="index"><li><a href="#description">Description</a></li><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>Protocol driver process for PBF (Google's Protocol Buffers
Format) protocol sessions.
<h2><a name="description">Description</a></h2><p>Protocol driver process for PBF (Google's Protocol Buffers
Format) protocol sessions.</p>
The process executing <code>loop()</code> in this module is represented in the
diagram below by the "UBF Driver" circle.
<img src="../priv/doc/ubf-flow-01.png">
<h2><a name="index">Function Index</a></h2>
<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#decode-4">decode/4</a></td><td></td></tr>
<tr><td valign="top"><a href="#encode-2">encode/2</a></td><td></td></tr>
<tr><td valign="top"><a href="#init-1">init/1</a></td><td></td></tr>
<tr><td valign="top"><a href="#start-1">start/1</a></td><td></td></tr>
</table>
<h2><a name="functions">Function Details</a></h2>
<h3 class="function"><a name="decode-4">decode/4</a></h3>
<div class="spec">
<p><tt>decode(Contract, Cont, Binary, CallBack) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="encode-2">encode/2</a></h3>
<div class="spec">
<p><tt>encode(Contract, Term) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="init-1">init/1</a></h3>
<div class="spec">
<p><tt>init(Contract) -&gt; any()</tt></p>
</div>
<h3 class="function"><a name="start-1">start/1</a></h3>
<div class="spec">
<p><tt>start(Contract) -&gt; any()</tt></p>
</div>
<hr>
<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div>
<p><i>Generated EDoc, $Id$</i></p>
</body>
</html>

View File

@@ -117,21 +117,22 @@ usually have no need to use these functions.</p>
| 'T-I08' | 'T-I16' | 'T-I32' | 'T-U64' | 'T-I64' | 'T-DOUBLE'
| 'T-BINARY' | 'T-STRUCT' | 'T-MAP' | 'T-SET' | 'T-LIST'.
tbf::field_id() = integer().
tbf::field_data() = tbf::void() | tbf::boolean() | integer() | double() | binary() | binary() |
| tbf::struct() | tbf::map() | tbf::set() | tbf::list().
tbf::field_data() = tbf::void() | tbf::boolean() | integer()
| integer() | float()
| binary() | tbf::struct() | tbf::map() | tbf::set() | tbf::list().
tbf::map() = {'map', tbf::map_type(), [tbf::map_data()]}.
tbf::map_type() = {tbf::field_type(), tbf::field_type()}.
tbf::map_data() = {tbf::field_data(), tbf::field_data()}.
tbf::list() = {'list', tbf::list_type(), [tbf::list_data()]}.
tbf::list_type() = tbf::field_type().
tbf::list_data() = tbf::field_data().
tbf::set() = {'set', tbf::set_type(), [tbf::set_data()]}.
tbf::set_type() = tbf::field_type().
tbf::set_data() = tbf::field_data().
tbf::list() = {'list', tbf::list_type(), [tbf::list_data()]}.
tbf::list_type() = tbf::field_type().
tbf::list_data() = tbf::field_data().
tbf::void() = 'undefined'.
tbf::boolean() = 'true' | 'false'.</pre>

View File

@@ -25,8 +25,9 @@
client process. </li>
</ul>
<p>Note that this library can support UBF(A), EBF, and JSF transport.
See the <code>connect()</code> function arguments for details.</p>
<p>Note that this library can support UBF(A), EBF, JSF, TBF, PBF, and
ABF transport. See the <code>connect()</code> function arguments for
details.</p>
<p>This module also provides an alternative client-side function for
calling's UBF contract manager and a UBF contract's implementation
@@ -43,7 +44,7 @@ procedure call to a contract's implementation.</p>
<p>A DNS hostname or IP address.</p>
<h3 class="typedecl"><a name="type-connect_options">connect_options()</a></h3>
<p><tt>connect_options() = list({proto, ubf | ebf | jsf})</tt></p>
<p><tt>connect_options() = list({proto, ubf | ebf | jsf | tbf | pbf | abf})</tt></p>
<p>An OTP-style property list, see 'proplists' module for details.</p>
<h3 class="typedecl"><a name="type-ip_address">ip_address()</a></h3>

View File

@@ -37,13 +37,19 @@ implementation of a UBF(B) protocol-checking server:</p>
terms between a UBF(B) contract checking server and a client
that does not support the UBF(A) wire format but does support
Erlang's native wire formats. </li>
<li> JSF, a.k.a the JSON Server Format. Similar to EBF, except
<li> JSF, a.k.a the JSon Format. Similar to EBF, except
that JavaScript's JSON encoding is used for the wire protocol
instead of UBF(A) or Erlang's native wire formats.
NOTE: This server is currently incomplete. Source code from
Gemini Mobile Technologies, Inc. is not yet available to
help glue JSF-style encoding to a full HTTP/JSON-RPC service.
</li>
instead of UBF(A) or Erlang's native wire formats.</li>
<li> TBF, a.k.a the Thrift Binary Format. Similar to EBF, except
that Thrift's binary encoding is used for the wire protocol
instead of UBF(A) or Erlang's native wire formats.</li>
<li> PBF, a.k.a the Google's Protocol Buffers Format. Similar to
EBF, except that Google's Protocol Buffers binary encoding is used
for the wire protocol instead of UBF(A) or Erlang's native wire
formats.</li>
<li> ABF, a.k.a the Avro Binary Format. Similar to EBF, except
that Avro's binary encoding is used for the wire protocol
instead of UBF(A) or Erlang's native wire formats.</li>
</ul>
<p>There is no "stop" function. To stop the server, instead stop the
@@ -125,15 +131,17 @@ undefined, the server is not registered</p>
<li> {maxconn, integer()} ... Maximum number of simultaneous TCP
connections allowed.
Default: 10,000. </li>
<li> {proto, {ubf | ebf | jsf}} ... Enable the UBF, EBF, or JSF version
of the protocol's wire format.
<li> {proto, {ubf | ebf | jsf | tbf | pbf | abf}} ... Enable the
UBF, EBF, JSF, TBF, PBF or ABF version of the protocol's wire
format.
Default: ubf. </li>
<li> {registeredname, atom()} ... Set the name to be registered for
the TCP listener. If undefined, a default name is automatically
registered.
Default: undefined. </li>
<li> {serverhello, string()} ... Meta contract greeting string, sent
when a client first connects to the server.
<li> {serverhello, string() | undefined} ... Meta contract greeting
string, sent when a client first connects to the server. If
undefined, server hello is not sent to the client.
Default: "meta_server" </li>
<li> {statelessrpc, true | false} ... run the stateless variety of
a UBF(B) contract. A stateless contract is an extension of

View File

@@ -25,6 +25,10 @@ MODULES = \
ebf_driver \
tbf \
tbf_driver \
pbf \
pbf_driver \
abf \
abf_driver \
ubf_plugin_meta_stateful \
ubf_plugin_meta_stateless

View File

@@ -104,7 +104,67 @@ init(Args) ->
[JSFServer]
end,
{ok, {{one_for_one, 2, 60}, CUBF ++ CEBF ++ CJSF}}.
CTBF = case proplists:get_value(test_tbf_tcp_port, Args, 0) of
undefined ->
[];
TBFPort ->
TBFMaxConn = proplists:get_value(test_tbf_maxconn, Args, DefaultMaxConn),
TBFIdleTimer = proplists:get_value(test_tbf_timeout, Args, DefaultTimeout),
TBFOptions = [{serverhello, undefined}
, {statelessrpc,false}
, {proto,tbf}
, {maxconn,TBFMaxConn}
, {idletimer,TBFIdleTimer}
, {registeredname,test_tbf_tcp_port}
],
TBFServer =
{tbf_server, {ubf_server, start_link, [test_tbf, DefaultPlugins, TBFPort, TBFOptions]},
permanent, 2000, worker, [tbf_server]},
[TBFServer]
end,
CPBF = case proplists:get_value(test_pbf_tcp_port, Args, 0) of
undefined ->
[];
PBFPort ->
PBFMaxConn = proplists:get_value(test_pbf_maxconn, Args, DefaultMaxConn),
PBFIdleTimer = proplists:get_value(test_pbf_timeout, Args, DefaultTimeout),
PBFOptions = [{serverhello, undefined}
, {statelessrpc,false}
, {proto,pbf}
, {maxconn,PBFMaxConn}
, {idletimer,PBFIdleTimer}
, {registeredname,test_pbf_tcp_port}
],
PBFServer =
{pbf_server, {ubf_server, start_link, [test_pbf, DefaultPlugins, PBFPort, PBFOptions]},
permanent, 2000, worker, [pbf_server]},
[PBFServer]
end,
CABF = case proplists:get_value(test_abf_tcp_port, Args, 0) of
undefined ->
[];
ABFPort ->
ABFMaxConn = proplists:get_value(test_abf_maxconn, Args, DefaultMaxConn),
ABFIdleTimer = proplists:get_value(test_abf_timeout, Args, DefaultTimeout),
ABFOptions = [{serverhello, undefined}
, {statelessrpc,false}
, {proto,ubf} %% @TODO ubf->abf
, {maxconn,ABFMaxConn}
, {idletimer,ABFIdleTimer}
, {registeredname,test_abf_tcp_port}
],
ABFServer =
{abf_server, {ubf_server, start_link, [test_abf, DefaultPlugins, ABFPort, ABFOptions]},
permanent, 2000, worker, [abf_server]},
[ABFServer]
end,
{ok, {{one_for_one, 2, 60}, CUBF++CEBF++CJSF++CTBF++CPBF++CABF}}.
%%%----------------------------------------------------------------------
%%% Internal functions

View File

@@ -37,8 +37,11 @@ all_tests_(Setup,Teardown) ->
non_existing ->
[];
_ ->
[] %% TODO: fix failure (stateless_plugin_test:all_actual_tests_(jsf,false,start))(not_used)
[] %% @TODO fix failure (stateless_plugin_test:all_actual_tests_(jsf,false,start))(not_used)
end
++ (stateless_plugin_test:all_actual_tests_(tbf,false,start))(not_used)
%% @TODO ++ (stateless_plugin_test:all_actual_tests_(pbf,false,start))(not_used)
%% @TODO ++ (stateless_plugin_test:all_actual_tests_(abf,false,start))(not_used)
++ (stateless_plugin_test:all_actual_tests_(etf,false,start))(not_used)
++ (stateless_plugin_test:all_actual_tests_(lpc,false,start))(not_used)
}.

View File

@@ -104,7 +104,67 @@ init(Args) ->
[JSFServer]
end,
{ok, {{one_for_one, 2, 60}, CUBF ++ CEBF ++ CJSF}}.
CTBF = case proplists:get_value(test_tbf_tcp_port, Args, 0) of
undefined ->
[];
TBFPort ->
TBFMaxConn = proplists:get_value(test_tbf_maxconn, Args, DefaultMaxConn),
TBFIdleTimer = proplists:get_value(test_tbf_timeout, Args, DefaultTimeout),
TBFOptions = [{serverhello, undefined}
, {statelessrpc,true}
, {proto,tbf}
, {maxconn,TBFMaxConn}
, {idletimer,TBFIdleTimer}
, {registeredname,test_tbf_tcp_port}
],
TBFServer =
{tbf_server, {ubf_server, start_link, [test_tbf, DefaultPlugins, TBFPort, TBFOptions]},
permanent, 2000, worker, [tbf_server]},
[TBFServer]
end,
CPBF = case proplists:get_value(test_pbf_tcp_port, Args, 0) of
undefined ->
[];
PBFPort ->
PBFMaxConn = proplists:get_value(test_pbf_maxconn, Args, DefaultMaxConn),
PBFIdleTimer = proplists:get_value(test_pbf_timeout, Args, DefaultTimeout),
PBFOptions = [{serverhello, undefined}
, {statelessrpc,true}
, {proto,pbf}
, {maxconn,PBFMaxConn}
, {idletimer,PBFIdleTimer}
, {registeredname,test_pbf_tcp_port}
],
PBFServer =
{pbf_server, {ubf_server, start_link, [test_pbf, DefaultPlugins, PBFPort, PBFOptions]},
permanent, 2000, worker, [pbf_server]},
[PBFServer]
end,
CABF = case proplists:get_value(test_abf_tcp_port, Args, 0) of
undefined ->
[];
ABFPort ->
ABFMaxConn = proplists:get_value(test_abf_maxconn, Args, DefaultMaxConn),
ABFIdleTimer = proplists:get_value(test_abf_timeout, Args, DefaultTimeout),
ABFOptions = [{serverhello, undefined}
, {statelessrpc,true}
, {proto,ubf} %% @TODO ubf->abf
, {maxconn,ABFMaxConn}
, {idletimer,ABFIdleTimer}
, {registeredname,test_abf_tcp_port}
],
ABFServer =
{abf_server, {ubf_server, start_link, [test_abf, DefaultPlugins, ABFPort, ABFOptions]},
permanent, 2000, worker, [abf_server]},
[ABFServer]
end,
{ok, {{one_for_one, 2, 60}, CUBF++CEBF++CJSF++CTBF++CPBF++CABF}}.
%%%----------------------------------------------------------------------
%%% Internal functions

View File

@@ -10,11 +10,15 @@ do_eunit() ->
_ -> erlang:halt(1)
end.
-define(APPLICATION, stateless_plugin).
-define(UBF_PORT, server_port(test_ubf_tcp_port)).
-define(EBF_PORT, server_port(test_ebf_tcp_port)).
-define(JSF_PORT, server_port(test_jsf_tcp_port)).
-define(TBF_PORT, server_port(test_tbf_tcp_port)).
-define(PBF_PORT, server_port(test_pbf_tcp_port)).
-define(ABF_PORT, server_port(test_abf_tcp_port)).
-define(SLEEP, 25).
-record(args, {host, port, proto, stateless, state}).
@@ -44,6 +48,9 @@ all_tests_(Setup,Teardown) ->
_ ->
(all_actual_tests_(jsf,true,none))(not_used)
end
++ (all_actual_tests_(tbf,true,none))(not_used)
%% @TODO ++ (all_actual_tests_(pbf,true,none))(not_used)
%% @TODO ++ (all_actual_tests_(abf,true,none))(not_used)
++ (all_actual_tests_(etf,true,none))(not_used)
++ (all_actual_tests_(lpc,true,none))(not_used)
}.
@@ -54,6 +61,12 @@ all_actual_tests_(ebf=Proto,Stateless,State) ->
all_actual_tests_("localhost",fun() -> ?EBF_PORT end,Proto,Stateless,State);
all_actual_tests_(jsf=Proto,Stateless,State) ->
all_actual_tests_("localhost",fun() -> ?JSF_PORT end,Proto,Stateless,State);
all_actual_tests_(tbf=Proto,Stateless,State) ->
all_actual_tests_("localhost",fun() -> ?TBF_PORT end,Proto,Stateless,State);
all_actual_tests_(pbf=Proto,Stateless,State) ->
all_actual_tests_("localhost",fun() -> ?PBF_PORT end,Proto,Stateless,State);
all_actual_tests_(abf=Proto,Stateless,State) ->
all_actual_tests_("localhost",fun() -> ?ABF_PORT end,Proto,Stateless,State);
all_actual_tests_(Proto,Stateless,State) ->
all_actual_tests_(undefined,fun() -> undefined end,Proto,Stateless,State).
@@ -137,15 +150,13 @@ test_002(#args{host=Host,port=Port}=Args,How) ->
%% connect -> close
test_003(#args{state=State}=Args) ->
assert_process(Args, 0, 0, 0, 0, 0),
{ok,Pid1,?S("test_meta_server")} = client_connect(Args),
{ok,Pid1} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
client_stop(Pid1),
assert_process(Args, 0, 0, 0, 0, 0),
{ok,Pid2,?S("test_meta_server")} = client_connect(Args),
{ok,Pid2} = client_connect(Args),
client_stop(Pid1),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,{ok,ok},State} = client_rpc(Pid2,{startSession,?S("test"),[]}),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,ok,State} = client_rpc(Pid2,keepalive),
client_stop(Pid2),
assert_process(Args, 0, 0, 0, 0, 0).
@@ -153,9 +164,7 @@ test_003(#args{state=State}=Args) ->
%% connect -> client breaks -> close
test_004(#args{state=State}=Args) ->
assert_process(Args, 0, 0, 0, 0, 0),
{ok,Pid,?S("test_meta_server")} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,{ok,ok},State} = client_rpc(Pid,{startSession,?S("test"),[]}),
{ok,Pid} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,ok,State} = client_rpc(Pid,keepalive),
assert_process(Args, 1, 1, 1, 1, 1),
@@ -170,9 +179,7 @@ test_004(#args{state=State}=Args) ->
%% connect -> client timeout -> close
test_005(#args{state=State}=Args) ->
assert_process(Args, 0, 0, 0, 0, 0),
{ok,Pid,?S("test_meta_server")} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,{ok,ok},State} = client_rpc(Pid,{startSession,?S("test"),[]}),
{ok,Pid} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,ok,State} = client_rpc(Pid,keepalive),
assert_process(Args, 1, 1, 1, 1, 1),
@@ -184,9 +191,7 @@ test_005(#args{state=State}=Args) ->
%% connect -> server breaks -> close
test_006(#args{state=State}=Args) ->
assert_process(Args, 0, 0, 0, 0, 0),
{ok,Pid,?S("test_meta_server")} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,{ok,ok},State} = client_rpc(Pid,{startSession,?S("test"),[]}),
{ok,Pid} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,ok,State} = client_rpc(Pid,keepalive),
assert_process(Args, 1, 1, 1, 1, 1),
@@ -201,9 +206,7 @@ test_006(#args{state=State}=Args) ->
%% connect -> server timeout -> close
test_007(#args{state=State}=Args) ->
assert_process(Args, 0, 0, 0, 0, 0),
{ok,Pid,?S("test_meta_server")} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,{ok,ok},State} = client_rpc(Pid,{startSession,?S("test"),[]}),
{ok,Pid} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,ok,State} = client_rpc(Pid,keepalive),
assert_process(Args, 1, 1, 1, 1, 1),
@@ -217,9 +220,7 @@ test_007(#args{state=State}=Args) ->
%% connect -> server crash -> close
test_008(#args{proto=Proto,state=State}=Args) ->
assert_process(Args, 0, 0, 0, 0, 0),
{ok,Pid,?S("test_meta_server")} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,{ok,ok},State} = client_rpc(Pid,{startSession,?S("test"),[]}),
{ok,Pid} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,ok,State} = client_rpc(Pid,keepalive),
assert_process(Args, 1, 1, 1, 1, 1),
@@ -244,9 +245,7 @@ test_009(#args{proto=Proto})
ok;
test_009(#args{state=State}=Args) ->
assert_process(Args, 0, 0, 0, 0, 0),
{ok,Pid,?S("test_meta_server")} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,{ok,ok},State} = client_rpc(Pid,{startSession,?S("test"),[]}),
{ok,Pid} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,ok,State} = client_rpc(Pid,keepalive),
assert_process(Args, 1, 1, 1, 1, 1),
@@ -268,9 +267,7 @@ test_010(#args{proto=Proto})
ok;
test_010(#args{state=State}=Args) ->
assert_process(Args, 0, 0, 0, 0, 0),
{ok,Pid,?S("test_meta_server")} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,{ok,ok},State} = client_rpc(Pid,{startSession,?S("test"),[]}),
{ok,Pid} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,ok,State} = client_rpc(Pid,keepalive),
assert_process(Args, 1, 1, 1, 1, 1),
@@ -367,9 +364,7 @@ server_port(Name) ->
%% connect -> driver socket is shutdown or closed -> close
test_shutdown_socket(#args{state=State}=Args,Who,Reason) ->
assert_process(Args, 0, 0, 0, 0, 0),
{ok,Pid,?S("test_meta_server")} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,{ok,ok},State} = client_rpc(Pid,{startSession,?S("test"),[]}),
{ok,Pid} = client_connect(Args),
assert_process(Args, 1, 1, 1, 1, 1),
{reply,ok,State} = client_rpc(Pid,keepalive),
assert_process(Args, 1, 1, 1, 1, 1),
@@ -387,15 +382,25 @@ test_shutdown_socket(#args{state=State}=Args,Who,Reason) ->
client_connect(#args{proto=lpc,stateless=Stateless,state=State}) ->
Mod = if Stateless -> stateless_plugin; true -> stateful_plugin end,
{ok,{Mod,State},?S("test_meta_server")};
client_connect(#args{proto=etf,stateless=Stateless}) ->
{ok,{Mod,State}};
client_connect(#args{proto=etf,stateless=Stateless,state=State}) ->
Plugins = if Stateless -> [stateless_plugin]; true -> [stateful_plugin] end,
Server = test_ubf,
Options = [{serverhello, "test_meta_server"},{proto,etf},{statelessrpc,Stateless}],
ubf_client:connect(Plugins,Server,Options,infinity);
client_connect(#args{host=Host,port=Port,proto=Proto,stateless=Stateless}) ->
{ok,Pid,?S("test_meta_server")} = ubf_client:connect(Plugins,Server,Options,infinity),
{reply,{ok,ok},State} = client_rpc(Pid,{startSession,?S("test"),[]}),
{ok,Pid};
client_connect(#args{host=Host,port=Port,proto=Proto,stateless=Stateless,state=State})
when Proto =:= tbf; Proto =:= pbf; Proto =:= abf ->
Options = [{proto,Proto},{statelessrpc,Stateless},{serverhello,undefined}],
{ok,Pid,undefined} = ubf_client:connect(Host,Port,Options,infinity),
{reply,{ok,ok},State} = client_rpc(Pid,{startSession,?S("test"),[]}), %% @TODO remove this line
{ok,Pid};
client_connect(#args{host=Host,port=Port,proto=Proto,stateless=Stateless,state=State}) ->
Options = [{proto,Proto},{statelessrpc,Stateless}],
ubf_client:connect(Host,Port,Options,infinity).
{ok,Pid,?S("test_meta_server")} = ubf_client:connect(Host,Port,Options,infinity),
{reply,{ok,ok},State} = client_rpc(Pid,{startSession,?S("test"),[]}),
{ok,Pid}.
client_rpc(X,Y) ->
@@ -419,28 +424,49 @@ client_stop(Pid) ->
assert_process(#args{proto=ubf}=Args, Driver, Contract, Plugin, Client, ClientDriver) ->
timer:sleep(50),
timer:sleep(?SLEEP),
assert_process(Args, ubf_driver, Driver),
assert_process(Args, contract_manager, Contract),
assert_process(Args, ubf_plugin_handler, Plugin),
assert_process(Args, ubf_client, Client),
assert_process(Args, ubf_client_driver, ClientDriver);
assert_process(#args{proto=ebf}=Args, Driver, Contract, Plugin, Client, ClientDriver) ->
timer:sleep(50),
timer:sleep(?SLEEP),
assert_process(Args, ebf_driver, Driver),
assert_process(Args, contract_manager, Contract),
assert_process(Args, ubf_plugin_handler, Plugin),
assert_process(Args, ubf_client, Client),
assert_process(Args, ebf_client_driver, ClientDriver);
assert_process(#args{proto=jsf}=Args, Driver, Contract, Plugin, Client, ClientDriver) ->
timer:sleep(50),
timer:sleep(?SLEEP),
assert_process(Args, jsf_driver, Driver),
assert_process(Args, contract_manager, Contract),
assert_process(Args, ubf_plugin_handler, Plugin),
assert_process(Args, ubf_client, Client),
assert_process(Args, jsf_client_driver, ClientDriver);
assert_process(#args{proto=tbf}=Args, Driver, Contract, Plugin, Client, ClientDriver) ->
timer:sleep(?SLEEP),
assert_process(Args, tbf_driver, Driver),
assert_process(Args, contract_manager, Contract),
assert_process(Args, ubf_plugin_handler, Plugin),
assert_process(Args, ubf_client, Client),
assert_process(Args, tbf_client_driver, ClientDriver);
assert_process(#args{proto=pbf}=Args, Driver, Contract, Plugin, Client, ClientDriver) ->
timer:sleep(?SLEEP),
assert_process(Args, pbf_driver, Driver),
assert_process(Args, contract_manager, Contract),
assert_process(Args, ubf_plugin_handler, Plugin),
assert_process(Args, ubf_client, Client),
assert_process(Args, pbf_client_driver, ClientDriver);
assert_process(#args{proto=abf}=Args, Driver, Contract, Plugin, Client, ClientDriver) ->
timer:sleep(?SLEEP),
assert_process(Args, abf_driver, Driver),
assert_process(Args, contract_manager, Contract),
assert_process(Args, ubf_plugin_handler, Plugin),
assert_process(Args, ubf_client, Client),
assert_process(Args, abf_client_driver, ClientDriver);
assert_process(#args{proto=etf}=Args, _, Contract, Plugin, Client, _) ->
timer:sleep(50),
timer:sleep(?SLEEP),
assert_process(Args, contract_manager, Contract),
assert_process(Args, ubf_plugin_handler, Plugin),
assert_process(Args, ubf_client, Client);
@@ -449,7 +475,7 @@ assert_process(#args{proto=lpc}=_Args, _, _Contract, _Plugin, _Client, _) ->
assert_process(#args{stateless=false}=Args, ubf_plugin_handler=M, CheckNum) ->
assert_process(Args, M, CheckNum, -3); % adjust for manager plugins
assert_process(Args, M, CheckNum, -6); % adjust for manager plugins
assert_process(Args, M, CheckNum) ->
assert_process(Args, M, CheckNum, 0).
@@ -477,12 +503,20 @@ exit_process(#args{proto=ebf}, driver, Reason) ->
do_exit_process(ebf_driver, Reason);
exit_process(#args{proto=jsf}, driver, Reason) ->
do_exit_process(jsf_driver, Reason);
exit_process(#args{proto=tbf}, driver, Reason) ->
do_exit_process(tbf_driver, Reason);
exit_process(#args{proto=ubf}, client_driver, Reason) ->
do_exit_process(ubf_client_driver, Reason);
exit_process(#args{proto=ebf}, client_driver, Reason) ->
do_exit_process(ebf_client_driver, Reason);
exit_process(#args{proto=jsf}, client_driver, Reason) ->
do_exit_process(jsf_client_driver, Reason).
do_exit_process(jsf_client_driver, Reason);
exit_process(#args{proto=tbf}, client_driver, Reason) ->
do_exit_process(tbf_client_driver, Reason);
exit_process(#args{proto=pbf}, client_driver, Reason) ->
do_exit_process(pbf_client_driver, Reason);
exit_process(#args{proto=abf}, client_driver, Reason) ->
do_exit_process(abf_client_driver, Reason).
shutdown_socket(Args, Process) ->
@@ -494,12 +528,24 @@ shutdown_socket(#args{proto=ebf}, driver, Reason) ->
do_shutdown_socket(ebf_driver, Reason);
shutdown_socket(#args{proto=jsf}, driver, Reason) ->
do_shutdown_socket(jsf_driver, Reason);
shutdown_socket(#args{proto=tbf}, driver, Reason) ->
do_shutdown_socket(tbf_driver, Reason);
shutdown_socket(#args{proto=pbf}, driver, Reason) ->
do_shutdown_socket(pbf_driver, Reason);
shutdown_socket(#args{proto=abf}, driver, Reason) ->
do_shutdown_socket(abf_driver, Reason);
shutdown_socket(#args{proto=ubf}, client_driver, Reason) ->
do_shutdown_socket(ubf_client_driver, Reason);
shutdown_socket(#args{proto=ebf}, client_driver, Reason) ->
do_shutdown_socket(ebf_client_driver, Reason);
shutdown_socket(#args{proto=jsf}, client_driver, Reason) ->
do_shutdown_socket(jsf_client_driver, Reason).
do_shutdown_socket(jsf_client_driver, Reason);
shutdown_socket(#args{proto=tbf}, client_driver, Reason) ->
do_shutdown_socket(tbf_client_driver, Reason);
shutdown_socket(#args{proto=pbf}, client_driver, Reason) ->
do_shutdown_socket(bbf_client_driver, Reason);
shutdown_socket(#args{proto=abf}, client_driver, Reason) ->
do_shutdown_socket(abf_client_driver, Reason).
do_exit_process(M) ->

109
src/abf.erl Normal file
View File

@@ -0,0 +1,109 @@
%%
%% For most purposes, these functions are not called by code outside of
%% this library: Erlang client &amp; Erlang server application code usually
%% have no need to use these functions.
%%
%% == Links ==
%%
%% <ul>
%% <li> http://hadoop.apache.org/avro/docs/current/spec.html </li>
%% <li> http://lucene.apache.org/java/2_4_0/fileformats.html#VInt </li>
%% <li> http://code.google.com/apis/protocolbuffers/docs/encoding.html#types </li>
%% </ul>
%%
%% == Avro Data Types ==
%% ```
%% typeval = prim/ complex
%% prim = null/ boolean/ int/ long/ float/ double/ bytes/ string
%% complex = record/ enum/ array/ map/ union/ fixed
%%
%% null = "" ; zero-length
%% boolean = %x00/ %x01
%% int = vint
%% long = vint
%% float = 4*OCTET ; 32-bit IEEE 754 floating-point number
%% double = 8*OCTET ; 64-bit IEEE 754 floating-point number
%% bytes = long *OCTET ; bytes and that bytes of data
%% string = long *OCTET ; bytes and that bytes of utf-8 characters
%%
%% record = *typeval ; list of other type values decleared by the schema
%% enum = int ; zero-based position
%% array = *ablock end
%% map = *mblock end
%% union = long typeval ; zero-based position and its value
%% fixed = *OCTET ; length is declared in the schema
%%
%% end = 0x00
%% ablock = long *typeval ; number of array items and that many items
%% mblock = long *keyval ; number of key-val pairs and that many key-val pairs
%% keyval = string typeval ; key is always string
%% vint = OCTET *OCTET ; variable length zig-zag encoding
%% ; http://lucene.apache.org/java/2_4_0/fileformats.html#VInt </li>
%% ; http://code.google.com/apis/protocolbuffers/docs/encoding.html#types </li>
%% '''
%% == Mapping: Avro -> Erlang Terms
%% ```
%% abf::null() = null.
%% abf::boolean() = true | false.
%% abf::int() = integer().
%% abf::long() = integer().
%% abf::float() = float().
%% abf::double() = float().
%% abf::bytes() = binary().
%% abf::string() = {'$S', [integer()]}.
%%
%% '''
%% == Mapping: UBF -> Erlang Terms ==
%% ```
%% todo
%% '''
%% == Mapping: UBF value -> Avro value ==
%% ```
%% todo
%% '''
-module(abf).
-include("ubf.hrl").
-export([encode/3]).
-export([decode_init/0, decode/3, decode/4]).
%%
%%---------------------------------------------------------------------
%%
-type state() :: term(). %% todo
-spec encode(Input::term(), module(), state()) -> {state(), iolist()}.
-type ok() :: {ok, Output::term(), Remainder::binary()}.
-type error() :: {error, Reason::term()}.
-type cont() :: {more, fun()}.
-spec decode_init() -> fun().
-spec decode(Input::binary(), module(), state()) -> {state(), ok()} | {state(), error()} | {state(), cont()}.
-spec decode(Input::binary(), module(), cont(), state()) -> {state(), ok()} | {state(), error()} | {state(), cont()}.
-record(state,{todo}).
%%
%%---------------------------------------------------------------------
%%
encode(_X, _Mod, State) when is_record(State, state) ->
{State, <<"todo">>}.
%%
%%---------------------------------------------------------------------
%%
decode(_X, _Mod, State) ->
{State, {ok, todo, <<"">>}}.
decode(_X, _Mod, _Cont, State) ->
{State, {ok, todo, <<"">>}}.
decode_init() ->
{more, []}. %% todo

39
src/abf_driver.erl Normal file
View File

@@ -0,0 +1,39 @@
%% @doc Protocol driver process for Avro protocol sessions.
%%
%% The process executing `loop()' in this module is represented in the
%% diagram below by the "UBF Driver" circle.
%% <img src="../priv/doc/ubf-flow-01.png"></img>
-module(abf_driver).
-export([start/1, init/1, encode/2, decode/4]).
-define(DIC_KEY, abf_avro_state).
start(Contract) ->
proc_utils:spawn_link_debug(fun() -> contract_driver:start(?MODULE, Contract) end, abf_client_driver).
init(_Contract) ->
erase(),
abf:decode_init().
encode(Contract, Term) ->
State = get(?DIC_KEY),
{NewState, Res} = abf:encode(Term, Contract, State),
put(?DIC_KEY, NewState),
Res.
decode(Contract, Cont, Binary, CallBack) ->
State = get(?DIC_KEY),
{NewState, Cont1} = abf:decode(Binary, Contract, Cont, State),
put(?DIC_KEY, NewState),
decode(Contract, Cont1, CallBack).
decode(_Contract, {more, _}=Cont, _CallBack) ->
Cont;
decode(Contract, {ok, Term, Binary}=_Cont, CallBack) ->
State = get(?DIC_KEY),
CallBack(Term),
{NewState, Cont1} = abf:decode(Binary, Contract, State),
put(?DIC_KEY, NewState),
decode(Contract, Cont1, CallBack).

View File

@@ -34,6 +34,7 @@ EVENT : {token,{eventkwd,TokenLine}}.
"[^"]*" : S = lists:sublist(TokenChars, 2, length(TokenChars) - 2),
{token,{string,TokenLine,S}}.
=> : {token,{'=>',TokenLine}}.
<= : {token,{'<=',TokenLine}}.
\+\+ : {token,{'++',TokenLine}}.
\.\. : {token,{'..',TokenLine}}.
\#\# : {token,{'##',TokenLine}}.

View File

@@ -5,7 +5,7 @@ form type typeDef typeRef primType typeAttr typeSeq typeRec.
Terminals
namekwd vsnkwd typekwd statekwd anystatekwd eventkwd atom binary float integer string
'+' '|' '=' '#' '{' '}' '&' ';' ',' '[]' '[' ']' '(' ')' ']?' ']{0}' ']{1}' ']+' ')?' '){0}' '){1}' '++' '..' '##' '=>' dot.
'+' '|' '=' '#' '{' '}' '&' ';' ',' '[]' '[' ']' '(' ')' ']?' ']{0}' ']{1}' ']+' ')?' '){0}' '){1}' '++' '..' '##' '=>' '<=' dot.
Rootsymbol form.
@@ -83,6 +83,7 @@ transitions -> transition : ['$1'].
transition -> typeRef '=>' outputs : {input, '$1', '$3'}.
transition -> eventkwd '=>' typeRef : {event_out, '$3'}.
transition -> eventkwd '<=' typeRef : {event_in, '$3'}.
outputs -> responseAndState '|' outputs : ['$1'|'$3'].
outputs -> responseAndState : ['$1'].
@@ -93,6 +94,8 @@ anyrules -> anyrule ';' anyrules : ['$1'|'$3'].
anyrules -> anyrule : ['$1'].
anyrule -> typeRef '=>' typeRef : {'$1', '$3'}.
anyrule -> eventkwd '=>' typeRef : {event_out, '$3'}.
anyrule -> eventkwd '<=' typeRef : {event_in, '$3'}.
Erlang code.

145
src/pbf.erl Normal file
View File

@@ -0,0 +1,145 @@
%% @doc Functions for Google's Protocol Buffers&lt;->Erlang data conversion.
%%
%% For most purposes, these functions are not called by code outside
%% of this library: Erlang client &amp; Erlang server application code
%% usually have no need to use these functions.
%%
%% == Links ==
%%
%% <ul>
%% <li> http://code.google.com/p/protobuf/ </li>
%% </ul>
%%
%% @TODO add types and mapping specification
%%
%%
-module(pbf).
-include("ubf.hrl").
-export([encode_print/1, encode_print/2, encode/1, encode/2]).
-export([decode_print/1, decode_print/2, decode_init/0, decode/1, decode/2, decode/3]).
-export([atom_to_binary/1]).
-export([binary_to_existing_atom/1]).
%% Dummy hack/kludge.
-export([contract_records/0]).
contract_records() ->
[].
%%
%%---------------------------------------------------------------------
%%
-spec encode_print(Input::term()) -> ok | no_return().
-spec encode_print(Input::term(), module()) -> ok | no_return().
-spec encode(Input::term()) -> iolist() | no_return().
-spec encode(Input::term(), module()) -> iolist() | no_return().
-spec decode_print(Input::binary()) -> ok | no_return().
-spec decode_print(Input::binary(), module()) -> ok | no_return().
-type ok() :: {ok, Output::term(), Remainder::binary()}.
-type error() :: {error, Reason::term()}.
-type cont() :: {more, fun()}.
-spec decode_init() -> cont().
-spec decode(Input::binary()) -> ok() | error() | cont().
-spec decode(Input::binary(), module()) -> ok() | error() | cont().
-spec decode(Input::binary(), module(), cont()) -> ok() | error() | cont().
-record(state,
{
x % current binary to be decoded
, stack % current stack
, type % current type (optional)
, size % current size (optional)
, mod % contract
}
).
%%
%%---------------------------------------------------------------------
%%
encode_print(X) ->
encode_print(X, ?MODULE).
encode_print(X, Mod) ->
io:format("~p~n", [encode(X, Mod)]).
encode(X) ->
encode(X, ?MODULE).
encode(_X, _Mod) ->
%% @TODO
exit(unimplemented).
%%
%%---------------------------------------------------------------------
%%
decode_print(X) ->
decode_print(X, ?MODULE).
decode_print(X, Mod) ->
io:format("~p~n", [decode(X, Mod)]).
decode(X) ->
decode(X, ?MODULE).
decode(X, Mod) ->
decode(X, Mod, decode_init()).
decode(X, Mod, {more, Fun}) ->
Fun(#state{x=X,mod=Mod}).
decode_init() ->
{more, fun decode_start/1}.
decode_start(_S) ->
%% @TODO
exit(unimplemented).
decode_finish(#state{x=X,stack=Term}) ->
{ok, Term, X}.
decode_pause(#state{x=X}=S, Cont, Resume) ->
{more, fun(#state{x=X1,mod=Mod1}) ->
Resume(S#state{x= <<X/binary,X1/binary>>,mod=Mod1}, Cont)
end}.
decode_error(Type, SubType, Value, S) ->
{error, {Type, SubType, Value, S}}.
%%
%%---------------------------------------------------------------------
%%
%% @TODO encode implementation
%%
%%---------------------------------------------------------------------
%%
%% @TODO decode implementation
%%
%%---------------------------------------------------------------------
%%
atom_to_binary(X) ->
list_to_binary(atom_to_list(X)).
binary_to_existing_atom(X) ->
list_to_existing_atom(binary_to_list(X)).
push(X, [Top|Rest]) ->
[[X|Top]|Rest].

30
src/pbf_driver.erl Normal file
View File

@@ -0,0 +1,30 @@
%% @doc Protocol driver process for PBF (Google's Protocol Buffers
%% Format) protocol sessions.
%%
%% The process executing `loop()' in this module is represented in the
%% diagram below by the "UBF Driver" circle.
%% <img src="../priv/doc/ubf-flow-01.png"></img>
-module(pbf_driver).
-export([start/1, init/1, encode/2, decode/4]).
start(Contract) ->
proc_utils:spawn_link_debug(fun() -> contract_driver:start(?MODULE, Contract) end, pbf_client_driver).
init(_Contract) ->
pbf:decode_init().
encode(Contract, Term) ->
pbf:encode(Term, Contract).
decode(Contract, Cont, Binary, CallBack) ->
Cont1 = pbf:decode(Binary, Contract, Cont),
decode(Contract, Cont1, CallBack).
decode(_Contract, {more, _}=Cont, _CallBack) ->
Cont;
decode(Contract, {ok, Term, Binary}=_Cont, CallBack) ->
CallBack(Term),
Cont1 = pbf:decode(Binary, Contract),
decode(Contract, Cont1, CallBack).

View File

@@ -110,21 +110,22 @@
%% | 'T-I08' | 'T-I16' | 'T-I32' | 'T-U64' | 'T-I64' | 'T-DOUBLE'
%% | 'T-BINARY' | 'T-STRUCT' | 'T-MAP' | 'T-SET' | 'T-LIST'.
%% tbf::field_id() = integer().
%% tbf::field_data() = tbf::void() | tbf::boolean() | integer() | double() | binary() | binary() |
%% | tbf::struct() | tbf::map() | tbf::set() | tbf::list().
%% tbf::field_data() = tbf::void() | tbf::boolean() | integer()
%% | integer() | float()
%% | binary() | tbf::struct() | tbf::map() | tbf::set() | tbf::list().
%%
%% tbf::map() = {'map', tbf::map_type(), [tbf::map_data()]}.
%% tbf::map_type() = {tbf::field_type(), tbf::field_type()}.
%% tbf::map_data() = {tbf::field_data(), tbf::field_data()}.
%%
%% tbf::list() = {'list', tbf::list_type(), [tbf::list_data()]}.
%% tbf::list_type() = tbf::field_type().
%% tbf::list_data() = tbf::field_data().
%%
%% tbf::set() = {'set', tbf::set_type(), [tbf::set_data()]}.
%% tbf::set_type() = tbf::field_type().
%% tbf::set_data() = tbf::field_data().
%%
%% tbf::list() = {'list', tbf::list_type(), [tbf::list_data()]}.
%% tbf::list_type() = tbf::field_type().
%% tbf::list_data() = tbf::field_data().
%%
%% tbf::void() = 'undefined'.
%% tbf::boolean() = 'true' | 'false'.
%%
@@ -283,7 +284,7 @@ contract_records() ->
-type error() :: {error, Reason::term()}.
-type cont() :: {more, fun()}.
-spec decode_init() -> fun().
-spec decode_init() -> cont().
-spec decode(Input::binary()) -> ok() | error() | cont().
-spec decode(Input::binary(), module()) -> ok() | error() | cont().
-spec decode(Input::binary(), module(), cont()) -> ok() | error() | cont().
@@ -350,11 +351,21 @@ encode(X, Mod) when is_tuple(X) ->
'list' ->
encode_list(X, Mod);
_ ->
exit(badarg)
try_encode_ubf(X, Mod)
end;
encode(_, _) ->
exit(badarg).
encode(X, Mod) ->
try_encode_ubf(X, Mod).
try_encode_ubf(X, Mod) ->
%% automagically try to encode from native ubf
case get('ubf_info') of
tbf_client_driver ->
encode_message({'message', <<"$UBF">>, 'T-CALL', 0, X}, Mod);
tbf_driver ->
encode_message({'message', <<"$UBF">>, 'T-REPLY', 0, X}, Mod);
_ ->
exit(badarg)
end.
%%
%%---------------------------------------------------------------------
@@ -369,43 +380,39 @@ decode(X) ->
decode(X, ?MODULE).
decode(X, Mod) ->
decode_message(#state{x=X,mod=Mod}, decode_init()).
decode(X, Mod, decode_init()).
decode(X, Mod, {more, Fun}) ->
Fun(#state{x=X,mod=Mod}).
decode_init() ->
fun decode_done/1.
{more, fun decode_start/1}.
decode_done(#state{x=X,stack=Term}) ->
{ok, Term, X}.
decode_start(S) ->
decode_message(S, fun decode_finish/1).
decode_done('field', #state{stack=[[H,T,[T1|T2]|T3]|Stack]}=S, Cont) ->
H1 = list_to_tuple(lists:reverse([H|T])),
H2 = [[H1|T1]|T2],
Cont(S#state{stack=[[H2|T3]|Stack]});
decode_done('field-data', #state{stack=[[H,[T|T1]|T2]|Stack]}=S, Cont) ->
H1 = [[H|T]|T1],
Cont(S#state{stack=[[H1|T2]|Stack]});
decode_done('field-datum', #state{stack=[[H,T,[T1|T2]|T3]|Stack]}=S, Cont) ->
H1 = [[{T,H}|T1]|T2],
Cont(S#state{stack=[[H1|T3]|Stack]});
decode_done(Type, #state{stack=[[[H|T]|T1]|Stack]}=S, Cont)
when Type =:= 'struct';
Type =:= 'map';
Type =:= 'set';
Type =:= 'list' ->
H1 = list_to_tuple(lists:reverse([lists:reverse(H)|T])),
Cont(S#state{stack=[[H1|T1]|Stack]});
decode_done('message', #state{stack=[H|[[]]],mod=Mod}=S, Cont) ->
H1 = list_to_tuple(lists:reverse(H)),
case H1 of
{'message',<<"$UBF">>,_Type,_SeqId,Struct} ->
%% special treatment for UBF-native messages
UBF = decode_ubf(Struct, Mod),
Cont(S#state{stack=setelement(5,H1,UBF)});
decode_finish(#state{x=X,stack=Term}) ->
{ok, try_decode_ubf(Term), X}.
try_decode_ubf(X) ->
%% automagically try to decode to native ubf
case get('ubf_info') of
tbf_client_driver ->
case X of
{'message', <<"$UBF">>, 'T-REPLY', 0, Y} ->
Y;
_ ->
exit(badarg)
end;
tbf_driver ->
case X of
{'message', <<"$UBF">>, 'T-CALL', 0, Y} ->
Y;
_ ->
exit(badarg)
end;
_ ->
Cont(S#state{stack=H1})
X
end.
decode_pause(#state{x=X}=S, Cont, Resume) ->
@@ -575,6 +582,34 @@ encode_type(_, _, _) -> exit(badarg).
%%
%%---------------------------------------------------------------------
%%
decode_finish('field', #state{stack=[[H,T,[T1|T2]|T3]|Stack]}=S, Cont) ->
H1 = list_to_tuple(lists:reverse([H|T])),
H2 = [[H1|T1]|T2],
Cont(S#state{stack=[[H2|T3]|Stack]});
decode_finish('field-data', #state{stack=[[H,[T|T1]|T2]|Stack]}=S, Cont) ->
H1 = [[H|T]|T1],
Cont(S#state{stack=[[H1|T2]|Stack]});
decode_finish('field-datum', #state{stack=[[H,T,[T1|T2]|T3]|Stack]}=S, Cont) ->
H1 = [[{T,H}|T1]|T2],
Cont(S#state{stack=[[H1|T3]|Stack]});
decode_finish(Type, #state{stack=[[[H|T]|T1]|Stack]}=S, Cont)
when Type =:= 'struct';
Type =:= 'map';
Type =:= 'set';
Type =:= 'list' ->
H1 = list_to_tuple(lists:reverse([lists:reverse(H)|T])),
Cont(S#state{stack=[[H1|T1]|Stack]});
decode_finish('message', #state{stack=[H|[[]]],mod=Mod}=S, Cont) ->
H1 = list_to_tuple(lists:reverse(H)),
case H1 of
{'message',<<"$UBF">>,_Type,_SeqId,Struct} ->
%% special treatment for UBF-native messages
UBF = decode_ubf(Struct, Mod),
Cont(S#state{stack=setelement(5,H1,UBF)});
_ ->
Cont(S#state{stack=H1})
end.
decode_message(#state{x=X,stack=undefined}=S, Cont) ->
case X of
<<Len:32/signed,X1/binary>> when Len >= 0 ->
@@ -585,7 +620,7 @@ decode_message(#state{x=X,stack=undefined}=S, Cont) ->
decode_error('message', 'message-type', Type, S);
DecodedType ->
Stack1 = [[Id, DecodedType, Name, 'message'], []],
Cont1 = fun(S1) -> decode_done('message', S1, Cont) end,
Cont1 = fun(S1) -> decode_finish('message', S1, Cont) end,
decode_struct(S#state{x=X2,stack=Stack1}, Cont1)
end;
_ ->
@@ -631,7 +666,7 @@ decode_map(#state{x=X,stack=Stack}=S, Cont) ->
DecodedValueType ->
Type = {KeyType,ValueType},
Stack1 = push([[], DecodedValueType, DecodedKeyType, 'map'], Stack),
Cont1 = fun(S1) -> decode_done('map', S1, Cont) end,
Cont1 = fun(S1) -> decode_finish('map', S1, Cont) end,
decode_field_datum(S#state{x=X1,stack=Stack1,type=Type,size=Size}, Cont1)
end
end;
@@ -649,7 +684,7 @@ decode_set(#state{x=X,stack=Stack}=S, Cont) ->
decode_error('set', 'set-type', Type, S);
DecodedType ->
Stack1 = push([[], DecodedType, 'set'], Stack),
Cont1 = fun(S1) -> decode_done('set', S1, Cont) end,
Cont1 = fun(S1) -> decode_finish('set', S1, Cont) end,
decode_field_data(S#state{x=X1,stack=Stack1,type=Type,size=Size}, Cont1)
end;
<<_Type:8/signed,Size:32/signed>> when Size < 0 ->
@@ -666,7 +701,7 @@ decode_list(#state{x=X,stack=Stack}=S, Cont) ->
decode_error('list', 'list-type', Type, S);
DecodedType ->
Stack1 = push([[], DecodedType, 'list'], Stack),
Cont1 = fun(S1) -> decode_done('list', S1, Cont) end,
Cont1 = fun(S1) -> decode_finish('list', S1, Cont) end,
decode_field_data(S#state{x=X1,stack=Stack1,type=Type,size=Size}, Cont1)
end;
<<_Type:8/signed,Size:32/signed>> when Size < 0 ->
@@ -678,7 +713,7 @@ decode_list(#state{x=X,stack=Stack}=S, Cont) ->
decode_fields(#state{x=X,stack=Stack}=S, Cont) ->
case X of
<<?STOP:8/signed,X1/binary>> ->
decode_done('struct', S#state{x=X1}, Cont);
decode_finish('struct', S#state{x=X1}, Cont);
<<Type:8/signed,Id:16/signed,X2/binary>> ->
case decode_field_type(Type) of
undefined ->
@@ -687,7 +722,7 @@ decode_fields(#state{x=X,stack=Stack}=S, Cont) ->
Name = <<>>,
Stack1 = push([Id, DecodedType, Name, 'field'], Stack),
Cont2 = fun(S2) -> decode_fields(S2, Cont) end,
Cont1 = fun(S1) -> decode_done('field', S1, Cont2) end,
Cont1 = fun(S1) -> decode_finish('field', S1, Cont2) end,
decode_type(Type, S#state{x=X2,stack=Stack1}, Cont1)
end;
_ ->
@@ -698,14 +733,14 @@ decode_field_data(#state{size=0}=S, Cont) ->
Cont(S#state{type=undefined,size=undefined});
decode_field_data(#state{type=Type,size=Size}=S, Cont) ->
Cont2 = fun(S2) -> decode_field_data(S2#state{type=Type,size=Size-1}, Cont) end,
Cont1 = fun(S1) -> decode_done('field-data', S1, Cont2) end,
Cont1 = fun(S1) -> decode_finish('field-data', S1, Cont2) end,
decode_type(Type, S, Cont1).
decode_field_datum(#state{size=0}=S, Cont) ->
Cont(S#state{type=undefined,size=undefined});
decode_field_datum(#state{type={KeyType,ValueType}=Type,size=Size}=S, Cont) ->
Cont3 = fun(S3) -> decode_field_datum(S3#state{type=Type,size=Size-1}, Cont) end,
Cont2 = fun(S2) -> decode_done('field-datum', S2, Cont3) end,
Cont2 = fun(S2) -> decode_finish('field-datum', S2, Cont3) end,
Cont1 = fun(S1) -> decode_type(ValueType, S1, Cont2) end,
decode_type(KeyType, S, Cont1).

View File

@@ -12,8 +12,9 @@
%%% client process. </li>
%%% </ul>
%%%
%%% Note that this library can support UBF(A), EBF, and JSF transport.
%%% See the `connect()' function arguments for details.
%%% Note that this library can support UBF(A), EBF, JSF, TBF, PBF, and
%%% ABF transport. See the `connect()' function arguments for
%%% details.
%%%
%%% This module also provides an alternative client-side function for
%%% calling's UBF contract manager and a UBF contract's implementation
@@ -42,7 +43,7 @@
-import(contract_manager, [do_lpcIn/4, do_lpcOut/9, do_lpcOutError/6]).
%% @type address() = string() | ip_address(). A DNS hostname or IP address.
%% @type connect_options() = list({proto, ubf | ebf | jsf}).
%% @type connect_options() = list({proto, ubf | ebf | jsf | tbf | pbf | abf}).
%% An OTP-style property list, see 'proplists' module for details.
%% @type ip_address() = string() | tuple(). An IP address in string form,
%% e.g. "127.0.0.1" (IPv4) or "::1" (IPv6), or in tuple form (see
@@ -142,6 +143,7 @@ ubf_client(Parent, Host, Port, Options, Timeout)
process_flag(trap_exit, true),
DefaultConnectOptions =
[binary, {nodelay, true}, {active, false}],
ServerHello = proplists:get_value(serverhello, Options, defined),
{DriverModule, DriverContract, DriverVersion, ConnectOptions} =
case proplists:get_value(proto,Options,ubf) of
ubf ->
@@ -149,7 +151,13 @@ ubf_client(Parent, Host, Port, Options, Timeout)
ebf ->
{ebf_driver, undefined, 'ebf1.0', DefaultConnectOptions++[{packet,4}]};
jsf ->
{jsf_driver, jsf, 'jsf1.0', DefaultConnectOptions}
{jsf_driver, jsf, 'jsf1.0', DefaultConnectOptions};
tbf ->
{tbf_driver, tbf, 'tbf1.0', DefaultConnectOptions};
pbf ->
{pbf_driver, pbf, 'pbf1.0', DefaultConnectOptions};
abf -> %% @TODO ubf_driver -> abf_driver
{ubf_driver, undefined, 'abf1.0', DefaultConnectOptions}
end,
case gen_tcp:connect(Host, Port, ConnectOptions) of
{ok, Socket} ->
@@ -163,18 +171,23 @@ ubf_client(Parent, Host, Port, Options, Timeout)
%%, {send_timeout, Timeout}
%%, {send_timeout_close, true}
]),
%% wait for a startup message
receive
{Driver, {DriverVersion, Service, _}} ->
Parent ! {self(), {ok, Service}},
ubf_client_loop(Parent, Driver);
{'EXIT', Driver, Reason} ->
Parent ! {self(), {error, Reason}};
{'EXIT', Parent, Reason} ->
exit(Driver, Reason)
after Timeout ->
exit(Driver, timeout),
Parent ! {self(), {error, timeout}}
if ServerHello =/= undefined ->
%% wait for a startup message
receive
{Driver, {DriverVersion, Service, _}} ->
Parent ! {self(), {ok, Service}},
ubf_client_loop(Parent, Driver);
{'EXIT', Driver, Reason} ->
Parent ! {self(), {error, Reason}};
{'EXIT', Parent, Reason} ->
exit(Driver, Reason)
after Timeout ->
exit(Driver, timeout),
Parent ! {self(), {error, timeout}}
end;
true ->
Parent ! {self(), {ok, undefined}},
ubf_client_loop(Parent, Driver)
end;
{error, _E} ->
Parent ! {self(), {error, socket}}

View File

@@ -24,13 +24,19 @@
%%% terms between a UBF(B) contract checking server and a client
%%% that does not support the UBF(A) wire format but does support
%%% Erlang's native wire formats. </li>
%%% <li> JSF, a.k.a the JSON Server Format. Similar to EBF, except
%%% <li> JSF, a.k.a the JSon Format. Similar to EBF, except
%%% that JavaScript's JSON encoding is used for the wire protocol
%%% instead of UBF(A) or Erlang's native wire formats.
%%% NOTE: This server is currently incomplete. Source code from
%%% Gemini Mobile Technologies, Inc. is not yet available to
%%% help glue JSF-style encoding to a full HTTP/JSON-RPC service.
%%% </li>
%%% instead of UBF(A) or Erlang's native wire formats.</li>
%%% <li> TBF, a.k.a the Thrift Binary Format. Similar to EBF, except
%%% that Thrift's binary encoding is used for the wire protocol
%%% instead of UBF(A) or Erlang's native wire formats.</li>
%%% <li> PBF, a.k.a the Google's Protocol Buffers Format. Similar to
%%% EBF, except that Google's Protocol Buffers binary encoding is used
%%% for the wire protocol instead of UBF(A) or Erlang's native wire
%%% formats.</li>
%%% <li> ABF, a.k.a the Avro Binary Format. Similar to EBF, except
%%% that Avro's binary encoding is used for the wire protocol
%%% instead of UBF(A) or Erlang's native wire formats.</li>
%%% </ul>
%%%
%%% There is no "stop" function. To stop the server, instead stop the
@@ -88,15 +94,17 @@ start(Name, PluginModules, Port) ->
%% <li> {maxconn, integer()} ... Maximum number of simultaneous TCP
%% connections allowed.
%% Default: 10,000. </li>
%% <li> {proto, {ubf | ebf | jsf}} ... Enable the UBF, EBF, or JSF version
%% of the protocol's wire format.
%% <li> {proto, {ubf | ebf | jsf | tbf | pbf | abf}} ... Enable the
%% UBF, EBF, JSF, TBF, PBF or ABF version of the protocol's wire
%% format.
%% Default: ubf. </li>
%% <li> {registeredname, atom()} ... Set the name to be registered for
%% the TCP listener. If undefined, a default name is automatically
%% registered.
%% Default: undefined. </li>
%% <li> {serverhello, string()} ... Meta contract greeting string, sent
%% when a client first connects to the server.
%% <li> {serverhello, string() | undefined} ... Meta contract greeting
%% string, sent when a client first connects to the server. If
%% undefined, server hello is not sent to the client.
%% Default: "meta_server" </li>
%% <li> {statelessrpc, true | false} ... run the stateless variety of
%% a UBF(B) contract. A stateless contract is an extension of
@@ -169,7 +177,13 @@ start_ubf_listener(MetaContract, Port, Server, Options) ->
ebf ->
{ebf_driver, 'ebf1.0', 4};
jsf ->
{jsf_driver, 'jsf1.0', 0}
{jsf_driver, 'jsf1.0', 0};
tbf ->
{tbf_driver, 'tbf1.0', 0};
pbf ->
{pbf_driver, 'pbf1.0', 0};
abf -> %% @TODO ubf_driver -> abf_driver
{ubf_driver, 'abf1.0', 0}
end,
IdleTimer =
case proplists:get_value(idletimer,Options,16#ffffffff) of
@@ -200,9 +214,13 @@ start_ubf_listener(MetaContract, Port, Server, Options) ->
contract_manager:start(ProcessOptions)
end,
Handler = ubf_plugin_handler:start_handler(ProcessOptions),
%% (The next three lines are pretty devious but they
%% work !) send hello back to the opening program
self() ! {self(), {DriverVersion, ?S(ServerHello), help()}},
%% Next few lines are pretty devious but they work!
if ServerHello =/= undefined ->
%% send hello back to the opening program
self() ! {self(), {DriverVersion, ?S(ServerHello), help()}};
true ->
noop
end,
%% swap the driver
contract_driver:relay(DriverModule, self(), ContractManager),
ContractManager !