From e76ad5cf165c8c494e028ff5767725fea8d72006 Mon Sep 17 00:00:00 2001 From: anonpenguin Date: Sat, 9 Aug 2025 17:34:59 +0300 Subject: [PATCH] feat: add NETWORK_DEV_LOCAL flag to force localhost defaults for DB and bootstrap peers --- README.md | 20 ++++++++++++++++++ pkg/client/defaults.go | 23 +++++++++++++++++++++ pkg/client/interface.go | 46 ++++++++++++++++++++++++++++++++++------- 3 files changed, 82 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 042ed4e..181be71 100644 --- a/README.md +++ b/README.md @@ -445,6 +445,8 @@ Precedence: CLI flags > Environment variables > Code defaults. Set any of the fo - RQLITE_JOIN_ADDRESS: host:port for Raft join (regular nodes) - RQLITE_NODES: comma/space-separated DB endpoints (e.g. "http://n1:5001,http://n2:5001"). Used by client if `ClientConfig.DatabaseEndpoints` is empty. - RQLITE_PORT: default DB HTTP port for constructing library defaults (fallback 5001) +- NETWORK_DEV_LOCAL: when truthy (1/true/yes/on), client defaults use localhost for DB endpoints; default bootstrap peers also return localhost values. +- LOCAL_BOOTSTRAP_MULTIADDR: when set with NETWORK_DEV_LOCAL, overrides default bootstrap with a specific local multiaddr (e.g. `/ip4/127.0.0.1/tcp/4001/p2p/`) - ADVERTISE_MODE: "auto" | "localhost" | "ip" - BOOTSTRAP_PEERS: comma-separated multiaddrs for bootstrap peers @@ -499,6 +501,24 @@ cli, err := client.NewClient(cfg) // cli.Connect() will prefer cfg.DatabaseEndpoints, then RQLITE_NODES, then defaults ``` +#### Development Mode (localhost-only) + +To force localhost defaults for both database endpoints and bootstrap peers: + +```bash +export NETWORK_DEV_LOCAL=1 +# Optional: specify a local bootstrap peer multiaddr with peer ID +export LOCAL_BOOTSTRAP_MULTIADDR="/ip4/127.0.0.1/tcp/4001/p2p/" +# Optional: customize default DB port used in localhost endpoints +export RQLITE_PORT=5001 +``` + +Notes: + +- With `NETWORK_DEV_LOCAL`, `client.DefaultDatabaseEndpoints()` returns `http://127.0.0.1:$RQLITE_PORT`. +- `client.DefaultBootstrapPeers()` returns `LOCAL_BOOTSTRAP_MULTIADDR` if set, otherwise `/ip4/127.0.0.1/tcp/4001`. +- If you construct config via `client.DefaultClientConfig(...)`, DB endpoints are pinned to localhost and will override `RQLITE_NODES` automatically. + ### Migration Guide for Apps (e.g., anchat) - __Stop hardcoding endpoints__: Replace any hardcoded bootstrap peers and DB URLs with calls to diff --git a/pkg/client/defaults.go b/pkg/client/defaults.go index 0c6bd3e..4c814f0 100644 --- a/pkg/client/defaults.go +++ b/pkg/client/defaults.go @@ -11,12 +11,30 @@ import ( // DefaultBootstrapPeers returns the library's default bootstrap peer multiaddrs. func DefaultBootstrapPeers() []string { + // Development local-only override + if truthy(os.Getenv("NETWORK_DEV_LOCAL")) { + if ma := os.Getenv("LOCAL_BOOTSTRAP_MULTIADDR"); ma != "" { + return []string{ma} + } + // Fallback to localhost transport without peer ID (connect will warn and skip) + return []string{"/ip4/127.0.0.1/tcp/4001"} + } peers := constants.GetBootstrapPeers() out := make([]string, len(peers)) copy(out, peers) return out } +// truthy reports if s is a common truthy string. +func truthy(s string) bool { + switch s { + case "1", "true", "TRUE", "True", "yes", "YES", "on", "ON": + return true + default: + return false + } +} + // DefaultDatabaseEndpoints returns default DB HTTP endpoints derived from default bootstrap peers. // Port defaults to RQLite HTTP 5001, or RQLITE_PORT if set. func DefaultDatabaseEndpoints() []string { @@ -27,6 +45,11 @@ func DefaultDatabaseEndpoints() []string { } } + // Development local-only override + if truthy(os.Getenv("NETWORK_DEV_LOCAL")) { + return []string{"http://127.0.0.1:" + strconv.Itoa(port)} + } + peers := DefaultBootstrapPeers() if len(peers) == 0 { return []string{"http://localhost:" + strconv.Itoa(port)} diff --git a/pkg/client/interface.go b/pkg/client/interface.go index a69f4ec..dd17c98 100644 --- a/pkg/client/interface.go +++ b/pkg/client/interface.go @@ -3,6 +3,8 @@ package client import ( "context" "fmt" + "os" + "strconv" "time" ) @@ -133,13 +135,43 @@ type ClientConfig struct { // DefaultClientConfig returns a default client configuration func DefaultClientConfig(appName string) *ClientConfig { + // Base defaults + peers := []string{} + endpoints := DefaultDatabaseEndpoints() + + // Development local-only override via env + if isTruthyEnv("NETWORK_DEV_LOCAL") { + port := 5001 + if v := os.Getenv("RQLITE_PORT"); v != "" { + if n, err := strconv.Atoi(v); err == nil && n > 0 { port = n } + } + endpoints = []string{fmt.Sprintf("http://127.0.0.1:%d", port)} + if ma := os.Getenv("LOCAL_BOOTSTRAP_MULTIADDR"); ma != "" { + peers = []string{ma} + } else { + // Leave peers empty if no local bootstrap multiaddr provided + peers = []string{} + } + } + return &ClientConfig{ - AppName: appName, - DatabaseName: fmt.Sprintf("%s_db", appName), - BootstrapPeers: []string{}, - DatabaseEndpoints: DefaultDatabaseEndpoints(), - ConnectTimeout: time.Second * 30, - RetryAttempts: 3, - RetryDelay: time.Second * 5, + AppName: appName, + DatabaseName: fmt.Sprintf("%s_db", appName), + BootstrapPeers: peers, + DatabaseEndpoints: endpoints, + ConnectTimeout: time.Second * 30, + RetryAttempts: 3, + RetryDelay: time.Second * 5, + } +} + +// isTruthyEnv returns true if the env var is set to a common truthy value. +func isTruthyEnv(key string) bool { + v := os.Getenv(key) + switch v { + case "1", "true", "TRUE", "True", "yes", "YES", "on", "ON": + return true + default: + return false } }