fryorcraken 994d485b49 chore!: make sharding configuration explicit (#3468)
* Reserve `networkconfig` name to waku network related settings

* Rename cluster conf to network conf

 A `NetworkConf` is a Waku network configuration.

# Conflicts:
#	tests/factory/test_waku_conf.nim

# Conflicts:
#	tests/factory/test_waku_conf.nim

* Improve sharding configuration

A smarter data types simplifies the logic.

* Fixing tests

* fixup! rename to endpointConf

* wip: autosharding is a specific configuration state and treat it like
it

# Conflicts:
#	waku/factory/external_config.nim

* refactor lightpush handler

some metrics error reporting were missing

# Conflicts:
#	waku/waku_lightpush/protocol.nim

* test_node_factory tests pass

* remove warnings

* fix tests

* Revert eager previous replace-all command

* fix up build tools compilation

* metadata is used to store cluster id

* Mount relay routes in static sharding

* Rename activeRelayShards to subscribeShards

To make it clearer that these are the shards the node will subscribe to.

* Remove unused msg var

* Improve error handling

* Set autosharding as default, with 1 shard in network

Also makes shards to subscribe to all shards in auto sharding, none in
static sharding.
2025-07-04 17:10:53 +10:00

141 lines
3.7 KiB
Nim

## Waku content topics definition and namespacing utils
##
## See 23/WAKU2-TOPICS RFC: https://rfc.vac.dev/spec/23/
{.push raises: [].}
import std/options, std/strutils, results
import ./parsing
export parsing
## Content topic
type ContentTopic* = string
const DefaultContentTopic* = ContentTopic("/waku/2/default-content/proto")
## Namespaced content topic
type NsContentTopic* = object
generation*: Option[int]
application*: string
version*: string
name*: string
encoding*: string
proc init*(
T: type NsContentTopic,
generation: Option[int],
application: string,
version: string,
name: string,
encoding: string,
): T =
NsContentTopic(
generation: generation,
application: application,
version: version,
name: name,
encoding: encoding,
)
# Serialization
proc `$`*(topic: NsContentTopic): string =
## Returns a string representation of a namespaced topic
## in the format `/<application>/<version>/<topic-name>/<encoding>`
## Autosharding adds 1 optional prefix `/<gen#>
var formatted = ""
if topic.generation.isSome():
formatted = formatted & "/" & $topic.generation.get()
formatted & "/" & topic.application & "/" & topic.version & "/" & topic.name & "/" &
topic.encoding
# Deserialization
proc parse*(
T: type NsContentTopic, topic: ContentTopic | string
): ParsingResult[NsContentTopic] =
## Splits a namespaced topic string into its constituent parts.
## The topic string has to be in the format `/<application>/<version>/<topic-name>/<encoding>`
## Autosharding adds 1 optional prefix `/<gen#>
if not topic.startsWith("/"):
return err(
ParsingError.invalidFormat("content-topic '" & topic & "' must start with slash")
)
let parts = topic[1 ..< topic.len].split("/")
case parts.len
of 4:
let app = parts[0]
if app.len == 0:
return err(ParsingError.missingPart("application"))
let ver = parts[1]
if ver.len == 0:
return err(ParsingError.missingPart("version"))
let name = parts[2]
if name.len == 0:
return err(ParsingError.missingPart("topic-name"))
let enc = parts[3]
if enc.len == 0:
return err(ParsingError.missingPart("encoding"))
return ok(NsContentTopic.init(none(int), app, ver, name, enc))
of 5:
if parts[0].len == 0:
return err(ParsingError.missingPart("generation"))
let gen =
try:
parseInt(parts[0])
except ValueError:
return err(ParsingError.invalidFormat("generation should be a numeric value"))
let app = parts[1]
if app.len == 0:
return err(ParsingError.missingPart("application"))
let ver = parts[2]
if ver.len == 0:
return err(ParsingError.missingPart("version"))
let name = parts[3]
if name.len == 0:
return err(ParsingError.missingPart("topic-name"))
let enc = parts[4]
if enc.len == 0:
return err(ParsingError.missingPart("encoding"))
return ok(NsContentTopic.init(some(gen), app, ver, name, enc))
else:
let errMsg =
"Invalid content topic structure. Expected either /<application>/<version>/<topic-name>/<encoding> or /<gen>/<application>/<version>/<topic-name>/<encoding>"
return err(ParsingError.invalidFormat(errMsg))
proc parse*(
T: type NsContentTopic, topics: seq[ContentTopic]
): ParsingResult[seq[NsContentTopic]] =
var res: seq[NsContentTopic] = @[]
for contentTopic in topics:
let parseRes = NsContentTopic.parse(contentTopic)
if parseRes.isErr():
let error: ParsingError = parseRes.error
return ParsingResult[seq[NsContentTopic]].err(error)
res.add(parseRes.value)
return ParsingResult[seq[NsContentTopic]].ok(res)
# Content topic compatibility
converter toContentTopic*(topic: NsContentTopic): ContentTopic =
$topic