LoginSignup
6
2

More than 5 years have passed since last update.

RubyでNEMのWebSocketを使う

Last updated at Posted at 2018-03-07

はじめに

RubyでNEMのWebSocketを扱った前例が無かったので調査しました。WebSocketやSTOMPの仕組みなどの解説はここでは省略します。

実装

require "json"
require 'websocket-client-simple'
require 'stomp_parser'
require 'securerandom'


host = "http://alice3.nem.ninja"
port = 7778
path = "/w/messages/"
server = format("%0#{3}d", SecureRandom.random_number(10**3))
strings = [('a'..'z'), ('0'..'5')].map { |i| i.to_a }.flatten
session = (0...8).map { strings[rand(strings.length)] }.join

endpoint = host + ":" + port.to_s + path + server.to_s + "/" +session + "/websocket/"

ws = WebSocket::Client::Simple.connect(endpoint)
ws.on :open do
  connect_header = {"accept-version":"1.1,1.0","heart-beat":"10000,10000"}
  stomp_connect = '["' + StompParser::Frame.new("CONNECT", connect_header,"").to_str + '"]'
  ws.send(stomp_connect)
end

ws.on :message do |msg|
  if msg.data[0] == "o"

  end

  if msg.data[0] == "h"

  end
  if msg.data[0] == "a"
    data = msg.data
    data.slice!(0,data.index("[")+2)
    data.slice!(data.rindex("]")-1,data.length)
    data.gsub!("\\n","\n")
    data.gsub!("\\r","\r")
    data.gsub!("\\/","\/")
    data.gsub!("\\u0000","\u0000")
    data.gsub!("\\\"","\"")
    parser = StompParser::Parser.new
    parser.parse(data) do |frame|
      puts "We received #{frame.command} frame with #{frame.body} and headers #{frame.headers}!"
      if frame.command == "CONNECTED"
        blocks_header = {"id":"sub-0","destination":"/blocks"}
        stomp_subscribe_blocks = '["' + StompParser::Frame.new("SUBSCRIBE", blocks_header, "").to_str + '"]'
        ws.send(stomp_subscribe_blocks)
      end
      if frame.command == "MESSAGE"
        result = JSON.parse(frame.body)
        p result["timeStamp"]
      end
    end
  end
end

ws.on :error do |e|
  p(e)
end

loop do

end

解説

以下のような動作を行っています。

  1. 接続先のURLを生成する

    • 接続先はhttp://ホスト名:websocket用のポート/w/messages/3桁の数字で構成された乱数/8桁の小文字の英字と0~5の数字で構成された乱数/となります。
  2. WebSocketClientを用いて接続する

    • websocket-client-simpleを使用させていただきました。
  3. open時にCONNECTコマンドを送信する

    • 以下のSUBSCRIBEコマンドの場合もですが、STOMPパーサーを使うとハッシュから楽にSTOMPに対応した文字列を生成できます。
    • SockJSの仕様か、生成したフレームは[""]で覆わないとサーバー側からの返信が来ません。
  4. サーバーから通知が来たらデータの最初の一文字目で分岐する

    • "o"はサーバーがframeを開いた時に送信されるようです。
    • "h"はサーバーからのハートビートです。
    • "a"は[]内にサーバーからのデータが含まれています。
  5. CONNECTEDコマンドを含む通知が来たらSUBSCRIBEコマンドを送信する

    • 受信時のデータは余分なバックスラッシュ等余計なものが多く、そのままではパースできないのでここで綺麗にしています。
    • このプログラムでは最新ブロック高監視を行っています。
  6. MESSAGEコマンドを含む通知が来たらbodyをパース後データを表示

    • MESSAGEコマンドを含むフレームのbodyは通常のAPIと同じくjsonで記述されているので、簡単にパースできます。

詳細

こちらにWebSocketなどの技術解説や調査方法についてまとめました。
この調査を元にしてrubyでnemのwebsocketを扱えるgemを作りました。詳しくは こちらへどうぞ。

参考

github - varvet/stomp_parser
github - shokai/websocket-client-simple
github - sockjs/sockjs-client
github - sockjs/sockjs-protocol
田舎からGeekを目指す - NEMのWebSocket通信を使ってみた

6
2
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
6
2