mirror of
https://github.com/DeBrosOfficial/network.git
synced 2025-10-06 12:09:07 +00:00
feat: add dev-local mode for localhost testing with auto-discovery of bootstrap peers
This commit is contained in:
parent
e76ad5cf16
commit
cf36d301d5
6
Makefile
6
Makefile
@ -26,21 +26,21 @@ test:
|
||||
# Run bootstrap node explicitly
|
||||
run-node:
|
||||
@echo "Starting BOOTSTRAP node (role=bootstrap)..."
|
||||
go run ./cmd/node -role bootstrap -data ./data/bootstrap -advertise localhost -p2p-port $${P2P:-4001}
|
||||
go run ./cmd/node -role bootstrap -data ./data/bootstrap -advertise localhost -p2p-port $${P2P:-4001} -dev-local
|
||||
|
||||
# Run second node (regular) - requires BOOTSTRAP multiaddr
|
||||
# Usage: make run-node2 BOOTSTRAP=/ip4/127.0.0.1/tcp/4001/p2p/<ID> HTTP=5002 RAFT=7002 P2P=4002
|
||||
run-node2:
|
||||
@echo "Starting REGULAR node2 (role=node)..."
|
||||
@if [ -z "$(BOOTSTRAP)" ]; then echo "ERROR: Provide BOOTSTRAP multiaddr: make run-node2 BOOTSTRAP=/ip4/127.0.0.1/tcp/4001/p2p/<ID> [HTTP=5002 RAFT=7002 P2P=4002]"; exit 1; fi
|
||||
go run ./cmd/node -role node -id node2 -data ./data/node2 -bootstrap $(BOOTSTRAP) -rqlite-http-port $${HTTP:-5002} -rqlite-raft-port $${RAFT:-7002} -p2p-port $${P2P:-4002} -advertise $${ADVERTISE:-localhost}
|
||||
go run ./cmd/node -role node -id node2 -data ./data/node2 -bootstrap $(BOOTSTRAP) -rqlite-http-port $${HTTP:-5002} -rqlite-raft-port $${RAFT:-7002} -p2p-port $${P2P:-4002} -advertise $${ADVERTISE:-localhost} -dev-local
|
||||
|
||||
# Run third node (regular) - requires BOOTSTRAP multiaddr
|
||||
# Usage: make run-node3 BOOTSTRAP=/ip4/127.0.0.1/tcp/4001/p2p/<ID> HTTP=5003 RAFT=7003 P2P=4003
|
||||
run-node3:
|
||||
@echo "Starting REGULAR node3 (role=node)..."
|
||||
@if [ -z "$(BOOTSTRAP)" ]; then echo "ERROR: Provide BOOTSTRAP multiaddr: make run-node3 BOOTSTRAP=/ip4/127.0.0.1/tcp/4001/p2p/<ID> [HTTP=5003 RAFT=7003 P2P=4003]"; exit 1; fi
|
||||
go run ./cmd/node -role node -id node3 -data ./data/node3 -bootstrap $(BOOTSTRAP) -rqlite-http-port $${HTTP:-5003} -rqlite-raft-port $${RAFT:-7003} -p2p-port $${P2P:-4003} -advertise $${ADVERTISE:-localhost}
|
||||
go run ./cmd/node -role node -id node3 -data ./data/node3 -bootstrap $(BOOTSTRAP) -rqlite-http-port $${HTTP:-5003} -rqlite-raft-port $${RAFT:-7003} -p2p-port $${P2P:-4003} -advertise $${ADVERTISE:-localhost} -dev-local
|
||||
|
||||
# Run basic usage example
|
||||
run-example:
|
||||
|
@ -187,7 +187,7 @@ make build
|
||||
|
||||
```bash
|
||||
# Start an explicit bootstrap node (LibP2P 4001, RQLite 5001/7001)
|
||||
go run ./cmd/node -role bootstrap -data ./data/bootstrap
|
||||
go run ./cmd/node -role bootstrap -data ./data/bootstrap -dev-local
|
||||
```
|
||||
|
||||
**Terminal 2 - Regular Node:**
|
||||
@ -200,7 +200,8 @@ go run ./cmd/node \
|
||||
-data ./data/node2 \
|
||||
-bootstrap /ip4/127.0.0.1/tcp/4001/p2p/<BOOTSTRAP_PEER_ID> \
|
||||
-rqlite-http-port 5002 \
|
||||
-rqlite-raft-port 7002
|
||||
-rqlite-raft-port 7002 \
|
||||
-dev-local
|
||||
```
|
||||
|
||||
**Terminal 3 - Another Node (optional):**
|
||||
@ -421,6 +422,7 @@ For more advanced configuration options and development setup, see the sections
|
||||
|
||||
- **Bootstrap node**: `-role bootstrap`
|
||||
- **Regular node**: `-role node -bootstrap <multiaddr>`
|
||||
- **Development localhost defaults**: `-dev-local` (sets `NETWORK_DEV_LOCAL=1` in-process); use this for local-only testing so the library returns localhost DB endpoints and bootstrap peers.
|
||||
- **RQLite ports**: `-rqlite-http-port` (default 5001), `-rqlite-raft-port` (default 7001)
|
||||
|
||||
Examples are shown in Quick Start above for local multi-node on a single machine.
|
||||
|
@ -2,9 +2,11 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"git.debros.io/DeBros/network/pkg/config"
|
||||
"git.debros.io/DeBros/network/pkg/client"
|
||||
"git.debros.io/DeBros/network/pkg/constants"
|
||||
"git.debros.io/DeBros/network/pkg/logging"
|
||||
)
|
||||
@ -21,6 +23,17 @@ type NodeFlagValues struct {
|
||||
Advertise string
|
||||
}
|
||||
|
||||
// isTruthyEnv returns true if the environment variable is set to a common truthy value
|
||||
func isTruthyEnv(key string) bool {
|
||||
v := strings.ToLower(strings.TrimSpace(os.Getenv(key)))
|
||||
switch v {
|
||||
case "1", "true", "yes", "on":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// MapFlagsAndEnvToConfig applies environment overrides and CLI flags to cfg.
|
||||
// Precedence: flags > env > defaults. Behavior mirrors previous inline logic in main.go.
|
||||
// Returns the derived RQLite Raft join address for non-bootstrap nodes (empty for bootstrap nodes).
|
||||
@ -28,6 +41,9 @@ func MapFlagsAndEnvToConfig(cfg *config.Config, fv NodeFlagValues, isBootstrap b
|
||||
// Apply environment variable overrides first so that flags can override them after
|
||||
config.ApplyEnvOverrides(cfg)
|
||||
|
||||
// Detect dev-local mode (set via -dev-local -> NETWORK_DEV_LOCAL=1)
|
||||
devLocal := isTruthyEnv("NETWORK_DEV_LOCAL")
|
||||
|
||||
// Determine data directory if not provided
|
||||
if fv.DataDir == "" {
|
||||
if isBootstrap {
|
||||
@ -56,6 +72,14 @@ func MapFlagsAndEnvToConfig(cfg *config.Config, fv NodeFlagValues, isBootstrap b
|
||||
|
||||
// Bootstrap-specific vs regular-node logic
|
||||
if isBootstrap {
|
||||
if devLocal {
|
||||
// In dev-local, run a primary bootstrap locally
|
||||
cfg.Database.RQLiteJoinAddress = ""
|
||||
// Also prefer localhost bootstrap peers for any consumers reading cfg
|
||||
cfg.Discovery.BootstrapPeers = client.DefaultBootstrapPeers()
|
||||
logger.Printf("Dev-local: Primary bootstrap node - localhost defaults enabled")
|
||||
return ""
|
||||
}
|
||||
bootstrapPeers := constants.GetBootstrapPeers()
|
||||
isSecondaryBootstrap := false
|
||||
if len(bootstrapPeers) > 1 {
|
||||
@ -103,6 +127,11 @@ func MapFlagsAndEnvToConfig(cfg *config.Config, fv NodeFlagValues, isBootstrap b
|
||||
logger.Printf("Using command line bootstrap peer: %s", fv.Bootstrap)
|
||||
} else {
|
||||
bootstrapPeers := cfg.Discovery.BootstrapPeers
|
||||
if devLocal {
|
||||
// Force localhost bootstrap for development
|
||||
bootstrapPeers = client.DefaultBootstrapPeers()
|
||||
logger.Printf("Dev-local: overriding bootstrap peers to %v", bootstrapPeers)
|
||||
}
|
||||
if len(bootstrapPeers) == 0 {
|
||||
bootstrapPeers = constants.GetBootstrapPeers()
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ func main() {
|
||||
rqlHTTP = flag.Int("rqlite-http-port", 5001, "RQLite HTTP API port")
|
||||
rqlRaft = flag.Int("rqlite-raft-port", 7001, "RQLite Raft port")
|
||||
advertise = flag.String("advertise", "auto", "Advertise mode: auto|localhost|ip")
|
||||
devLocal = flag.Bool("dev-local", false, "Enable development localhost defaults for the client library (sets NETWORK_DEV_LOCAL=1)")
|
||||
help = flag.Bool("help", false, "Show help")
|
||||
)
|
||||
flag.Parse()
|
||||
@ -38,6 +39,12 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
// Enable development localhost defaults for the client library if requested
|
||||
if *devLocal {
|
||||
os.Setenv("NETWORK_DEV_LOCAL", "1")
|
||||
log.Printf("Development local mode enabled (NETWORK_DEV_LOCAL=1)")
|
||||
}
|
||||
|
||||
// Determine node role
|
||||
var isBootstrap bool
|
||||
switch strings.ToLower(*role) {
|
||||
|
@ -2,6 +2,7 @@ package client
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@ -16,6 +17,10 @@ func DefaultBootstrapPeers() []string {
|
||||
if ma := os.Getenv("LOCAL_BOOTSTRAP_MULTIADDR"); ma != "" {
|
||||
return []string{ma}
|
||||
}
|
||||
// Try to auto-resolve local bootstrap peer multiaddr from peer.info
|
||||
if ma, ok := readLocalPeerInfoMultiaddr(); ok {
|
||||
return []string{ma}
|
||||
}
|
||||
// Fallback to localhost transport without peer ID (connect will warn and skip)
|
||||
return []string{"/ip4/127.0.0.1/tcp/4001"}
|
||||
}
|
||||
@ -84,27 +89,27 @@ func MapAddrsToDBEndpoints(addrs []multiaddr.Multiaddr, dbPort int) []string {
|
||||
}
|
||||
|
||||
func endpointFromMultiaddr(ma multiaddr.Multiaddr, port int) string {
|
||||
var host string
|
||||
// Prefer DNS if present, then IP
|
||||
if v, err := ma.ValueForProtocol(multiaddr.P_DNS); err == nil && v != "" {
|
||||
host = v
|
||||
}
|
||||
if host == "" {
|
||||
if v, err := ma.ValueForProtocol(multiaddr.P_DNS4); err == nil && v != "" { host = v }
|
||||
}
|
||||
if host == "" {
|
||||
if v, err := ma.ValueForProtocol(multiaddr.P_DNS6); err == nil && v != "" { host = v }
|
||||
}
|
||||
if host == "" {
|
||||
if v, err := ma.ValueForProtocol(multiaddr.P_IP4); err == nil && v != "" { host = v }
|
||||
}
|
||||
if host == "" {
|
||||
if v, err := ma.ValueForProtocol(multiaddr.P_IP6); err == nil && v != "" { host = v }
|
||||
}
|
||||
if host == "" {
|
||||
host = "localhost"
|
||||
}
|
||||
return "http://" + host + ":" + strconv.Itoa(port)
|
||||
var host string
|
||||
// Prefer DNS if present, then IP
|
||||
if v, err := ma.ValueForProtocol(multiaddr.P_DNS); err == nil && v != "" {
|
||||
host = v
|
||||
}
|
||||
if host == "" {
|
||||
if v, err := ma.ValueForProtocol(multiaddr.P_DNS4); err == nil && v != "" { host = v }
|
||||
}
|
||||
if host == "" {
|
||||
if v, err := ma.ValueForProtocol(multiaddr.P_DNS6); err == nil && v != "" { host = v }
|
||||
}
|
||||
if host == "" {
|
||||
if v, err := ma.ValueForProtocol(multiaddr.P_IP4); err == nil && v != "" { host = v }
|
||||
}
|
||||
if host == "" {
|
||||
if v, err := ma.ValueForProtocol(multiaddr.P_IP6); err == nil && v != "" { host = v }
|
||||
}
|
||||
if host == "" {
|
||||
host = "localhost"
|
||||
}
|
||||
return "http://" + host + ":" + strconv.Itoa(port)
|
||||
}
|
||||
|
||||
func dedupeStrings(in []string) []string {
|
||||
@ -123,3 +128,32 @@ func dedupeStrings(in []string) []string {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// readLocalPeerInfoMultiaddr attempts to read the local bootstrap peer multiaddr from common dev paths.
|
||||
// It checks LOCAL_BOOTSTRAP_INFO (path), then ./data/bootstrap/peer.info, then ./data/peer.info.
|
||||
func readLocalPeerInfoMultiaddr() (string, bool) {
|
||||
candidates := make([]string, 0, 3)
|
||||
if p := strings.TrimSpace(os.Getenv("LOCAL_BOOTSTRAP_INFO")); p != "" {
|
||||
candidates = append(candidates, p)
|
||||
}
|
||||
candidates = append(candidates,
|
||||
filepath.Join(".", "data", "bootstrap", "peer.info"),
|
||||
filepath.Join(".", "data", "peer.info"),
|
||||
)
|
||||
|
||||
for _, p := range candidates {
|
||||
b, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
s := strings.TrimSpace(string(b))
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
// expect a full multiaddr with /p2p/<peerID>
|
||||
if strings.Contains(s, "/p2p/") {
|
||||
return s, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user