4
5

More than 5 years have passed since last update.

ES.next的にNode.jsでJSON-RPCする

Last updated at Posted at 2013-06-02

気づいたら自分の投稿が合計100回もストックされていました。みなさんありがとうございます、あらっきぃです。

method_missing を利用して動的にAPIのエンドポイントにアクセスする を読んで、ES.nextのProxyを使ってJSON-RPCを呼んだら面白そうな気がしたので実装しました。

ちゃちゃっと作ったものだし、そもそも似たようなライブラリがすでにありそう。

ちなみにJSON-RPCというのは、リモート環境にある関数をネットワークからJSONにデータを載せてでリクエストして、実行するプロトコルです。
Ideone APIとかで使えます。(というかそれでしか使ったことない)

jsonrpc.js
var
request = require('request');

function JsonRpcClient(url) {
  return Proxy.create({
    get: function(_, method) {
      var
      requester = function() {
        var
        args = Array.prototype.slice.call(arguments, 0);
        return call.bind(this, method, args);
      };
      requester.call = function(params, callback) {
        call(method, params, callback);
      };
      return requester;
    }
  });

  function call(method, params, callback) {
    var
    body = JSON.stringify({
      jsonrpc: '2.0',
      id: +(new Date),
      method: method,
      params: params,
    });
    request(url, {
      method: 'POST',
      body: body,
      header: {
        'Content-Length': Buffer.byteLength(body, encoding='utf8'),
      },
      json: true,
    }, function(err, res, body) {
      if(body && body.error) {
        err = new Error(body.error.msg);
        err.data = body.error;
      }

      callback(err, body && body.result);
    });
  }
}

module.exports = {
  createClient : JsonRpcClient,
};

例として ideone のAPIを呼んでみます。
userpassは自分のものを使ってください。

また、このコードを実行するためには上記のjsonrpc.jsと同じディレクトリに置いて,
nodeに--harmony-proxiesオプションを付けてください。

ideone.js
var
async  = require('async'),
ideone = require('./jsonrpc').createClient('http://ideone.com/api/1/service.json');

var
user   = 'your user',
pass   = 'your pass',
lang   = {'python': 4, 'ruby': 17}['ruby'],
src    = 'puts "Hello, World!"',
input  = '';

/*
ideone.testFunction(user, pass)(function(err, res) {
  console.log(res);
});
*/

async.waterfall([
  function(next) {
    console.log('createSubmission');
    ideone.createSubmission(user, pass, src, lang, input, true, false)(next);
  },
  function loop(data, next) {
    var
    link = data.link;
    console.log('getSubmissionStatus: %s', link);
    ideone.getSubmissionStatus(user, pass, link)(function(err, res) {
      console.log(res);
      if(err){
        next(err);
        return;
      }
      if(res.status == 0){
        next(null, link);
        return;
      }
      setTimeout(function(){
        loop(data, next);
      }, 100);
    });
  },
  function(link, next) {
    console.log('getSubmissionDetails');
    ideone.getSubmissionDetails(user, pass, link, false, false, true, true, true)(next);
  },
], function(err, result) {
  if(err) {
    console.log(err);
    return;
  }
  console.log(result);
});

ideone.createSubmissionのように、APIをメソッドのように呼び出していることに注目!

ところでgetSubmissionStatusを呼び出して実行の終了を確かめている辺り、async.jsを使ってもっとスムーズに実装できたりしないんでしょうか?

参考

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5