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:
48
edoc/abf.html
Normal file
48
edoc/abf.html
Normal 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) -> 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) -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="decode_init-0">decode_init/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>decode_init() -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="encode-3">encode/3</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>encode(X, Mod, State) -> 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
53
edoc/abf_driver.html
Normal 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) -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="encode-2">encode/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>encode(Contract, Term) -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="init-1">init/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>init(Contract) -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="start-1">start/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>start(Contract) -> 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>
|
||||
@@ -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]}.
|
||||
|
||||
@@ -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
114
edoc/pbf.html
Normal 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<->Erlang data conversion.
|
||||
|
||||
|
||||
<h2><a name="description">Description</a></h2><p>Functions for Google's Protocol Buffers<->Erlang data conversion.</p>
|
||||
|
||||
<p>For most purposes, these functions are not called by code outside
|
||||
of this library: Erlang client & 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) -> 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) -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="contract_records-0">contract_records/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>contract_records() -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="decode-1">decode/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>decode(X) -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="decode-2">decode/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>decode(X, Mod) -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="decode-3">decode/3</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>decode(X, Mod, X3) -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="decode_init-0">decode_init/0</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>decode_init() -> 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) -> 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) -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="encode-1">encode/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>encode(X) -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="encode-2">encode/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>encode(X, Mod) -> 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) -> 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) -> 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
55
edoc/pbf_driver.html
Normal 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) -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="encode-2">encode/2</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>encode(Contract, Term) -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="init-1">init/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>init(Contract) -> any()</tt></p>
|
||||
</div>
|
||||
|
||||
<h3 class="function"><a name="start-1">start/1</a></h3>
|
||||
<div class="spec">
|
||||
<p><tt>start(Contract) -> 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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -25,6 +25,10 @@ MODULES = \
|
||||
ebf_driver \
|
||||
tbf \
|
||||
tbf_driver \
|
||||
pbf \
|
||||
pbf_driver \
|
||||
abf \
|
||||
abf_driver \
|
||||
ubf_plugin_meta_stateful \
|
||||
ubf_plugin_meta_stateless
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
109
src/abf.erl
Normal file
@@ -0,0 +1,109 @@
|
||||
%%
|
||||
%% For most purposes, these functions are not called by code outside of
|
||||
%% this library: Erlang client & 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
39
src/abf_driver.erl
Normal 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).
|
||||
@@ -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}}.
|
||||
|
||||
@@ -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
145
src/pbf.erl
Normal file
@@ -0,0 +1,145 @@
|
||||
%% @doc Functions for Google's Protocol Buffers<->Erlang data conversion.
|
||||
%%
|
||||
%% For most purposes, these functions are not called by code outside
|
||||
%% of this library: Erlang client & 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
30
src/pbf_driver.erl
Normal 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).
|
||||
129
src/tbf.erl
129
src/tbf.erl
@@ -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).
|
||||
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -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 !
|
||||
|
||||
Reference in New Issue
Block a user