ipc.cr-old/src/ipc/message.cr

112 lines
2.6 KiB
Crystal

require "cbor"
require "json"
# JSON is currently used for messages over websockets
# At some point, this will be replaced by the CBOR format
class IPC::Message
property fd : Int32 # file descriptor
property mtype : UInt8 # libipc message type
property utype : UInt8 # libipc user message type
property payload : Bytes
# Clients send and receive JSON (or CBOR) payloads.
struct JSONMessage
include JSON::Serializable
property mtype : UInt8 = 1 # libipc message type
property utype : UInt8 # libipc user message type
property payload : String
def initialize(@utype, @payload, @mtype = 1)
end
end
def self.from_json (str : String) : IPC::Message
jsonmessage = JSONMessage.from_json str
IPC::Message.new 0, jsonmessage.mtype, jsonmessage.utype, jsonmessage.payload
end
def to_json : String
JSONMessage.new(@utype, String.new(@payload), @mtype).to_json
end
struct CBORMessage
include CBOR::Serializable
property mtype : UInt8 = 1 # libipc message type
property utype : UInt8 # libipc user message type
property payload : Bytes
def initialize(@utype, @payload, @mtype = 1)
end
end
def self.from_cbor (m : Bytes) : IPC::Message
cbor_message = CBORMessage.from_cbor m
IPC::Message.new 0, cbor_message.mtype, cbor_message.utype, cbor_message.payload
end
def to_cbor : Bytes
CBORMessage.new(@utype, @payload, @mtype).to_cbor
end
def initialize(message : Pointer(LibIPC::Message))
if message.null?
@mtype = LibIPC::MessageType::Error.to_u8
@fd = 0
@utype = 0
@payload = Bytes.new "".to_unsafe, 0
else
m = message.value
@fd = m.fd
@mtype = m.type
@utype = m.user_type
@payload = Bytes.new m.payload, m.length
end
end
def initialize(message : LibIPC::Message)
initialize pointerof(message)
end
def initialize(@fd, mtype, @utype, @payload : Bytes)
@mtype = mtype.to_u8
end
def initialize(fd, mtype, utype, payload : String)
initialize(fd, mtype, utype, Bytes.new(payload.to_unsafe, payload.bytesize))
end
def self.to_packet (user_type : Int, message : String)
payload = Bytes.new (6 + message.to_slice.size)
# true start
payload[0] = 1.to_u8
IO::ByteFormat::NetworkEndian.encode message.to_slice.size, (payload + 1)
# second part: user message
payload[5] = user_type.to_u8
(payload + 6).copy_from message.to_slice
return payload
end
def to_packet
IPC::Message.to_packet @utype, String.new(@payload)
end
def copy_to_message_pointer(pm : LibIPC::Message*)
LibIPC.ipc_message_copy pm, @fd, @mtype, @utype, @payload, @payload.size
end
def to_s
"(internal) utype #{@mtype}, (user) utype #{@utype}, payload #{String.new @payload}"
end
end