mirror of
https://github.com/logos-messaging/logos-messaging-nim.git
synced 2026-01-08 00:43:06 +00:00
119 lines
3.3 KiB
Nim
119 lines
3.3 KiB
Nim
## Waku pub-sub topics definition and namespacing utils
|
|
##
|
|
## See 23/WAKU2-TOPICS RFC: https://rfc.vac.dev/spec/23/
|
|
|
|
when (NimMajor, NimMinor) < (1, 4):
|
|
{.push raises: [Defect].}
|
|
else:
|
|
{.push raises: [].}
|
|
|
|
|
|
import
|
|
std/strutils,
|
|
stew/[results, base10]
|
|
import
|
|
./parsing
|
|
|
|
export parsing
|
|
|
|
|
|
## Pub-sub topic
|
|
|
|
type PubsubTopic* = string
|
|
|
|
const DefaultPubsubTopic* = PubsubTopic("/waku/2/default-waku/proto")
|
|
|
|
|
|
## Namespaced pub-sub topic
|
|
|
|
type
|
|
NsPubsubTopicKind* {.pure.} = enum
|
|
StaticSharding,
|
|
NamedSharding
|
|
|
|
type
|
|
NsPubsubTopic* = object
|
|
case kind*: NsPubsubTopicKind
|
|
of NsPubsubTopicKind.StaticSharding:
|
|
cluster*: uint16
|
|
shard*: uint16
|
|
of NsPubsubTopicKind.NamedSharding:
|
|
name*: string
|
|
|
|
proc staticSharding*(T: type NsPubsubTopic, cluster, shard: uint16): T =
|
|
NsPubsubTopic(
|
|
kind: NsPubsubTopicKind.StaticSharding,
|
|
cluster: cluster,
|
|
shard: shard
|
|
)
|
|
|
|
proc named*(T: type NsPubsubTopic, name: string): T =
|
|
NsPubsubTopic(
|
|
kind: NsPubsubTopicKind.NamedSharding,
|
|
name: name
|
|
)
|
|
|
|
|
|
# Serialization
|
|
|
|
proc `$`*(topic: NsPubsubTopic): string =
|
|
## Returns a string representation of a namespaced topic
|
|
## in the format `/waku/2/<raw-topic>
|
|
case topic.kind:
|
|
of NsPubsubTopicKind.NamedSharding:
|
|
"/waku/2/" & topic.name
|
|
of NsPubsubTopicKind.StaticSharding:
|
|
"/waku/2/rs/" & $topic.cluster & "/" & $topic.shard
|
|
|
|
|
|
# Deserialization
|
|
|
|
const
|
|
Waku2PubsubTopicPrefix = "/waku/2"
|
|
StaticShardingPubsubTopicPrefix = Waku2PubsubTopicPrefix & "/rs"
|
|
|
|
|
|
proc parseStaticSharding*(T: type NsPubsubTopic, topic: PubsubTopic|string): ParsingResult[NsPubsubTopic] =
|
|
if not topic.startsWith(StaticShardingPubsubTopicPrefix):
|
|
return err(ParsingError.invalidFormat("must start with " & StaticShardingPubsubTopicPrefix))
|
|
|
|
let parts = topic[11..<topic.len].split("/")
|
|
if parts.len != 2:
|
|
return err(ParsingError.invalidFormat("invalid topic structure"))
|
|
|
|
let clusterPart = parts[0]
|
|
if clusterPart.len == 0:
|
|
return err(ParsingError.missingPart("shard_cluster_index"))
|
|
let cluster = ?Base10.decode(uint16, clusterPart).mapErr(proc(err: auto): auto = ParsingError.invalidFormat($err))
|
|
|
|
let shardPart = parts[1]
|
|
if shardPart.len == 0:
|
|
return err(ParsingError.missingPart("shard_number"))
|
|
let shard = ?Base10.decode(uint16, shardPart).mapErr(proc(err: auto): auto = ParsingError.invalidFormat($err))
|
|
|
|
ok(NsPubsubTopic.staticSharding(cluster, shard))
|
|
|
|
proc parseNamedSharding*(T: type NsPubsubTopic, topic: PubsubTopic|string): ParsingResult[NsPubsubTopic] =
|
|
if not topic.startsWith(Waku2PubsubTopicPrefix):
|
|
return err(ParsingError.invalidFormat("must start with " & Waku2PubsubTopicPrefix))
|
|
|
|
let raw = topic[8..<topic.len]
|
|
if raw.len == 0:
|
|
return err(ParsingError.missingPart("topic-name"))
|
|
|
|
ok(NsPubsubTopic.named(name=raw))
|
|
|
|
proc parse*(T: type NsPubsubTopic, topic: PubsubTopic|string): ParsingResult[NsPubsubTopic] =
|
|
## Splits a namespaced topic string into its constituent parts.
|
|
## The topic string has to be in the format `/<application>/<version>/<topic-name>/<encoding>`
|
|
if topic.startsWith(StaticShardingPubsubTopicPrefix):
|
|
NsPubsubTopic.parseStaticSharding(topic)
|
|
else:
|
|
NsPubsubTopic.parseNamedSharding(topic)
|
|
|
|
|
|
# Pubsub topic compatibility
|
|
|
|
converter toPubsubTopic*(topic: NsPubsubTopic): PubsubTopic =
|
|
$topic
|