RPC通信のdnodeモジュールを使ってみた


Nodebot-workshopにdnodeを使う部分があるんですよね。
dnodeってなんだろって思ったので調べてみました。

![](https://camo.githubusercontent.com/4d670b404676927ab953876b7f50811284a649a4/687474703a2f2f737562737461636b2e6e65742f696d616765732f646e6f64652e706e67)

※ 関係あるのか無いのか分からないけど、謎に`新人プログラマ応援`タグをつけてみました。応援してますよ！笑

## dnode

RPCをNode.jsで使うためのモジュールです。

>dnode is an asynchronous rpc system for node.js that lets you call remote functions.
You can pass callbacks to remote functions, and the remote end can call the functions you passed in with callbacks of its own and so on. It's callbacks all the way down!

https://github.com/substack/dnode

##RPC

リモートプロシージャコール

http://www.weblio.jp/content/RPC
http://e-words.jp/w/RPC.html
https://ja.wikipedia.org/wiki/RPC

>リモートプロシージャコールとは、ネットワークによって接続された他のコンピュータ上でプログラムを呼び出し、実行させるための手法のことである。あるいは、そのためのプロトコルのことである。

ネットワーク系が弱いのでTCP上なのか別のレイヤーなのかいまいち理解してないですが、サーバー/クライアント通信やM2Mな通信に使えるプロトコルの一つとして使えそうという感覚で覚えておきます。(ツッコミ待ち)

`プロシージャ・コールの特徴は，何といってもリアルタイム性だ`って解説もありますが、`プロシージャ・コールはトラブルに弱い。`って解説もあります。利用シーンを選びそうですね。

>http://itpro.nikkeibp.co.jp/article/lecture/20061215/257077/?rt=nocnt

## 使ってみる

* バージョン

```
$ node -v
v5.7.1
```

* インストール

```bash
$ npm i dnode
```

* サーバー側

port5004で待ち受けるサーバーです。
サーバーは小文字で送られた文字列を大文字にして返します。

```server.js
'use strict'

/*小文字で来た文字列を大文字にして返す*/

const dnode = require('dnode');
const server = dnode({
    transform : (s, cb) => {
        console.log('受信: '+ s);
        let res = s.replace(/[aeiou]{2,}/, 'oo').toUpperCase();
        console.log('返信: '+ res);
        cb(res);
    }
});

server.listen(5004);
```

* クライアント側

beepという文字列を送ります。

```client.js
'use strict'

const dnode = require('dnode');
const d = dnode.connect(5004);

d.on('remote', (remote) => {
    remote.transform('beep', (s) => {
        console.log('beep => ' + s);
        d.end();
    });
});
```

* 実行

```bash
$ node server.js

(受信したら)
受信: beep
返信: BOOP
```

```bash
$ node client.js
beep => BOOP
```

![](https://i.gyazo.com/6afea249d41a81bcd001664cdf3f875e.gif)

こんな感じでプロセス間の通信ができます。

## streaming

node.jsのstream apiのインターフェイスを使って`.pipe`な形でtcpとrpcを連結できます。

* サーバー側

```
'use strict'

/*小文字で来た文字列を大文字にして返す*/

const dnode = require('dnode');
const net = require('net');

const server = net.createServer((c) => {
    let d = dnode({
        transform : (s, cb) => {
          console.log('受信: '+ s);
          let res = s.replace(/[aeiou]{2,}/, 'oo').toUpperCase();
          console.log('返信: '+ res);
          cb(res);
        }
    });
    c.pipe(d).pipe(c);
});

server.listen(5004);
```

* クライアント側

```
'use strict'

const dnode = require('dnode');
const net = require('net');

const d = dnode();
const c = net.connect(5004);

d.on('remote', (remote) => {
    remote.transform('beep', (s) => {
        console.log('beep => ' + s);
        d.end();
    });
});

c.pipe(d).pipe(c);

```

## Webとつなげてみる

ブラウザからRPCサーバーと接続してみましょう。

* インストール

```bash
$ npm i dnode shoe ecstatic domready
$ npm install -g browserify
```

* サーバー側

dnodeと同じ開発者が作っている`shoe`というモジュールを使っています。
https://github.com/substack/shoe

[sockjs](https://github.com/sockjs/sockjs-node)(靴下)のラッパーだからshoe(靴)なんですね笑

[ecstatic](https://www.npmjs.com/package/ecstatic)は静的ファイルを利用するためのミドルウェアみたいです。


```server.js
'use strict'

const http = require('http');
const shoe = require('shoe');
const ecstatic = require('ecstatic')(__dirname + '/static');
const dnode = require('dnode');

const server = http.createServer(ecstatic);
server.listen(9999);

const sock = shoe((stream) => {
  let d = dnode({
    transform : (s, cb) => {
      console.log('受信: '+ s);
      let res = s.replace(/[aeiou]{2,}/, 'oo').toUpperCase();
      console.log('返信: '+ res);
      cb(res);
    }
  });

  d.pipe(stream).pipe(d);
});

sock.install(server, '/dnode');
```

* クライアント側

[domready](https://www.npmjs.com/package/domready)というモジュールを使っています。

```client.js
'use strict'

const domready = require('domready');
const shoe = require('shoe');
const dnode = require('dnode');

domready(() => {
    let result = document.getElementById('result');
    let stream = shoe('/dnode');

    let d = dnode();
    d.on('remote', (remote) => {
        remote.transform('beep', (s) => {
            result.textContent = 'beep => ' + s;
        });
    });
    d.pipe(stream).pipe(d);
});
```

browserifyを使ってブラウザ側で利用できるようにします。
staticフォルダ内にbundle.jsとして出力します。

```bash
$ browserify client.js -o static/bundle.js
```


index.htmlをstaticフォルダ内に作ります。

```index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <script src="/bundle.js"></script>
    <div id="result"></div>
  </body>
</html>
```

ディレクトリ構成はこんな感じです

![](https://i.gyazo.com/161e659b655723bf7ac84c18329d7217.png)

* 実行

```bash
$ node server.js
```

サーバー起動をすると [localhot:9999](http://localhot:9999) にstatic/index.htmlがホスティングされます。(僕の認識だと)アクセスするとhttp -> websocket -> rpc みたいな流れでサーバーと通信できます。

![](https://i.gyazo.com/8289bb53e9ae6615144e8a84f1904d15.gif)

## まとめ

dnodeのサンプルはいい感じに動作してくれたので安心です。これを元に(RPC自体がむいてないかもだけど)チャットとかも作れそうですね。

関係無いけど、最近はgRPCが流行ってましたよね。
http://www.apps-gcp.com/grpc-go/#gRPC

こっちの方も使ってみたいなと思いつつ書いた記事でした笑