Add production environment support for bootstrap peers and RQLite connections

This commit is contained in:
anonpenguin 2025-08-04 18:31:49 +03:00
parent 9832e97ed8
commit bf32cc2a49
5 changed files with 74 additions and 24 deletions

2
.gitignore vendored
View File

@ -70,4 +70,4 @@ data/*
./node
data/bootstrap/rqlite/
.env
.env.*

View File

@ -11,12 +11,14 @@ import (
"time"
"git.debros.io/DeBros/network/pkg/client"
"git.debros.io/DeBros/network/pkg/constants"
)
var (
bootstrapPeer = "/ip4/127.0.0.1/tcp/4001"
timeout = 30 * time.Second
format = "table"
useProduction = false
)
func main() {
@ -80,6 +82,8 @@ func parseGlobalFlags(args []string) {
timeout = d
}
}
case "--production":
useProduction = true
}
}
}
@ -348,14 +352,26 @@ func handleConnect(peerAddr string) {
}
func createClient() (client.NetworkClient, error) {
// Try to discover the bootstrap peer from saved peer info
discoveredPeer := discoverBootstrapPeer()
if discoveredPeer != "" {
bootstrapPeer = discoveredPeer
var bootstrapPeers []string
if useProduction {
// Set environment to production to trigger production bootstrap peers
os.Setenv("ENVIRONMENT", "production")
bootstrapPeers = constants.GetBootstrapPeers()
if format != "json" {
fmt.Printf("🔗 Using production bootstrap peers\n")
}
} else {
// Try to discover the bootstrap peer from saved peer info
discoveredPeer := discoverBootstrapPeer()
if discoveredPeer != "" {
bootstrapPeer = discoveredPeer
}
bootstrapPeers = []string{bootstrapPeer}
}
config := client.DefaultClientConfig("network-cli")
config.BootstrapPeers = []string{bootstrapPeer}
config.BootstrapPeers = bootstrapPeers
config.ConnectTimeout = timeout
config.QuietMode = true // Suppress debug/info logs for CLI
@ -441,10 +457,12 @@ func showHelp() {
fmt.Printf("Global Flags:\n")
fmt.Printf(" -b, --bootstrap <addr> - Bootstrap peer address (default: /ip4/127.0.0.1/tcp/4001)\n")
fmt.Printf(" -f, --format <format> - Output format: table, json (default: table)\n")
fmt.Printf(" -t, --timeout <duration> - Operation timeout (default: 30s)\n\n")
fmt.Printf(" -t, --timeout <duration> - Operation timeout (default: 30s)\n")
fmt.Printf(" --production - Connect to production bootstrap peers\n\n")
fmt.Printf("Examples:\n")
fmt.Printf(" network-cli health\n")
fmt.Printf(" network-cli peers --format json\n")
fmt.Printf(" network-cli peers --production\n")
fmt.Printf(" network-cli storage put user:123 '{\"name\":\"Alice\"}'\n")
fmt.Printf(" network-cli pubsub subscribe notifications 1m\n")
}

View File

@ -3,6 +3,7 @@ package client
import (
"context"
"fmt"
"os"
"strings"
"sync"
"time"
@ -169,14 +170,8 @@ func (d *DatabaseClientImpl) getRQLiteConnection() (*gorqlite.Connection, error)
// connectToAvailableNode tries to connect to any available RQLite node
func (d *DatabaseClientImpl) connectToAvailableNode() (*gorqlite.Connection, error) {
// List of RQLite nodes to try (bootstrap, node1, node2, etc.)
rqliteNodes := []string{
"http://localhost:5001", // bootstrap
"http://localhost:5002", // node1
"http://localhost:5003", // node2
"http://localhost:5004", // node3 (if exists)
"http://localhost:5005", // node4 (if exists)
}
// Get RQLite nodes from environment or use defaults
rqliteNodes := d.getRQLiteNodes()
var lastErr error
@ -201,6 +196,32 @@ func (d *DatabaseClientImpl) connectToAvailableNode() (*gorqlite.Connection, err
return nil, fmt.Errorf("failed to connect to any RQLite instance. Last error: %w", lastErr)
}
// getRQLiteNodes returns a list of RQLite node URLs from environment or defaults
func (d *DatabaseClientImpl) getRQLiteNodes() []string {
// Try to get RQLite nodes from environment variable
if envNodes := os.Getenv("RQLITE_NODES"); envNodes != "" {
return strings.Split(envNodes, ",")
}
// Check if we're in production environment
if env := os.Getenv("ENVIRONMENT"); env == "production" {
// Use production servers with RQLite HTTP API ports (network port + 1000)
return []string{
"http://57.129.81.31:5001", // production server 1
"http://38.242.250.186:5001", // production server 2
}
}
// Fallback to localhost for development
return []string{
"http://localhost:5001", // bootstrap
"http://localhost:5002", // node1
"http://localhost:5003", // node2
"http://localhost:5004", // node3 (if exists)
"http://localhost:5005", // node4 (if exists)
}
}
// testConnection performs a health check on the RQLite connection
func (d *DatabaseClientImpl) testConnection(conn *gorqlite.Connection) error {
// Try a simple read query first (works even without leadership)

View File

@ -87,15 +87,25 @@ func loadEnvironmentConfig() {
// setDefaultBootstrapConfig sets default bootstrap configuration
func setDefaultBootstrapConfig() {
BootstrapPeerIDs = []string{
"12D3KooWN3AQHuxAzXfu98tiFYw7W3N2SyDwdxDRANXJp3ktVf8j",
"12D3KooWQRK2duw5B5LXi8gA7HBBFiCsLvwyph2ZU9VBmvbE1Nei",
"12D3KooWGbdnA22bN24X2gyY1o9jozwTBq9wbfvwtJ7G4XQ9JgFm",
}
BootstrapAddresses = []string{
"/ip4/127.0.0.1/tcp/4001/p2p/12D3KooWN3AQHuxAzXfu98tiFYw7W3N2SyDwdxDRANXJp3ktVf8j",
"/ip4/57.129.81.31/tcp/4001/p2p/12D3KooWQRK2duw5B5LXi8gA7HBBFiCsLvwyph2ZU9VBmvbE1Nei",
"/ip4/38.242.250.186/tcp/4001/p2p/12D3KooWGbdnA22bN24X2gyY1o9jozwTBq9wbfvwtJ7G4XQ9JgFm",
// Check if we're in production environment
if env := os.Getenv("ENVIRONMENT"); env == "production" {
// Production: only use live production peers
BootstrapPeerIDs = []string{
"12D3KooWQRK2duw5B5LXi8gA7HBBFiCsLvwyph2ZU9VBmvbE1Nei",
"12D3KooWGbdnA22bN24X2gyY1o9jozwTBq9wbfvwtJ7G4XQ9JgFm",
}
BootstrapAddresses = []string{
"/ip4/57.129.81.31/tcp/4001/p2p/12D3KooWQRK2duw5B5LXi8gA7HBBFiCsLvwyph2ZU9VBmvbE1Nei",
"/ip4/38.242.250.186/tcp/4001/p2p/12D3KooWGbdnA22bN24X2gyY1o9jozwTBq9wbfvwtJ7G4XQ9JgFm",
}
} else {
// Development: only use localhost bootstrap
BootstrapPeerIDs = []string{
"12D3KooWN3AQHuxAzXfu98tiFYw7W3N2SyDwdxDRANXJp3ktVf8j",
}
BootstrapAddresses = []string{
"/ip4/127.0.0.1/tcp/4001/p2p/12D3KooWN3AQHuxAzXfu98tiFYw7W3N2SyDwdxDRANXJp3ktVf8j",
}
}
BootstrapPort = 4001
}

View File

@ -706,6 +706,7 @@ Type=simple
User=debros
Group=debros
WorkingDirectory=$INSTALL_DIR
Environment=ENVIRONMENT=production
ExecStart=$exec_start
Restart=always
RestartSec=10