mirror of
https://github.com/logos-messaging/nim-chat-poc.git
synced 2026-01-02 14:13:10 +00:00
initial pass impl
This commit is contained in:
parent
85e6980593
commit
cdaceef413
159
src/chat_sdk/delivery/multicast_client.nim
Normal file
159
src/chat_sdk/delivery/multicast_client.nim
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
import std/net
|
||||||
|
import strformat
|
||||||
|
import chronos
|
||||||
|
import posix
|
||||||
|
import tables
|
||||||
|
import hashes
|
||||||
|
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Multicast Utils
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
const MSG_LEN = 1024
|
||||||
|
const MCAST_GRP = "239.18.0.10"
|
||||||
|
const MCAST_PORT = 18010
|
||||||
|
|
||||||
|
|
||||||
|
# These are the MacOS specific values for the multicast socket options names
|
||||||
|
const IP_ADD_MEMBERSHIP = 12
|
||||||
|
const IP_DROP_MEMBERSHIP = 13
|
||||||
|
|
||||||
|
type
|
||||||
|
ip_mreq {.pure, final.} = object
|
||||||
|
imr_multiaddr*: InAddrT
|
||||||
|
imr_interface*: InAddrT
|
||||||
|
|
||||||
|
# This function creates the posix struct needed to join a multicast group.
|
||||||
|
# It is not defined in chronos so we define it here.
|
||||||
|
proc joinMulticast(socket: AsyncFD, groupAddr: string) =
|
||||||
|
|
||||||
|
let mreq = ip_mreq(
|
||||||
|
imr_multiaddr: inet_addr(groupAddr),
|
||||||
|
imr_interface: INADDR_ANY # INADDR_ANY - any interface
|
||||||
|
)
|
||||||
|
|
||||||
|
socket.setSockOpt2(IPPROTO_IP, IP_ADD_MEMBERSHIP, addr mreq, sizeof(mreq)).isOkOr:
|
||||||
|
echo "Failed to join multicast group"
|
||||||
|
quit(1) # TODO: Fail gracefully
|
||||||
|
echo "Joined multicast group ", groupAddr
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Types
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
type WapEnvelopeV1* = string
|
||||||
|
|
||||||
|
type MulticastConfig* = object
|
||||||
|
mcast_port: int
|
||||||
|
mcast_grp_start: string
|
||||||
|
mcast_grp_count: int
|
||||||
|
|
||||||
|
|
||||||
|
proc DefaultConfig*(): MulticastConfig =
|
||||||
|
result = MulticastConfig(
|
||||||
|
mcast_port: 18010,
|
||||||
|
mcast_grp_start: "239.18.0.10",
|
||||||
|
mcast_grp_count: 5,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
MulticastClient* = object
|
||||||
|
cfg: MulticastConfig
|
||||||
|
sendSocket*: DatagramTransport
|
||||||
|
listenSocket*: DatagramTransport
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Accessors and Getters
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
|
||||||
|
proc getListenAddress*(cfg: MulticastConfig): TransportAddress =
|
||||||
|
result = initTAddress(fmt"0.0.0.0:{cfg.mcast_port}")
|
||||||
|
|
||||||
|
proc getBaseAddress*(cfg: MulticastConfig): TransportAddress =
|
||||||
|
result = initTAddress(fmt"{cfg.mcast_grp_start}:{cfg.mcast_port}")
|
||||||
|
|
||||||
|
proc offsetAddress*(address: TransportAddress, offset: uint8): TransportAddress =
|
||||||
|
var newAddress = address
|
||||||
|
|
||||||
|
case newAddress.family
|
||||||
|
of AddressFamily.IPv4:
|
||||||
|
newAddress.address_v4[3] += offset # TODO: handle octet overflow
|
||||||
|
return newAddress
|
||||||
|
else:
|
||||||
|
echo "currently only supports ipv4"
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Better name, theres no disitinction between group and TAddr
|
||||||
|
proc getGroupForDeliveryAddress*(client: MulticastClient, delivery_address: string): TransportAddress =
|
||||||
|
var offset = hash(delivery_address) mod client.cfg.mcast_grp_count
|
||||||
|
var offsetU8 = cast[uint8](offset) # TODO: Unsafe cast
|
||||||
|
result = getBaseAddress(client.cfg).offsetAddress(offsetU8)
|
||||||
|
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Payload Handling
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
proc inboundMessageHandler(transp: DatagramTransport,
|
||||||
|
raddr: TransportAddress): Future[void] {.async: (raises: []).} =
|
||||||
|
|
||||||
|
echo "Received payload"
|
||||||
|
discard
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Message Sending and Receiving
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
proc subscribe*(client: MulticastClient, delivery_address: string): Future[void] {.async.} =
|
||||||
|
let group = client.getGroupForDeliveryAddress(delivery_address).toIpAddress()
|
||||||
|
joinMulticast(client.listenSocket.fd, $group)
|
||||||
|
|
||||||
|
|
||||||
|
proc sendPayload*(client: MulticastClient, delivery_address: string, env: WapEnvelopeV1): Future[void] {.async.} =
|
||||||
|
|
||||||
|
var payload = env
|
||||||
|
|
||||||
|
let group = client.getGroupForDeliveryAddress(delivery_address)
|
||||||
|
|
||||||
|
await client.sendSocket.sendTo(group, addr payload[0], len(payload))
|
||||||
|
echo "Sent message to ", group
|
||||||
|
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Object Initialization
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
proc initMulticastClient*(cfg: MulticastConfig): MulticastClient =
|
||||||
|
|
||||||
|
let listen_addr = cfg.getListenAddress()
|
||||||
|
|
||||||
|
let sendSocket = newDatagramTransport(inboundMessageHandler)
|
||||||
|
let listenSocket = newDatagramTransport(inboundMessageHandler, local=listen_addr)
|
||||||
|
|
||||||
|
result = MulticastClient(
|
||||||
|
cfg: cfg,
|
||||||
|
sendSocket: sendSocket,
|
||||||
|
listenSocket: listenSocket
|
||||||
|
)
|
||||||
|
|
||||||
|
proc main() {.async.} =
|
||||||
|
|
||||||
|
|
||||||
|
let cfg = DefaultConfig()
|
||||||
|
let m = initMulticastClient(cfg)
|
||||||
|
# asyncSpawn m.start()
|
||||||
|
|
||||||
|
await m.subscribe("cats")
|
||||||
|
await sleepAsync(1000)
|
||||||
|
await m.sendPayload("any_address", "Hello Multicast Group")
|
||||||
|
await sleepAsync(1000)
|
||||||
|
echo "Hello Multicast"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user