dRubyをWebSocketに載せるために、dRubyの1つの情報をWebSocketの1つのテキストフレームとして送信する方針で実装してみました。 でも、よく考えたら非効率っぽいのでやめました。
- WebSocketのフレームのヘッダーは6バイト
- dRubyはシンプルなLength-Prefixed Protocolでヘッダーは4バイト
- dRubyのsend_requestで少なくとも5つの情報を送る
テキストフレームを情報ごとに5分割するとフレームヘッダーが6x5=30バイト必要です。 一つのテキストフレームに5つの情報をまとめて送ればフレームヘッダー 6 + dRubyヘッダー 4x5=26バイトで済みます。
前者の方が「WebSocketを使いこなしているっぽい」と思ってはしゃいで実装しました。 残念です。 供養のためにコードをここに残しておきます。
# frozen_string_literal: true require "drb/drb" module DRbWebSocket # Send and receive messages for DRb over WebSocket. # Use TextFrame for WebSocket. class DRbMessage < DRb::DRbMessage def send_request(stream, ref, msg_id, arg, b) stream.write(dump(ref.__drbref)) stream.write(dump(msg_id.id2name)) stream.write(dump(arg.length)) arg.each do |e| stream.write(dump(e)) end stream.write(dump(b)) rescue StandardError raise(DRbConnError, $ERROR_INFO.message, $ERROR_INFO.backtrace) end def recv_request(stream) ref = load(stream) ro = DRb.to_obj(ref) msg = load(stream) argc = load(stream) raise(DRbConnError, "too many arguments") if @argc_limit < argc argv = Array.new(argc, nil) argc.times do |n| argv[n] = load(stream) end block = load(stream) [ro, msg, argv, block] end def send_reply(stream, succ, result) stream.write(dump(succ)) stream.write(dump(result, !succ)) rescue StandardError raise(DRbConnError, $ERROR_INFO.message, $ERROR_INFO.backtrace) end def load(soc) begin str = soc.gets rescue StandardError raise(DRb::DRbConnError, $ERROR_INFO.message, $ERROR_INFO.backtrace) end raise(DRb::DRbConnError, "connection closed") if str.nil? DRb.mutex.synchronize do Marshal.load(str) rescue NameError, ArgumentError DRbUnknown.new($ERROR_INFO, str) end end def dump(obj, error = false) case obj when DRbUndumped obj = make_proxy(obj, error) when Object # nothing else obj = make_proxy(obj, error) end begin str = Marshal.dump(obj) rescue StandardError str = Marshal.dump(make_proxy(obj, error)) end str end end end