From 7781e850d55b55cbdd1b4c9daa6227c7a4b46fdd Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Thu, 6 Jul 2023 14:20:16 -0400 Subject: [PATCH] feat(c-bindings): websockets support --- library/README.md | 40 +++++++++++++++++++++++++++++++++++- library/api.go | 9 ++++++++ mobile/api.go | 18 +++++++++++++++- mobile/config.go | 52 ++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 112 insertions(+), 7 deletions(-) diff --git a/library/README.md b/library/README.md index a67bf2e8..d726b50e 100644 --- a/library/README.md +++ b/library/README.md @@ -299,6 +299,8 @@ interface JsonConfig { databaseURL?: string; storeRetentionMaxMessages?: number; storeRetentionTimeSeconds?: number; + websocket?: Websocket; + dns4DomainName?: string; } ``` @@ -342,8 +344,10 @@ If a key is `undefined`, or `null`, a default value will be set. Default `10000` - `storeRetentionTimeSeconds`: max number of seconds that a message will be persisted in the database. Default `2592000` (30d) +- `websocket`: custom websocket support parameters. See `Websocket` section for defaults +- `dns4DomainName`: the domain name resolving to the node's public IPv4 address. + - For example: ```json { @@ -460,6 +464,40 @@ If a key is `undefined`, or `null`, a default value will be set. Default `120` seconds +### `Websocket` type + +Type holding custom websocket support configuration: + +```ts +interface Websocket { + enabled?: bool; + host?: string; + port?: number; + secure?: bool; + certPath?: string; + keyPath?: string; +} +``` + +Fields: + +All fields are optional. +If a key is `undefined`, or `null`, a default value will be set. If using `secure` websockets support, `certPath` and `keyPath` become mandatory attributes. Unless selfsigned certificates are used, it will probably make sense in the `JsonConfiguration` to specify the domain name used in the certificate in the `dns4DomainName` attribute. + +- `enabled`: indicates if websockets support will be enabled + Default `false` +- `host`: listening address for websocket connections + Default `0.0.0.0` +- `port`: TCP listening port for websocket connection (`0` for random, binding to `443` requires root access) + Default `60001`, if secure websockets support is enabled, the default is `6443“` +- `secure`: enable secure websockets support + Default `false` +- `certPath`: secure websocket certificate path +- `keyPath`: secure websocket key path + + + + ### `extern char* waku_new(char* jsonConfig)` Instantiates a Waku node. diff --git a/library/api.go b/library/api.go index a84165b8..d41c8fc7 100644 --- a/library/api.go +++ b/library/api.go @@ -69,6 +69,15 @@ func main() {} // - databaseURL: url connection string. Default: "sqlite3://store.db". Also accepts PostgreSQL connection strings // - storeRetentionMaxMessages: max number of messages to store in the database. Default 10000 // - storeRetentionTimeSeconds: max number of seconds that a message will be persisted in the database. Default 2592000 (30d) +// - websockets: an optional object containing settings to setup the websocket configuration +// - enabled: indicates if websockets support will be enabled. Default `false` +// - host: listening address for websocket connections. Default `0.0.0.0` +// - port: TCP listening port for websocket connection (0 for random, binding to 443 requires root access). Default: `60001“, if secure websockets support is enabled, the default is `6443“ +// - secure: enable secure websockets support. Default `false` +// - certPath: secure websocket certificate path +// - keyPath: secure websocket key path +// +// - dns4DomainName: the domain name resolving to the node's public IPv4 address. // //export waku_new func waku_new(configJSON *C.char) *C.char { diff --git a/mobile/api.go b/mobile/api.go index f6be85b3..2b01549b 100644 --- a/mobile/api.go +++ b/mobile/api.go @@ -101,11 +101,27 @@ func NewNode(configJSON string) string { pubsubOpt = append(pubsubOpt, pubsub.WithGossipSubParams(params)) } - pubsubOpt = append(pubsubOpt, pubsub.WithSeenMessagesTTL(GetSeenTTL(config))) + pubsubOpt = append(pubsubOpt, pubsub.WithSeenMessagesTTL(getSeenTTL(config))) opts = append(opts, node.WithWakuRelayAndMinPeers(*config.MinPeersToPublish, pubsubOpt...)) } + if config.DNS4DomainName != "" { + opts = append(opts, node.WithDns4Domain(config.DNS4DomainName)) + } + + if config.Websockets.Enabled { + if config.Websockets.Secure { + if config.DNS4DomainName == "" { + utils.Logger().Warn("using secure websockets without a dns4 domain name might indicate a misconfiguration") + } + opts = append(opts, node.WithSecureWebsockets(config.Websockets.Host, *config.Websockets.Port, config.Websockets.CertPath, config.Websockets.KeyPath)) + } else { + opts = append(opts, node.WithWebsockets(config.Websockets.Host, *config.Websockets.Port)) + + } + } + if *config.EnableLegacyFilter { opts = append(opts, node.WithLegacyWakuFilter(false)) } diff --git a/mobile/config.go b/mobile/config.go index 02e2a274..130e4599 100644 --- a/mobile/config.go +++ b/mobile/config.go @@ -2,12 +2,14 @@ package gowaku import ( "encoding/json" + "errors" "time" pubsub "github.com/libp2p/go-libp2p-pubsub" ) -type wakuConfig struct { +// WakuConfig contains all the configuration settings exposed to users of mobile and c libraries +type WakuConfig struct { Host *string `json:"host,omitempty"` Port *int `json:"port,omitempty"` AdvertiseAddress *string `json:"advertiseAddr,omitempty"` @@ -26,6 +28,18 @@ type wakuConfig struct { DatabaseURL *string `json:"databaseURL,omitempty"` RetentionMaxMessages *int `json:"storeRetentionMaxMessages,omitempty"` RetentionTimeSeconds *int `json:"storeRetentionTimeSeconds,omitempty"` + DNS4DomainName string `json:"dns4DomainName,omitempty"` + Websockets *WebsocketConfig `json:"websockets,omitempty"` +} + +// WebsocketConfig contains all the settings required to setup websocket support in waku +type WebsocketConfig struct { + Enabled bool `json:"enabled,omitempty"` + Host string `json:"host,omitempty"` + Port *int `json:"port,omitempty"` + Secure bool `json:"secure,omitempty"` + CertPath string `json:"certPath"` + KeyPath string `json:"keyPath"` } var defaultHost = "0.0.0.0" @@ -42,6 +56,10 @@ var defaultDatabaseURL = "sqlite3://store.db" var defaultRetentionMaxMessages = 10000 var defaultRetentionTimeSeconds = 30 * 24 * 60 * 60 // 30d +var defaultWSPort = 60001 +var defaultWSSPort = 6443 +var defaultWSHost = "0.0.0.0" + // GossipSubParams defines all the gossipsub specific parameters. type GossipSubParams struct { // overlay parameters. @@ -190,12 +208,12 @@ type GossipSubParams struct { SeenMessagesTTLSeconds *int `json:"seenMessagesTTLSeconds"` } -func getConfig(configJSON string) (wakuConfig, error) { - var config wakuConfig +func getConfig(configJSON string) (WakuConfig, error) { + var config WakuConfig if configJSON != "" { err := json.Unmarshal([]byte(configJSON), &config) if err != nil { - return wakuConfig{}, err + return WakuConfig{}, err } } @@ -255,10 +273,34 @@ func getConfig(configJSON string) (wakuConfig, error) { config.RetentionTimeSeconds = &defaultRetentionTimeSeconds } + if config.Websockets == nil { + config.Websockets = &WebsocketConfig{} + } + + if config.Websockets.Host == "" { + config.Websockets.Host = defaultWSHost + } + + if config.Websockets.Port == nil { + if config.Websockets.Secure { + config.Websockets.Port = &defaultWSSPort + } else { + config.Websockets.Port = &defaultWSPort + } + } + + if config.Websockets.CertPath == "" && config.Websockets.Secure { + return WakuConfig{}, errors.New("certPath is required") + } + + if config.Websockets.KeyPath == "" && config.Websockets.Secure { + return WakuConfig{}, errors.New("keyPath is required") + } + return config, nil } -func GetSeenTTL(cfg wakuConfig) time.Duration { +func getSeenTTL(cfg WakuConfig) time.Duration { if cfg.GossipSubParams == nil || *cfg.GossipSubParams.SeenMessagesTTLSeconds == 0 { return pubsub.TimeCacheDuration }