{"id":675,"date":"2016-06-13T10:49:55","date_gmt":"2016-06-13T10:49:55","guid":{"rendered":"http:\/\/www.crazygaze.com\/blog\/?p=675"},"modified":"2016-06-13T14:36:49","modified_gmt":"2016-06-13T14:36:49","slug":"support-for-server-side-asynchronous-functions","status":"publish","type":"post","link":"https:\/\/www.crazygaze.com\/blog\/2016\/06\/13\/support-for-server-side-asynchronous-functions\/","title":{"rendered":"Support for server-side asynchronous functions"},"content":{"rendered":"<p>As I&#8217;ve mentioned at the end of <a href=\"http:\/\/www.crazygaze.com\/blog\/2016\/06\/06\/modern-c-lightweight-binary-rpc-framework-without-code-generation\/\">Modern C++ lightweight binary RPC framework without code generation<\/a>, one of the features I had in my previous RPC solution was to allow the server-side functions to be asynchronous, and let the framework take care of the details, since from the client perspective, nothing changes.<\/p>\n<p>This last weekend, I&#8217;ve added experimental support for that to <a href=\"https:\/\/bitbucket.org\/ruifig\/czrpc\">czrpc<\/a>.<\/p>\n<p>Lets see the problem. Consider these two classes that we want to use for RPC calls:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/\/ Example of class with synchronous API.\r\nclass Calculator {\r\npublic:\r\n    double add(double a, double b) {\r\n        return a + b;\r\n    }\r\n};\r\n\r\n\/\/ Example of class with asynchronous API, since it needs to\r\n\/\/ do some IO on a database\r\nclass Database {\r\npublic:\r\n    \/\/ This returns a future, and not a readily available value\r\n    std::future&lt;bool&gt; checkLogin(const std::string&amp; name,\r\n                                 const std::string&amp; pass);\r\n};\r\n<\/pre>\n<p>From czrpc&#8217;s perspective, sending a result back to the client is easy enough for servers of <code>Calculator<\/code>. The <code>add<\/code> method returns the value right away (it&#8217;s synchronous). All czrpc has to do when the server-side code gets the RPC request from the client is to write the result of the method call to the output stream and send that output stream back to the client. Everything is linear. Akin to:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\noutStream &lt;&lt; obj.add(a, b);\r\n\/\/ send the contents of outStream to the client...\r\n<\/pre>\n<p>Now, for the <code>Database<\/code> case, the <code>checkLogin<\/code> method returns a <code>std::future&lt;bool&gt;<\/code>, and not a readily available value (it&#8217;s asynchronous).<br \/>\nTherefore, czrpc can&#8217;t return the result right away to the client when it receives the RPC request. Internally, it needs to know that <code>checkLogin<\/code> is asynchronous. When a client calls that RPC, it adds the resulting <code>std::future&lt;bool&gt;<\/code> to a list of pending results, and whenever that future is ready, it retrieves the result and sends it back to the client.<\/p>\n<p>From the user code perspective, nothing needs to change. Example (ignoring any setup code):<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/\/ Define the RPC table for Calculator\r\n#define RPCTABLE_CLASS Calculator\r\n#define RPCTABLE_CONTENTS \\\r\n    REGISTERRPC(add)\r\n#include &quot;crazygaze\/rpc\/RPCGenerate.h&quot;\r\n\r\n\/\/ Define the RPC table for Database. The framework automatically detects that\r\n\/\/ &quot;checkLogin&quot; returns std::future\r\n#define RPCTABLE_CLASS Database\r\n#define RPCTABLE_CONTENTS \\\r\n    REGISTERRPC(checkLogin)\r\n#include &quot;crazygaze\/rpc\/RPCGenerate.h&quot;\r\n\r\n\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\r\nvoid TestClients() {\r\n    \/\/ Initialize asio io_service here ...\r\n\r\n    \/\/ Connect to the Calculator server\r\n    auto calcCon =\r\n        AsioTransport&lt;void, Calculator&gt;::create(io, &quot;127.0.0.1&quot;, 9000).get();\r\n    \/\/ Call an RPC on Calculator\r\n    CZRPC_CALL(*calcCon, add, 1, 2)\r\n        .async([](Result&lt;double&gt; res) {\r\n            printf(&quot;Result=%f\\n&quot;, res.get());  \/\/ Prints 3.0\r\n        });\r\n\r\n    \/\/ Connect to the database server.\r\n    auto dbCon =\r\n        AsioTransport&lt;void, Database&gt;::create(io, &quot;127.0.0.1&quot;, 9001).get();\r\n    \/\/ For the client, it doesn't matter if the server side API is asynchronous.\r\n    \/\/ It still only has to deal with a Result&lt;T&gt;\r\n    CZRPC_CALL(*dbCon, checkLogin, &quot;Rui&quot;, &quot;Meow&quot;)\r\n        .async([](Result&lt;bool&gt; res) {\r\n            printf(&quot;Result=%s\\n&quot;, res.get() ? &quot;true&quot; : &quot;false&quot;);\r\n        });\r\n\r\n    \/\/ Shutdown here ...\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>As I&#8217;ve mentioned at the end of Modern C++ lightweight binary RPC framework without code generation, one of the features I had in my previous RPC solution was to allow the server-side functions to be asynchronous, and let the framework take care of the details, since from the client perspective, nothing changes. This last weekend, [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_mi_skip_tracking":false,"spay_email":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true},"categories":[50,3],"tags":[14,55,10,56,15],"jetpack_featured_media_url":"","jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p7jpe0-aT","_links":{"self":[{"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/posts\/675"}],"collection":[{"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/comments?post=675"}],"version-history":[{"count":6,"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/posts\/675\/revisions"}],"predecessor-version":[{"id":682,"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/posts\/675\/revisions\/682"}],"wp:attachment":[{"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/media?parent=675"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/categories?post=675"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.crazygaze.com\/blog\/wp-json\/wp\/v2\/tags?post=675"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}