210 lines
5.0 KiB
V
210 lines
5.0 KiB
V
module mycelium
|
|
|
|
import json
|
|
import encoding.base64
|
|
import incubaid.herolib.core.httpconnection
|
|
|
|
// Represents a destination for a message, can be either IP or public key
|
|
pub struct MessageDestination {
|
|
pub:
|
|
ip string @[omitempty] // IP in the subnet of the receiver node
|
|
pk string @[omitempty] // hex encoded public key of the receiver node
|
|
}
|
|
|
|
// Body of a message to be sent
|
|
pub struct PushMessageBody {
|
|
pub:
|
|
dst MessageDestination
|
|
topic ?string // optional message topic
|
|
payload string // base64 encoded message
|
|
}
|
|
|
|
// Response containing message ID after pushing
|
|
pub struct PushMessageResponseId {
|
|
pub:
|
|
id string // hex encoded message ID
|
|
}
|
|
|
|
// A message received by the system
|
|
pub struct InboundMessage {
|
|
pub:
|
|
id string
|
|
src_ip string @[json: 'srcIp'] // Sender overlay IP address
|
|
src_pk string @[json: 'srcPk'] // Sender public key, hex encoded
|
|
dst_ip string @[json: 'dstIp'] // Receiver overlay IP address
|
|
dst_pk string @[json: 'dstPk'] // Receiver public key, hex encoded
|
|
topic string // Optional message topic
|
|
payload string // Message payload, base64 encoded
|
|
}
|
|
|
|
// Information about an outbound message
|
|
pub struct MessageStatusResponse {
|
|
pub:
|
|
dst string // IP address of receiving node
|
|
state string // pending, received, read, aborted or sending object
|
|
created i64 // Unix timestamp of creation
|
|
deadline i64 // Unix timestamp of expiry
|
|
msg_len int @[json: 'msgLen'] // Length in bytes
|
|
}
|
|
|
|
// General information about a node
|
|
pub struct Info {
|
|
pub:
|
|
node_subnet string @[json: 'nodeSubnet'] // subnet owned by node
|
|
}
|
|
|
|
// Response containing public key for a node IP
|
|
pub struct PublicKeyResponse {
|
|
pub:
|
|
node_pub_key string @[json: 'NodePubKey'] // hex encoded public key
|
|
}
|
|
|
|
// Get connection to mycelium server
|
|
pub fn (mut self Mycelium) connection() !&httpconnection.HTTPConnection {
|
|
mut c := self.conn or {
|
|
mut c2 := httpconnection.new(
|
|
name: 'mycelium'
|
|
url: self.server_url
|
|
retry: 3
|
|
)!
|
|
c2
|
|
}
|
|
|
|
return c
|
|
}
|
|
|
|
@[params]
|
|
pub struct SendMessageArgs {
|
|
pub mut:
|
|
public_key string @[required]
|
|
payload string @[required]
|
|
topic ?string
|
|
wait bool
|
|
}
|
|
|
|
// Send a message to a node identified by public key
|
|
pub fn (mut self Mycelium) send_msg(args SendMessageArgs) !InboundMessage {
|
|
mut conn := self.connection()!
|
|
mut body := PushMessageBody{
|
|
dst: MessageDestination{
|
|
pk: args.public_key
|
|
ip: ''
|
|
}
|
|
payload: base64.encode_str(args.payload)
|
|
topic: if v := args.topic {
|
|
base64.encode_str(v)
|
|
} else {
|
|
none
|
|
}
|
|
}
|
|
mut prefix := '/api/v1/messages'
|
|
if args.wait {
|
|
prefix += '?reply_timeout=120'
|
|
}
|
|
return conn.post_json_generic[InboundMessage](
|
|
method: .post
|
|
prefix: prefix
|
|
data: json.encode(body)
|
|
dataformat: .json
|
|
)!
|
|
}
|
|
|
|
@[params]
|
|
pub struct ReceiveMessageArgs {
|
|
pub mut:
|
|
topic ?string
|
|
wait bool
|
|
peek bool
|
|
}
|
|
|
|
// Receive a message from the queue
|
|
pub fn (mut self Mycelium) receive_msg(args ReceiveMessageArgs) !InboundMessage {
|
|
mut conn := self.connection()!
|
|
mut prefix := '/api/v1/messages?peek=${args.peek}&'
|
|
|
|
if args.wait {
|
|
prefix += 'timeout=120&'
|
|
}
|
|
|
|
if v := args.topic {
|
|
prefix += 'topic=${base64.encode_str(v)}'
|
|
}
|
|
|
|
return conn.get_json_generic[InboundMessage](
|
|
method: .get
|
|
prefix: prefix
|
|
dataformat: .json
|
|
)!
|
|
}
|
|
|
|
// Optional version of receive_msg that returns none on 204
|
|
pub fn (mut self Mycelium) receive_msg_opt(args ReceiveMessageArgs) ?InboundMessage {
|
|
res := self.receive_msg(args) or {
|
|
if err.msg().contains('204') {
|
|
return none
|
|
}
|
|
panic(err)
|
|
}
|
|
return res
|
|
}
|
|
|
|
// Get status of a message by ID
|
|
pub fn (mut self Mycelium) get_msg_status(id string) !MessageStatusResponse {
|
|
mut conn := self.connection()!
|
|
return conn.get_json_generic[MessageStatusResponse](
|
|
method: .get
|
|
prefix: '/api/v1/messages/status/${id}'
|
|
dataformat: .json
|
|
)!
|
|
}
|
|
|
|
@[params]
|
|
pub struct ReplyMessageArgs {
|
|
pub mut:
|
|
id string @[required]
|
|
public_key string @[required]
|
|
payload string @[required]
|
|
topic ?string
|
|
}
|
|
|
|
// Reply to a message
|
|
pub fn (mut self Mycelium) reply_msg(args ReplyMessageArgs) ! {
|
|
mut conn := self.connection()!
|
|
mut body := PushMessageBody{
|
|
dst: MessageDestination{
|
|
pk: args.public_key
|
|
ip: ''
|
|
}
|
|
payload: base64.encode_str(args.payload)
|
|
topic: if v := args.topic { base64.encode_str(v) } else { none }
|
|
}
|
|
_ := conn.post_json_str(
|
|
method: .post
|
|
prefix: '/api/v1/messages/reply/${args.id}'
|
|
data: json.encode(body)
|
|
dataformat: .json
|
|
)!
|
|
}
|
|
|
|
// curl -v -H 'Content-Type: application/json' -d '{"dst": {"pk": "be4bf135d60b7e43a46be1ad68f955cdc1209a3c55dc30d00c4463b1dace4377"}, "payload": "xuV+"}' http://localhost:8989/api/v1/messages\
|
|
|
|
// Get node info
|
|
pub fn (mut self Mycelium) get_info() !Info {
|
|
mut conn := self.connection()!
|
|
return conn.get_json_generic[Info](
|
|
method: .get
|
|
prefix: '/api/v1/admin'
|
|
dataformat: .json
|
|
)!
|
|
}
|
|
|
|
// Get public key for a node IP
|
|
pub fn (mut self Mycelium) get_pubkey_from_ip(ip string) !PublicKeyResponse {
|
|
mut conn := self.connection()!
|
|
return conn.get_json_generic[PublicKeyResponse](
|
|
method: .get
|
|
prefix: '/api/v1/pubkey/${ip}'
|
|
dataformat: .json
|
|
)!
|
|
}
|