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