mirror of
https://github.com/DeBrosOfficial/network.git
synced 2025-12-11 09:18:50 +00:00
chore: update .gitignore and CHANGELOG for new development features
- Added .dev/ directory to .gitignore to exclude development process files. - Updated CHANGELOG.md with new entries for the one-command `make dev` target, full stack initialization, and improved configuration management. - Simplified README instructions for generating configuration files and starting the complete network stack.
This commit is contained in:
parent
cce5326368
commit
7c9851729e
2
.gitignore
vendored
2
.gitignore
vendored
@ -73,3 +73,5 @@ data/bootstrap/rqlite/
|
||||
.env.*
|
||||
|
||||
configs/
|
||||
|
||||
.dev/
|
||||
23
CHANGELOG.md
23
CHANGELOG.md
@ -8,14 +8,37 @@ The format is based on [Keep a Changelog][keepachangelog] and adheres to [Semant
|
||||
|
||||
### Added
|
||||
|
||||
- One-command `make dev` target to start full development stack (bootstrap + node2 + node3 + gateway in background)
|
||||
- New `network-cli config init` (no --type) generates complete development stack with all configs and identities
|
||||
- Full stack initialization with auto-generated peer identities for bootstrap and all nodes
|
||||
- Explicit control over LibP2P listen addresses for better localhost/development support
|
||||
- Production/development mode detection for NAT services (disabled for localhost, enabled for production)
|
||||
- Process management with .dev/pids directory for background process tracking
|
||||
- Centralized logging to ~/.debros/logs/ for all network services
|
||||
|
||||
### Changed
|
||||
|
||||
- Simplified Makefile: removed legacy dev commands, replaced with unified `make dev` target
|
||||
- Updated README with clearer getting started instructions (single `make dev` command)
|
||||
- Simplified `network-cli config init` behavior: defaults to generating full stack instead of single node
|
||||
- `network-cli config init` now handles bootstrap peer discovery and join addresses automatically
|
||||
- LibP2P configuration: removed always-on NAT services for development environments
|
||||
- Code formatting in pkg/node/node.go (indentation fixes in bootstrapPeerSource)
|
||||
|
||||
### Deprecated
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed legacy Makefile targets: run-example, show-bootstrap, run-cli, cli-health, cli-peers, cli-status, cli-storage-test, cli-pubsub-test
|
||||
- Removed verbose dev-setup, dev-cluster, and old dev workflow targets
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed indentation in bootstrapPeerSource function for consistency
|
||||
- Fixed gateway.yaml generation with correct YAML indentation for bootstrap_peers
|
||||
|
||||
### Security
|
||||
|
||||
## [0.51.6] - 2025-10-24
|
||||
|
||||
### Added
|
||||
|
||||
145
Makefile
145
Makefile
@ -21,7 +21,7 @@ test-e2e:
|
||||
|
||||
.PHONY: build clean test run-node run-node2 run-node3 run-example deps tidy fmt vet lint clear-ports
|
||||
|
||||
VERSION := 0.51.6-beta
|
||||
VERSION := 0.51.7-beta
|
||||
COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown)
|
||||
DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.commit=$(COMMIT)' -X 'main.date=$(DATE)'
|
||||
@ -77,110 +77,45 @@ run-gateway:
|
||||
@echo "Generate it with: network-cli config init --type gateway"
|
||||
go run ./cmd/gateway
|
||||
|
||||
# Run basic usage example
|
||||
run-example:
|
||||
@echo "Running basic usage example..."
|
||||
go run examples/basic_usage.go
|
||||
|
||||
# Show how to run with flags
|
||||
show-bootstrap:
|
||||
@echo "Provide join address via flags, e.g.:"
|
||||
@echo " make run-node2 JOINADDR=/ip4/127.0.0.1/tcp/5001 HTTP=5002 RAFT=7002 P2P=4002"
|
||||
|
||||
# Run network CLI
|
||||
run-cli:
|
||||
@echo "Running network CLI help..."
|
||||
./bin/network-cli help
|
||||
|
||||
# Network CLI helper commands
|
||||
cli-health:
|
||||
@echo "Checking network health..."
|
||||
./bin/network-cli health
|
||||
|
||||
cli-peers:
|
||||
@echo "Listing network peers..."
|
||||
./bin/network-cli peers
|
||||
|
||||
cli-status:
|
||||
@echo "Getting network status..."
|
||||
./bin/network-cli status
|
||||
|
||||
cli-storage-test:
|
||||
@echo "Testing storage operations..."
|
||||
@./bin/network-cli storage put test-key "Hello Network" || echo "Storage test requires running network"
|
||||
@./bin/network-cli storage get test-key || echo "Storage test requires running network"
|
||||
@./bin/network-cli storage list || echo "Storage test requires running network"
|
||||
|
||||
cli-pubsub-test:
|
||||
@echo "Testing pub/sub operations..."
|
||||
@./bin/network-cli pubsub publish test-topic "Hello World" || echo "PubSub test requires running network"
|
||||
@./bin/network-cli pubsub topics || echo "PubSub test requires running network"
|
||||
|
||||
# Download dependencies
|
||||
deps:
|
||||
@echo "Downloading dependencies..."
|
||||
go mod download
|
||||
|
||||
# Tidy dependencies
|
||||
tidy:
|
||||
@echo "Tidying dependencies..."
|
||||
go mod tidy
|
||||
|
||||
# Format code
|
||||
fmt:
|
||||
@echo "Formatting code..."
|
||||
go fmt ./...
|
||||
|
||||
# Vet code
|
||||
vet:
|
||||
@echo "Vetting code..."
|
||||
go vet ./...
|
||||
|
||||
# Lint alias (lightweight for now)
|
||||
lint: fmt vet
|
||||
@echo "Linting complete (fmt + vet)"
|
||||
|
||||
# Clear common development ports
|
||||
clear-ports:
|
||||
@echo "Clearing common dev ports (4001/4002, 5001/5002, 7001/7002)..."
|
||||
@chmod +x scripts/clear-ports.sh || true
|
||||
@scripts/clear-ports.sh
|
||||
|
||||
# Development setup
|
||||
dev-setup: deps
|
||||
@echo "Setting up development environment..."
|
||||
@mkdir -p data/bootstrap data/node data/node2 data/node3
|
||||
@mkdir -p data/test-bootstrap data/test-node1 data/test-node2
|
||||
@echo "Development setup complete!"
|
||||
|
||||
# Start development cluster (requires multiple terminals)
|
||||
dev-cluster:
|
||||
@echo "To start a development cluster with 3 nodes:"
|
||||
# One-command dev: Start bootstrap, node2, node3, and gateway in background
|
||||
# Requires: configs already exist in ~/.debros
|
||||
dev: build
|
||||
@echo "🚀 Starting development network stack..."
|
||||
@mkdir -p .dev/pids
|
||||
@mkdir -p $$HOME/.debros/logs
|
||||
@echo "Starting bootstrap node..."
|
||||
@nohup ./bin/node --config bootstrap.yaml > $$HOME/.debros/logs/bootstrap.log 2>&1 & echo $$! > .dev/pids/bootstrap.pid
|
||||
@sleep 2
|
||||
@echo "Starting node2..."
|
||||
@nohup ./bin/node --config node2.yaml > $$HOME/.debros/logs/node2.log 2>&1 & echo $$! > .dev/pids/node2.pid
|
||||
@sleep 1
|
||||
@echo "Starting node3..."
|
||||
@nohup ./bin/node --config node3.yaml > $$HOME/.debros/logs/node3.log 2>&1 & echo $$! > .dev/pids/node3.pid
|
||||
@sleep 1
|
||||
@echo "Starting gateway..."
|
||||
@nohup ./bin/gateway --config gateway.yaml > $$HOME/.debros/logs/gateway.log 2>&1 & echo $$! > .dev/pids/gateway.pid
|
||||
@echo ""
|
||||
@echo "1. Generate config files in ~/.debros:"
|
||||
@echo " make build"
|
||||
@echo " ./bin/network-cli config init --type bootstrap"
|
||||
@echo " ./bin/network-cli config init --type node --name node.yaml --bootstrap-peers '<bootstrap_peer_multiaddr>'"
|
||||
@echo " ./bin/network-cli config init --type node --name node2.yaml --bootstrap-peers '<bootstrap_peer_multiaddr>'"
|
||||
@echo "============================================================"
|
||||
@echo "✅ Development stack started!"
|
||||
@echo "============================================================"
|
||||
@echo ""
|
||||
@echo "2. Run in separate terminals:"
|
||||
@echo " Terminal 1: make run-node # Start bootstrap node (bootstrap.yaml)"
|
||||
@echo " Terminal 2: make run-node2 # Start node 1 (node.yaml)"
|
||||
@echo " Terminal 3: make run-node3 # Start node 2 (node2.yaml)"
|
||||
@echo " Terminal 4: make run-gateway # Start gateway"
|
||||
@echo "Processes:"
|
||||
@echo " Bootstrap: PID=$$(cat .dev/pids/bootstrap.pid)"
|
||||
@echo " Node2: PID=$$(cat .dev/pids/node2.pid)"
|
||||
@echo " Node3: PID=$$(cat .dev/pids/node3.pid)"
|
||||
@echo " Gateway: PID=$$(cat .dev/pids/gateway.pid)"
|
||||
@echo ""
|
||||
@echo "3. Or run custom node with any config file:"
|
||||
@echo " go run ./cmd/node --config custom-node.yaml"
|
||||
@echo "Ports:"
|
||||
@echo " Bootstrap P2P: 4001, HTTP: 5001, Raft: 7001"
|
||||
@echo " Node2 P2P: 4002, HTTP: 5002, Raft: 7002"
|
||||
@echo " Node3 P2P: 4003, HTTP: 5003, Raft: 7003"
|
||||
@echo " Gateway: 6001"
|
||||
@echo ""
|
||||
@echo "4. Test:"
|
||||
@echo " make cli-health # Check network health"
|
||||
@echo " make cli-peers # List peers"
|
||||
@echo " make cli-storage-test # Test storage"
|
||||
@echo " make cli-pubsub-test # Test messaging"
|
||||
|
||||
# Full development workflow
|
||||
dev: clean build test
|
||||
@echo "Development workflow complete!"
|
||||
@echo "Press Ctrl+C to stop all processes"
|
||||
@echo "============================================================"
|
||||
@echo ""
|
||||
@trap 'echo "Stopping all processes..."; kill $$(cat .dev/pids/*.pid) 2>/dev/null; rm -f .dev/pids/*.pid; exit 0' INT; \
|
||||
tail -f $$HOME/.debros/logs/bootstrap.log $$HOME/.debros/logs/node2.log $$HOME/.debros/logs/node3.log $$HOME/.debros/logs/gateway.log
|
||||
|
||||
# Help
|
||||
help:
|
||||
@ -189,12 +124,14 @@ help:
|
||||
@echo " clean - Clean build artifacts"
|
||||
@echo " test - Run tests"
|
||||
@echo ""
|
||||
@echo "Development:"
|
||||
@echo " dev - Start full dev stack (bootstrap + 2 nodes + gateway)"
|
||||
@echo " Requires: configs in ~/.debros (run 'network-cli config init' first)"
|
||||
@echo ""
|
||||
@echo "Configuration (NEW):"
|
||||
@echo " First, generate config files in ~/.debros with:"
|
||||
@echo " make build # Build CLI first"
|
||||
@echo " ./bin/network-cli config init --type bootstrap # Generate bootstrap config"
|
||||
@echo " ./bin/network-cli config init --type node --bootstrap-peers '<peer_multiaddr>'"
|
||||
@echo " ./bin/network-cli config init --type gateway"
|
||||
@echo " ./bin/network-cli config init # Generate full stack"
|
||||
@echo ""
|
||||
@echo "Network Targets (requires config files in ~/.debros):"
|
||||
@echo " run-node - Start bootstrap node"
|
||||
|
||||
126
README.md
126
README.md
@ -174,23 +174,36 @@ cd network
|
||||
make build
|
||||
```
|
||||
|
||||
### 3. Start a Bootstrap Node
|
||||
### 3. Generate Configuration Files
|
||||
|
||||
```bash
|
||||
make run-node
|
||||
# Or manually:
|
||||
go run ./cmd/node --config configs/node.yaml
|
||||
# Generate all configs (bootstrap, node2, node3, gateway) with one command
|
||||
./bin/network-cli config init
|
||||
```
|
||||
|
||||
### 4. Start Additional Nodes
|
||||
This creates:
|
||||
- `~/.debros/bootstrap.yaml` - Bootstrap node
|
||||
- `~/.debros/node2.yaml` - Regular node 2
|
||||
- `~/.debros/node3.yaml` - Regular node 3
|
||||
- `~/.debros/gateway.yaml` - HTTP Gateway
|
||||
|
||||
Plus auto-generated identities for each node.
|
||||
|
||||
### 4. Start the Complete Network Stack
|
||||
|
||||
```bash
|
||||
make run-node2
|
||||
# Or manually:
|
||||
go run ./cmd/node --config configs/node.yaml
|
||||
make dev
|
||||
```
|
||||
|
||||
### 5. Test with CLI
|
||||
This starts:
|
||||
- Bootstrap node (P2P: 4001, RQLite HTTP: 5001, Raft: 7001)
|
||||
- Node 2 (P2P: 4002, RQLite HTTP: 5002, Raft: 7002)
|
||||
- Node 3 (P2P: 4003, RQLite HTTP: 5003, Raft: 7003)
|
||||
- Gateway (HTTP: 6001)
|
||||
|
||||
Logs stream to terminal. Press **Ctrl+C** to stop all processes.
|
||||
|
||||
### 5. Test with CLI (in another terminal)
|
||||
|
||||
```bash
|
||||
./bin/network-cli health
|
||||
@ -261,100 +274,103 @@ The system will **only** load config from `~/.debros/` and will error if require
|
||||
|
||||
Use the `network-cli config init` command to generate configuration files:
|
||||
|
||||
#### Generate a Node Config
|
||||
### Generate Complete Stack (Recommended)
|
||||
|
||||
```bash
|
||||
# Generate bootstrap, node2, node3, and gateway configs in one command
|
||||
./bin/network-cli config init
|
||||
|
||||
# Force regenerate (overwrites existing configs)
|
||||
./bin/network-cli config init --force
|
||||
```
|
||||
|
||||
This is the **recommended way** to get started with a local development network.
|
||||
|
||||
### Generate Individual Configs (Advanced)
|
||||
|
||||
For custom setups or production deployments, you can generate individual configs:
|
||||
|
||||
#### Generate a Single Node Config
|
||||
|
||||
```bash
|
||||
# Generate basic node config with bootstrap peers
|
||||
network-cli config init --type node --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx,/ip4/127.0.0.1/tcp/4002/p2p/QmYyy"
|
||||
./bin/network-cli config init --type node --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx"
|
||||
|
||||
# With custom ports
|
||||
network-cli config init --type node --name node2.yaml --listen-port 4002 --rqlite-http-port 5002 --rqlite-raft-port 7002 --join localhost:5001 --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx"
|
||||
./bin/network-cli config init --type node --name node2.yaml \
|
||||
--listen-port 4002 --rqlite-http-port 5002 --rqlite-raft-port 7002 \
|
||||
--join localhost:5001 --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx"
|
||||
|
||||
# Force overwrite existing config
|
||||
network-cli config init --type node --force
|
||||
./bin/network-cli config init --type node --force
|
||||
```
|
||||
|
||||
#### Generate a Bootstrap Node Config
|
||||
|
||||
```bash
|
||||
# Generate bootstrap node (no join address required)
|
||||
network-cli config init --type bootstrap
|
||||
./bin/network-cli config init --type bootstrap
|
||||
|
||||
# With custom ports
|
||||
network-cli config init --type bootstrap --listen-port 4001 --rqlite-http-port 5001 --rqlite-raft-port 7001
|
||||
./bin/network-cli config init --type bootstrap --listen-port 4001 --rqlite-http-port 5001 --rqlite-raft-port 7001
|
||||
```
|
||||
|
||||
#### Generate a Gateway Config
|
||||
|
||||
```bash
|
||||
# Generate gateway config
|
||||
network-cli config init --type gateway
|
||||
./bin/network-cli config init --type gateway
|
||||
|
||||
# With bootstrap peers
|
||||
network-cli config init --type gateway --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx"
|
||||
./bin/network-cli config init --type gateway --bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/QmXxx"
|
||||
```
|
||||
|
||||
### Running Multiple Nodes on the Same Machine
|
||||
### Running the Network
|
||||
|
||||
You can run multiple nodes on a single machine by creating separate configuration files and using the `--config` flag:
|
||||
|
||||
#### Create Multiple Node Configs
|
||||
Once configs are generated, start the complete stack with:
|
||||
|
||||
```bash
|
||||
# Node 1
|
||||
./bin/network-cli config init --type node --name node1.yaml \
|
||||
--listen-port 4001 --rqlite-http-port 5001 --rqlite-raft-port 7001 \
|
||||
--bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/<BOOTSTRAP_ID>"
|
||||
|
||||
# Node 2
|
||||
./bin/network-cli config init --type node --name node2.yaml \
|
||||
--listen-port 4002 --rqlite-http-port 5002 --rqlite-raft-port 7002 \
|
||||
--join localhost:5001 \
|
||||
--bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/<BOOTSTRAP_ID>"
|
||||
|
||||
# Node 3
|
||||
./bin/network-cli config init --type node --name node3.yaml \
|
||||
--listen-port 4003 --rqlite-http-port 5003 --rqlite-raft-port 7003 \
|
||||
--join localhost:5001 \
|
||||
--bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/<BOOTSTRAP_ID>"
|
||||
make dev
|
||||
```
|
||||
|
||||
#### Run Multiple Nodes in Separate Terminals
|
||||
Or start individual components (in separate terminals):
|
||||
|
||||
```bash
|
||||
# Terminal 1 - Bootstrap node
|
||||
go run ./cmd/node --config bootstrap.yaml
|
||||
|
||||
# Terminal 2 - Node 1
|
||||
go run ./cmd/node --config node1.yaml
|
||||
|
||||
# Terminal 3 - Node 2
|
||||
# Terminal 2 - Node 2
|
||||
go run ./cmd/node --config node2.yaml
|
||||
|
||||
# Terminal 4 - Node 3
|
||||
# Terminal 3 - Node 3
|
||||
go run ./cmd/node --config node3.yaml
|
||||
|
||||
# Terminal 4 - Gateway
|
||||
go run ./cmd/gateway --config gateway.yaml
|
||||
```
|
||||
|
||||
#### Or Use Makefile Targets
|
||||
### Running Multiple Nodes on the Same Machine
|
||||
|
||||
The default `make dev` creates a 3-node setup. For additional nodes, generate individual configs:
|
||||
|
||||
```bash
|
||||
# Terminal 1
|
||||
make run-node # Runs: go run ./cmd/node --config bootstrap.yaml
|
||||
# Generate additional node configs with unique ports
|
||||
./bin/network-cli config init --type node --name node4.yaml \
|
||||
--listen-port 4004 --rqlite-http-port 5004 --rqlite-raft-port 7004 \
|
||||
--join localhost:5001 \
|
||||
--bootstrap-peers "/ip4/127.0.0.1/tcp/4001/p2p/<BOOTSTRAP_ID>"
|
||||
|
||||
# Terminal 2
|
||||
make run-node2 # Runs: go run ./cmd/node --config node.yaml
|
||||
|
||||
# Terminal 3
|
||||
make run-node3 # Runs: go run ./cmd/node --config node2.yaml
|
||||
# Start the additional node
|
||||
go run ./cmd/node --config node4.yaml
|
||||
```
|
||||
|
||||
#### Key Points for Multiple Nodes
|
||||
|
||||
- **Each node needs unique ports**: P2P port, RQLite HTTP port, and RQLite Raft port must all be different
|
||||
- **Join address**: Non-bootstrap nodes need `rqlite_join_address` pointing to the bootstrap or an existing node
|
||||
- **Join address**: Non-bootstrap nodes need `rqlite_join_address` pointing to the bootstrap or an existing node (use Raft port)
|
||||
- **Bootstrap peers**: All nodes need the bootstrap node's multiaddr in `discovery.bootstrap_peers`
|
||||
- **Config files**: Store all configs in `~/.debros/` with different filenames
|
||||
- **--config flag**: Specify which config file to load (defaults to `node.yaml`)
|
||||
- **--config flag**: Specify which config file to load
|
||||
|
||||
⚠️ **Common Mistake - Same Ports:**
|
||||
If all nodes use the same ports (e.g., 5001, 7001), they will try to bind to the same addresses and fail to communicate. Verify each node has unique ports:
|
||||
@ -365,11 +381,11 @@ grep "rqlite_port\|rqlite_raft_port" ~/.debros/bootstrap.yaml
|
||||
# Should show: rqlite_port: 5001, rqlite_raft_port: 7001
|
||||
|
||||
# Node 2
|
||||
grep "rqlite_port\|rqlite_raft_port" ~/.debros/node.yaml
|
||||
grep "rqlite_port\|rqlite_raft_port" ~/.debros/node2.yaml
|
||||
# Should show: rqlite_port: 5002, rqlite_raft_port: 7002
|
||||
|
||||
# Node 3
|
||||
grep "rqlite_port\|rqlite_raft_port" ~/.debros/node2.yaml
|
||||
grep "rqlite_port\|rqlite_raft_port" ~/.debros/node3.yaml
|
||||
# Should show: rqlite_port: 5003, rqlite_raft_port: 7003
|
||||
```
|
||||
|
||||
|
||||
225
cmd/cli/main.go
225
cmd/cli/main.go
@ -15,6 +15,7 @@ import (
|
||||
"github.com/DeBrosOfficial/network/pkg/auth"
|
||||
"github.com/DeBrosOfficial/network/pkg/client"
|
||||
"github.com/DeBrosOfficial/network/pkg/config"
|
||||
"github.com/DeBrosOfficial/network/pkg/encryption"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
@ -607,30 +608,35 @@ func showConfigHelp() {
|
||||
fmt.Printf("Config Management Commands\n\n")
|
||||
fmt.Printf("Usage: network-cli config <subcommand> [options]\n\n")
|
||||
fmt.Printf("Subcommands:\n")
|
||||
fmt.Printf(" init - Generate configuration files in ~/.debros\n")
|
||||
fmt.Printf(" init - Generate full network stack in ~/.debros (bootstrap + 2 nodes + gateway)\n")
|
||||
fmt.Printf(" validate --name <file> - Validate a config file\n\n")
|
||||
fmt.Printf("Init Default Behavior (no --type):\n")
|
||||
fmt.Printf(" Generates bootstrap.yaml, node2.yaml, node3.yaml, gateway.yaml with:\n")
|
||||
fmt.Printf(" - Auto-generated identities for bootstrap, node2, node3\n")
|
||||
fmt.Printf(" - Correct bootstrap_peers and join addresses\n")
|
||||
fmt.Printf(" - Default ports: P2P 4001-4003, HTTP 5001-5003, Raft 7001-7003\n\n")
|
||||
fmt.Printf("Init Options:\n")
|
||||
fmt.Printf(" --type <type> - Config type: node, bootstrap, gateway (default: node)\n")
|
||||
fmt.Printf(" --name <file> - Output filename (default: node.yaml)\n")
|
||||
fmt.Printf(" --type <type> - Single config type: node, bootstrap, gateway (skips stack generation)\n")
|
||||
fmt.Printf(" --name <file> - Output filename (default: depends on --type or 'stack' for full stack)\n")
|
||||
fmt.Printf(" --force - Overwrite existing config/stack files\n\n")
|
||||
fmt.Printf("Single Config Options (with --type):\n")
|
||||
fmt.Printf(" --id <id> - Node ID for bootstrap peers\n")
|
||||
fmt.Printf(" --listen-port <port> - LibP2P listen port (default: 4001)\n")
|
||||
fmt.Printf(" --rqlite-http-port <port> - RQLite HTTP port (default: 5001)\n")
|
||||
fmt.Printf(" --rqlite-raft-port <port> - RQLite Raft port (default: 7001)\n")
|
||||
fmt.Printf(" --join <host:port> - RQLite address to join (required for non-bootstrap)\n")
|
||||
fmt.Printf(" --bootstrap-peers <peers> - Comma-separated bootstrap peer multiaddrs\n")
|
||||
fmt.Printf(" --force - Overwrite existing config\n\n")
|
||||
fmt.Printf(" --bootstrap-peers <peers> - Comma-separated bootstrap peer multiaddrs\n\n")
|
||||
fmt.Printf("Examples:\n")
|
||||
fmt.Printf(" network-cli config init\n")
|
||||
fmt.Printf(" network-cli config init --type node --bootstrap-peers /ip4/127.0.0.1/tcp/4001/p2p/QmXxx,/ip4/127.0.0.1/tcp/4002/p2p/QmYyy\n")
|
||||
fmt.Printf(" network-cli config init --type bootstrap\n")
|
||||
fmt.Printf(" network-cli config init --type gateway\n")
|
||||
fmt.Printf(" network-cli config init # Generate full stack\n")
|
||||
fmt.Printf(" network-cli config init --force # Overwrite existing stack\n")
|
||||
fmt.Printf(" network-cli config init --type bootstrap # Single bootstrap config (legacy)\n")
|
||||
fmt.Printf(" network-cli config validate --name node.yaml\n")
|
||||
}
|
||||
|
||||
func handleConfigInit(args []string) {
|
||||
// Parse flags
|
||||
var (
|
||||
cfgType = "node"
|
||||
cfgType = ""
|
||||
name = "" // Will be set based on type if not provided
|
||||
id string
|
||||
listenPort = 4001
|
||||
@ -694,6 +700,13 @@ func handleConfigInit(args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
// If --type is not specified, generate full stack
|
||||
if cfgType == "" {
|
||||
initFullStack(force)
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, continue with single-file generation
|
||||
// Validate type
|
||||
if cfgType != "node" && cfgType != "bootstrap" && cfgType != "gateway" {
|
||||
fmt.Fprintf(os.Stderr, "Invalid --type: %s (expected: node, bootstrap, or gateway)\n", cfgType)
|
||||
@ -799,6 +812,192 @@ func handleConfigValidate(args []string) {
|
||||
fmt.Printf("✅ Config is valid: %s\n", configPath)
|
||||
}
|
||||
|
||||
func initFullStack(force bool) {
|
||||
fmt.Printf("🚀 Initializing full network stack...\n")
|
||||
|
||||
// Ensure ~/.debros directory exists
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to get home directory: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
debrosDir := filepath.Join(homeDir, ".debros")
|
||||
if err := os.MkdirAll(debrosDir, 0755); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to create ~/.debros directory: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Step 1: Generate bootstrap identity
|
||||
bootstrapIdentityDir := filepath.Join(debrosDir, "bootstrap")
|
||||
bootstrapIdentityPath := filepath.Join(bootstrapIdentityDir, "identity.key")
|
||||
|
||||
if !force {
|
||||
if _, err := os.Stat(bootstrapIdentityPath); err == nil {
|
||||
fmt.Fprintf(os.Stderr, "Bootstrap identity already exists at %s (use --force to overwrite)\n", bootstrapIdentityPath)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
bootstrapInfo, err := encryption.GenerateIdentity()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to generate bootstrap identity: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := os.MkdirAll(bootstrapIdentityDir, 0755); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to create bootstrap data directory: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := encryption.SaveIdentity(bootstrapInfo, bootstrapIdentityPath); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to save bootstrap identity: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("✅ Generated bootstrap identity: %s (Peer ID: %s)\n", bootstrapIdentityPath, bootstrapInfo.PeerID.String())
|
||||
|
||||
// Construct bootstrap multiaddr
|
||||
bootstrapMultiaddr := fmt.Sprintf("/ip4/127.0.0.1/tcp/4001/p2p/%s", bootstrapInfo.PeerID.String())
|
||||
fmt.Printf(" Bootstrap multiaddr: %s\n", bootstrapMultiaddr)
|
||||
|
||||
// Step 2: Generate bootstrap.yaml
|
||||
bootstrapName := "bootstrap.yaml"
|
||||
bootstrapPath := filepath.Join(debrosDir, bootstrapName)
|
||||
if !force {
|
||||
if _, err := os.Stat(bootstrapPath); err == nil {
|
||||
fmt.Fprintf(os.Stderr, "Bootstrap config already exists at %s (use --force to overwrite)\n", bootstrapPath)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
bootstrapContent := generateBootstrapConfig(bootstrapName, "", 4001, 5001, 7001)
|
||||
if err := os.WriteFile(bootstrapPath, []byte(bootstrapContent), 0644); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write bootstrap config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("✅ Generated bootstrap config: %s\n", bootstrapPath)
|
||||
|
||||
// Step 3: Generate node2 identity and config
|
||||
node2IdentityDir := filepath.Join(debrosDir, "node2")
|
||||
node2IdentityPath := filepath.Join(node2IdentityDir, "identity.key")
|
||||
|
||||
if !force {
|
||||
if _, err := os.Stat(node2IdentityPath); err == nil {
|
||||
fmt.Fprintf(os.Stderr, "Node2 identity already exists at %s (use --force to overwrite)\n", node2IdentityPath)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
node2Info, err := encryption.GenerateIdentity()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to generate node2 identity: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := os.MkdirAll(node2IdentityDir, 0755); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to create node2 data directory: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := encryption.SaveIdentity(node2Info, node2IdentityPath); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to save node2 identity: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("✅ Generated node2 identity: %s (Peer ID: %s)\n", node2IdentityPath, node2Info.PeerID.String())
|
||||
|
||||
node2Name := "node2.yaml"
|
||||
node2Path := filepath.Join(debrosDir, node2Name)
|
||||
if !force {
|
||||
if _, err := os.Stat(node2Path); err == nil {
|
||||
fmt.Fprintf(os.Stderr, "Node2 config already exists at %s (use --force to overwrite)\n", node2Path)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
node2Content := generateNodeConfig(node2Name, "", 4002, 5002, 7002, "127.0.0.1:7001", bootstrapMultiaddr)
|
||||
if err := os.WriteFile(node2Path, []byte(node2Content), 0644); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write node2 config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("✅ Generated node2 config: %s\n", node2Path)
|
||||
|
||||
// Step 4: Generate node3 identity and config
|
||||
node3IdentityDir := filepath.Join(debrosDir, "node3")
|
||||
node3IdentityPath := filepath.Join(node3IdentityDir, "identity.key")
|
||||
|
||||
if !force {
|
||||
if _, err := os.Stat(node3IdentityPath); err == nil {
|
||||
fmt.Fprintf(os.Stderr, "Node3 identity already exists at %s (use --force to overwrite)\n", node3IdentityPath)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
node3Info, err := encryption.GenerateIdentity()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to generate node3 identity: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := os.MkdirAll(node3IdentityDir, 0755); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to create node3 data directory: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := encryption.SaveIdentity(node3Info, node3IdentityPath); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to save node3 identity: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("✅ Generated node3 identity: %s (Peer ID: %s)\n", node3IdentityPath, node3Info.PeerID.String())
|
||||
|
||||
node3Name := "node3.yaml"
|
||||
node3Path := filepath.Join(debrosDir, node3Name)
|
||||
if !force {
|
||||
if _, err := os.Stat(node3Path); err == nil {
|
||||
fmt.Fprintf(os.Stderr, "Node3 config already exists at %s (use --force to overwrite)\n", node3Path)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
node3Content := generateNodeConfig(node3Name, "", 4003, 5003, 7003, "127.0.0.1:7001", bootstrapMultiaddr)
|
||||
if err := os.WriteFile(node3Path, []byte(node3Content), 0644); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write node3 config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("✅ Generated node3 config: %s\n", node3Path)
|
||||
|
||||
// Step 5: Generate gateway.yaml
|
||||
gatewayName := "gateway.yaml"
|
||||
gatewayPath := filepath.Join(debrosDir, gatewayName)
|
||||
if !force {
|
||||
if _, err := os.Stat(gatewayPath); err == nil {
|
||||
fmt.Fprintf(os.Stderr, "Gateway config already exists at %s (use --force to overwrite)\n", gatewayPath)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
gatewayContent := generateGatewayConfig(bootstrapMultiaddr)
|
||||
if err := os.WriteFile(gatewayPath, []byte(gatewayContent), 0644); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to write gateway config: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("✅ Generated gateway config: %s\n", gatewayPath)
|
||||
|
||||
// Print summary
|
||||
fmt.Printf("\n" + strings.Repeat("=", 60) + "\n")
|
||||
fmt.Printf("✅ Full network stack initialized successfully!\n")
|
||||
fmt.Printf(strings.Repeat("=", 60) + "\n\n")
|
||||
fmt.Printf("Configuration files created in: %s\n\n", debrosDir)
|
||||
fmt.Printf("Bootstrap Node:\n")
|
||||
fmt.Printf(" Config: %s\n", bootstrapPath)
|
||||
fmt.Printf(" Peer ID: %s\n", bootstrapInfo.PeerID.String())
|
||||
fmt.Printf(" Ports: P2P=4001, HTTP=5001, Raft=7001\n\n")
|
||||
fmt.Printf("Node2:\n")
|
||||
fmt.Printf(" Config: %s\n", node2Path)
|
||||
fmt.Printf(" Ports: P2P=4002, HTTP=5002, Raft=7002\n")
|
||||
fmt.Printf(" Join: 127.0.0.1:7001\n\n")
|
||||
fmt.Printf("Node3:\n")
|
||||
fmt.Printf(" Config: %s\n", node3Path)
|
||||
fmt.Printf(" Ports: P2P=4003, HTTP=5003, Raft=7003\n")
|
||||
fmt.Printf(" Join: 127.0.0.1:7001\n\n")
|
||||
fmt.Printf("Gateway:\n")
|
||||
fmt.Printf(" Config: %s\n\n", gatewayPath)
|
||||
fmt.Printf("To start the network:\n")
|
||||
fmt.Printf(" Terminal 1: ./bin/node --config bootstrap.yaml\n")
|
||||
fmt.Printf(" Terminal 2: ./bin/node --config node2.yaml\n")
|
||||
fmt.Printf(" Terminal 3: ./bin/node --config node3.yaml\n")
|
||||
fmt.Printf(" Terminal 4: ./bin/gateway --config gateway.yaml\n")
|
||||
fmt.Printf("\n" + strings.Repeat("=", 60) + "\n")
|
||||
}
|
||||
|
||||
func generateNodeConfig(name, id string, listenPort, rqliteHTTPPort, rqliteRaftPort int, joinAddr, bootstrapPeers string) string {
|
||||
nodeID := id
|
||||
if nodeID == "" {
|
||||
@ -923,11 +1122,11 @@ func generateGatewayConfig(bootstrapPeers string) string {
|
||||
|
||||
var peersYAML strings.Builder
|
||||
if len(peers) == 0 {
|
||||
peersYAML.WriteString(" bootstrap_peers: []")
|
||||
peersYAML.WriteString("bootstrap_peers: []")
|
||||
} else {
|
||||
peersYAML.WriteString(" bootstrap_peers:\n")
|
||||
peersYAML.WriteString("bootstrap_peers:\n")
|
||||
for _, p := range peers {
|
||||
fmt.Fprintf(&peersYAML, " - \"%s\"\n", p)
|
||||
fmt.Fprintf(&peersYAML, " - \"%s\"\n", p)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
105
pkg/node/node.go
105
pkg/node/node.go
@ -84,35 +84,35 @@ func (n *Node) startRQLite(ctx context.Context) error {
|
||||
|
||||
// bootstrapPeerSource returns a PeerSource that yields peers from BootstrapPeers.
|
||||
func bootstrapPeerSource(bootstrapAddrs []string, logger *zap.Logger) func(context.Context, int) <-chan peer.AddrInfo {
|
||||
return func(ctx context.Context, num int) <-chan peer.AddrInfo {
|
||||
out := make(chan peer.AddrInfo, num)
|
||||
go func() {
|
||||
defer close(out)
|
||||
count := 0
|
||||
for _, s := range bootstrapAddrs {
|
||||
if count >= num {
|
||||
return
|
||||
}
|
||||
ma, err := multiaddr.NewMultiaddr(s)
|
||||
if err != nil {
|
||||
logger.Debug("invalid bootstrap multiaddr", zap.String("addr", s), zap.Error(err))
|
||||
continue
|
||||
}
|
||||
ai, err := peer.AddrInfoFromP2pAddr(ma)
|
||||
if err != nil {
|
||||
logger.Debug("failed to parse bootstrap peer", zap.String("addr", s), zap.Error(err))
|
||||
continue
|
||||
}
|
||||
select {
|
||||
case out <- *ai:
|
||||
count++
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
return func(ctx context.Context, num int) <-chan peer.AddrInfo {
|
||||
out := make(chan peer.AddrInfo, num)
|
||||
go func() {
|
||||
defer close(out)
|
||||
count := 0
|
||||
for _, s := range bootstrapAddrs {
|
||||
if count >= num {
|
||||
return
|
||||
}
|
||||
ma, err := multiaddr.NewMultiaddr(s)
|
||||
if err != nil {
|
||||
logger.Debug("invalid bootstrap multiaddr", zap.String("addr", s), zap.Error(err))
|
||||
continue
|
||||
}
|
||||
ai, err := peer.AddrInfoFromP2pAddr(ma)
|
||||
if err != nil {
|
||||
logger.Debug("failed to parse bootstrap peer", zap.String("addr", s), zap.Error(err))
|
||||
continue
|
||||
}
|
||||
select {
|
||||
case out <- *ai:
|
||||
count++
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
// hasBootstrapConnections checks if we're connected to any bootstrap peers
|
||||
@ -250,21 +250,52 @@ func (n *Node) startLibP2P() error {
|
||||
return fmt.Errorf("failed to load identity: %w", err)
|
||||
}
|
||||
|
||||
// Create LibP2P host with NAT traversal support
|
||||
// Create LibP2P host with explicit listen addresses
|
||||
var opts []libp2p.Option
|
||||
opts = append(opts,
|
||||
libp2p.Identity(identity),
|
||||
libp2p.Security(noise.ID, noise.New),
|
||||
libp2p.DefaultMuxers,
|
||||
libp2p.EnableNATService(),
|
||||
libp2p.EnableAutoNATv2(),
|
||||
libp2p.EnableRelay(),
|
||||
libp2p.NATPortMap(),
|
||||
libp2p.EnableAutoRelayWithPeerSource(
|
||||
bootstrapPeerSource(n.config.Discovery.BootstrapPeers, n.logger.Logger),
|
||||
),
|
||||
)
|
||||
|
||||
// Add explicit listen addresses from config
|
||||
if len(n.config.Node.ListenAddresses) > 0 {
|
||||
listenAddrs := make([]multiaddr.Multiaddr, 0, len(n.config.Node.ListenAddresses))
|
||||
for _, addr := range n.config.Node.ListenAddresses {
|
||||
ma, err := multiaddr.NewMultiaddr(addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid listen address %s: %w", addr, err)
|
||||
}
|
||||
listenAddrs = append(listenAddrs, ma)
|
||||
}
|
||||
opts = append(opts, libp2p.ListenAddrs(listenAddrs...))
|
||||
n.logger.ComponentInfo(logging.ComponentLibP2P, "Configured listen addresses",
|
||||
zap.Strings("addrs", n.config.Node.ListenAddresses))
|
||||
}
|
||||
|
||||
// For localhost/development, disable NAT services
|
||||
// For production, these would be enabled
|
||||
isLocalhost := len(n.config.Node.ListenAddresses) > 0 &&
|
||||
(strings.Contains(n.config.Node.ListenAddresses[0], "127.0.0.1") ||
|
||||
strings.Contains(n.config.Node.ListenAddresses[0], "localhost"))
|
||||
|
||||
if isLocalhost {
|
||||
n.logger.ComponentInfo(logging.ComponentLibP2P, "Localhost detected - disabling NAT services for local development")
|
||||
// Don't add NAT/AutoRelay options for localhost
|
||||
} else {
|
||||
// Production: enable NAT traversal
|
||||
n.logger.ComponentInfo(logging.ComponentLibP2P, "Production mode - enabling NAT services")
|
||||
opts = append(opts,
|
||||
libp2p.EnableNATService(),
|
||||
libp2p.EnableAutoNATv2(),
|
||||
libp2p.EnableRelay(),
|
||||
libp2p.NATPortMap(),
|
||||
libp2p.EnableAutoRelayWithPeerSource(
|
||||
bootstrapPeerSource(n.config.Discovery.BootstrapPeers, n.logger.Logger),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
h, err := libp2p.New(opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user