Rewrite docs for modern node/client architecture and install system

This commit is contained in:
anonpenguin 2025-08-14 15:19:23 +03:00
parent 170b06b213
commit a6129d3fc2
3 changed files with 447 additions and 1492 deletions

View File

@ -3,574 +3,266 @@
## Table of Contents ## Table of Contents
- [Project Overview](#project-overview) - [Project Overview](#project-overview)
- [Product Requirements Document (PRD)](#product-requirements-document-prd)
- [Architecture Overview](#architecture-overview) - [Architecture Overview](#architecture-overview)
- [Codebase Structure](#codebase-structure) - [Codebase Structure](#codebase-structure)
- [Key Components](#key-components) - [Key Components](#key-components)
- [Network Protocol](#network-protocol) - [Configuration System](#configuration-system)
- [Data Flow](#data-flow) - [Node vs Client Roles](#node-vs-client-roles)
- [Network Protocol & Data Flow](#network-protocol--data-flow)
- [Build & Development](#build--development) - [Build & Development](#build--development)
- [API Reference](#api-reference) - [API Reference](#api-reference)
- [Troubleshooting](#troubleshooting) - [Troubleshooting](#troubleshooting)
- [Example Application: Anchat](#example-application-anchat)
---
## Project Overview ## Project Overview
**DeBros Network Cluster** is a decentralized peer-to-peer (P2P) network built in Go that provides distributed database operations, key-value storage, pub/sub messaging, and peer discovery. The system is designed for applications that need resilient, distributed data management without relying on centralized infrastructure. **DeBros Network Cluster** is a decentralized peer-to-peer (P2P) system built in Go, providing distributed database operations, key-value storage, pub/sub messaging, and peer management. It is designed for resilient, distributed data management and communication, with a clear separation between full network nodes and lightweight clients.
## Product Requirements Document (PRD) ---
### Vision
Create a robust, decentralized network platform that enables applications to seamlessly share data, communicate, and discover peers in a distributed environment.
### Core Requirements
#### Functional Requirements
1. **Distributed Database Operations**
- SQL query execution across network nodes
- ACID transactions with eventual consistency
- Schema management and table operations
- Multi-node resilience with automatic failover
2. **Key-Value Storage**
- Distributed storage with namespace isolation
- CRUD operations with consistency guarantees
- Prefix-based querying and key enumeration
- Data replication across network participants
3. **Pub/Sub Messaging**
- Topic-based publish/subscribe communication
- Real-time message delivery with ordering guarantees
- Subscription management with automatic cleanup
- Namespace isolation per application
4. **Peer Discovery & Management**
- Automatic peer discovery using DHT (Distributed Hash Table)
- Bootstrap node support for network joining
- Connection health monitoring and recovery
- Peer exchange for network growth
5. **Application Isolation**
- Namespace-based multi-tenancy
- Per-application data segregation
- Independent configuration and lifecycle management
#### Non-Functional Requirements
1. **Reliability**: 99.9% uptime with automatic failover
2. **Scalability**: Support 100+ nodes with linear performance
3. **Security**: End-to-end encryption for sensitive data
4. **Performance**: <100ms latency for local operations
5. **Developer Experience**: Simple client API with comprehensive examples
### Success Metrics
- Network uptime > 99.9%
- Peer discovery time < 30 seconds
- Database operation latency < 500ms
- Message delivery success rate > 99.5%
## Architecture Overview ## Architecture Overview
The architecture is modular and robust, supporting both full nodes (which run core services and participate in discovery) and lightweight clients (which connect to the network via bootstrap peers).
``` ```
┌─────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────┐
│ DeBros Network Cluster │ │ DeBros Network Cluster │
├─────────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────────┤
│ Application Layer │ │ Application Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ ┌─────────────┐ ┌─────────────┐ ┌───────────────────────┐ │
│ │ Anchat │ │ Custom App │ │ CLI Tools │ │ │ │ Anchat │ │ Custom App │ │ CLI Tools │ │
│ │ (Chat) │ │ │ │ │ │ │ └─────────────┘ └─────────────┘ └───────────────────────┘ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
├─────────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────────┤
│ Client API │ │ Client API │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ ┌─────────────┐ ┌─────────────┐ ┌───────────────────────┐ │
│ │ Database │ │ Storage │ │ PubSub │ │ │ │ Database │ │ Storage │ │ PubSub │ │
│ │ Client │ │ Client │ │ Client │ │ │ │ Client │ │ Client │ │ Client │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │ │ └─────────────┘ └─────────────┘ └───────────────────────┘ │
├─────────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────────┤
│ Network Layer │ │ Network Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ ┌─────────────┐ ┌─────────────┐ ┌───────────────────────┐ │
│ │ Discovery │ PubSub │ │ Consensus │ │ │ │ Node │ │ Discovery │ │ PubSub │ │
│ │ Manager │ │ Manager │ │ (RQLite) │ │ │ │ (Full P2P) │ │ Manager │ │ Manager │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │ │ └─────────────┘ └─────────────┘ └───────────────────────┘ │
├─────────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────────┤
Transport Layer │ Database Layer (RQLite) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ ┌─────────────┐ │
│ │ LibP2P │ │ DHT │ │ RQLite │ │ │ RQLite │ │
│ │ Host │ │ Kademlia │ │ Database │ │ │ Consensus │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────┘
``` ```
### Key Design Principles **Key Principles:**
- **Modularity:** Each component is independently testable and replaceable.
- **Fault Tolerance:** Network continues operating with node failures.
- **Security:** End-to-end encryption, peer authentication, and namespace isolation.
- **Performance:** Optimized for common operations, with connection pooling and caching.
1. **Modularity**: Each component can be developed and tested independently ---
2. **Fault Tolerance**: Network continues operating even with node failures
3. **Consistency**: Strong consistency for database operations, eventual consistency for discovery
4. **Security**: Defense in depth with multiple security layers
5. **Performance**: Optimized for common operations with caching and connection pooling
## Codebase Structure ## Codebase Structure
``` ```
network/ network/
├── cmd/ # Executables ├── cmd/ # Executables
│ ├── node/ # Network node (bootstrap via flag/auto) │ ├── node/ # Network node (full participant)
│ │ ├── main.go # Entrypoint │ │ └── main.go # Node entrypoint
│ └── configmap.go # Centralized flags/env → config mapping (flags > env > defaults) │ └── cli/ # Command-line interface
│ └── cli/main.go # Command-line interface │ └── main.go # CLI entrypoint
├── pkg/ # Core packages ├── pkg/ # Core packages
│ ├── client/ # Client API and implementations │ ├── client/ # Lightweight client API
│ │ ├── client.go # Main client (now slimmed) │ ├── node/ # Full node implementation
│ │ ├── connect_bootstrap.go # Bootstrap helpers │ ├── config/ # Centralized configuration management
│ │ ├── discovery_aggressive.go # Generic aggressive discovery │ ├── database/ # RQLite integration
│ │ ├── monitoring.go # Connection monitoring │ ├── storage/ # Distributed key-value storage
│ │ ├── pubsub_bridge.go # PubSub adapter bridge │ ├── pubsub/ # Pub/Sub messaging
│ │ ├── implementations.go # Database, storage, network implementations │ ├── discovery/ # Peer discovery (node only)
│ │ └── interface.go # Public API interfaces │ ├── logging/ # Structured and colored logging
│ ├── config/ # Configuration management │ └── anyoneproxy/ # Optional SOCKS5 proxy support
│ │ └── config.go # Node and client configuration ├── configs/ # YAML configuration files
│ ├── constants/ # System constants │ ├── node.yaml # Node config
│ │ └── bootstrap.go # Bootstrap node constants │ └── bootstrap.yaml # Bootstrap config (legacy, now unified)
│ ├── database/ # Database layer ├── scripts/ # Install and utility scripts
│ │ ├── adapter.go # Database adapter interface └── data/ # Runtime data (identity, db, logs)
│ │ └── rqlite.go # RQLite implementation
│ ├── discovery/ # Peer discovery
│ │ └── discovery.go # DHT-based peer discovery
│ ├── node/ # Node implementation
│ │ └── node.go # Network node logic
│ ├── pubsub/ # Publish/Subscribe messaging
│ │ ├── manager.go # Core pub/sub logic
│ │ ├── adapter.go # Client interface adapter
│ │ └── types.go # Shared types
│ └── storage/ # Distributed storage
│ ├── client.go # Storage client
│ ├── protocol.go # Storage protocol
│ ├── service.go # Service (struct/ctor/Close)
│ ├── rqlite_init.go # Schema initialization
│ ├── stream_handler.go # Stream handling
│ └── kv_ops.go # KV operation handlers
├── anchat/ # Example chat application
│ ├── cmd/cli/main.go # Chat CLI
│ └── pkg/
│ ├── chat/manager.go # Chat message management
│ └── crypto/crypto.go # End-to-end encryption
├── examples/ # Usage examples
│ └── basic_usage.go # Basic API usage
├── configs/ # Configuration files
│ ├── bootstrap.yaml # Bootstrap node config
│ └── node.yaml # Regular node config
├── data/ # Runtime data
│ ├── bootstrap/ # Bootstrap node data
│ └── node/ # Regular node data
└── scripts/ # Utility scripts
└── test-multinode.sh # Multi-node testing
``` ```
---
## Key Components ## Key Components
### 1. Network Client (`pkg/client/`) ### 1. **Network Client (`pkg/client/`)**
- **Role:** Lightweight P2P participant for apps and CLI.
- **Features:** Connects only to bootstrap peers, no peer discovery, provides Database, Storage, PubSub, and NetworkInfo interfaces.
- **Isolation:** Namespaced per application.
The main entry point for applications to interact with the network. ### 2. **Node (`pkg/node/`)**
- **Role:** Full P2P participant, runs core services (RQLite, storage, pubsub), handles peer discovery and network management.
- **Features:** Peer discovery, service registration, connection monitoring, and data replication.
**Core Interfaces:** ### 3. **Configuration (`pkg/config/`)**
- **Centralized:** All config is managed via YAML files, with CLI flags and environment variables overriding as needed.
- **Unified:** Node and client configs share structure; bootstrap is just a node with no join address.
- `NetworkClient`: Main client interface ### 4. **Database Layer (`pkg/database/`)**
- `DatabaseClient`: SQL database operations - **RQLite:** Distributed SQLite with Raft consensus, automatic leader election, and failover.
- `StorageClient`: Key-value storage operations - **Client API:** SQL queries, transactions, schema management.
- `PubSubClient`: Publish/subscribe messaging
- `NetworkInfo`: Network status and peer information
**Key Features:** ### 5. **Storage System (`pkg/storage/`)**
- **Distributed KV:** Namespace-isolated, CRUD operations, prefix queries, replication.
- Automatic connection management with retry logic ### 6. **Pub/Sub System (`pkg/pubsub/`)**
- Namespace isolation per application - **Messaging:** Topic-based, real-time delivery, automatic subscription management, namespace isolation.
- Health monitoring and status reporting
- Graceful shutdown and cleanup
### 2. Peer Discovery (`pkg/discovery/`) ### 7. **Discovery (`pkg/discovery/`)**
- **Node Only:** Handles peer discovery via peerstore and peer exchange. No DHT/Kademlia in client.
Handles automatic peer discovery and network topology management. ---
**Discovery Strategies:** ## Configuration System
- **DHT-based**: Uses Kademlia DHT for efficient peer routing - **Primary Source:** YAML files (`configs/node.yaml`)
- **Peer Exchange**: Learns about new peers from existing connections - **Overrides:** CLI flags > Environment variables > YAML > Code defaults
- **Bootstrap**: Connects to known bootstrap nodes for network entry - **Examples:**
- `data_dir`, `key_file`, `listen_addresses`, `solana_wallet`
- `rqlite_port`, `rqlite_raft_port`, `rqlite_join_address`
- `bootstrap_peers`, `discovery_interval`
- Logging: `level`, `file`
**Configuration:** **Client Configuration Precedence:**
1. Explicit in `ClientConfig`
2. Environment variables (`RQLITE_NODES`, `BOOTSTRAP_PEERS`)
3. Library defaults (from config package)
- Discovery interval (default: 10 seconds) ---
- Maximum concurrent connections (default: 3)
- Connection timeout and retry policies
### 3. Pub/Sub System (`pkg/pubsub/`) ## Node vs Client Roles
Provides reliable, topic-based messaging with ordering guarantees. ### **Node (`pkg/node/`)**
- Runs full network services (RQLite, storage, pubsub)
- Handles peer discovery and network topology
- Participates in consensus and replication
- Manages service lifecycle and monitoring
**Features:** ### **Client (`pkg/client/`)**
- Lightweight participant (does not run services)
- Connects only to known bootstrap peers
- No peer discovery or DHT
- Consumes network services via API (Database, Storage, PubSub, NetworkInfo)
- Used by CLI and application integrations
- Topic-based routing with wildcard support ---
- Namespace isolation per application
- Automatic subscription management
- Message deduplication and ordering
**Message Flow:** ## Network Protocol & Data Flow
1. Client subscribes to topic with handler ### **Connection Establishment**
2. Publisher sends message to topic - **Node:** Connects to bootstrap peers, discovers additional peers, registers services.
3. Network propagates message to all subscribers - **Client:** Connects only to bootstrap peers.
4. Handlers process messages asynchronously
### 4. Database Layer (`pkg/database/`) ### **Message Types**
- **Control:** Node status, heartbeats, topology updates
- **Database:** SQL queries, transactions, schema ops
- **Storage:** KV operations, replication
- **PubSub:** Topic subscriptions, published messages
Distributed SQL database built on RQLite (Raft-based SQLite). ### **Security Model**
- **Transport:** Noise/TLS encryption for all connections
- **Authentication:** Peer identity verification
- **Isolation:** Namespace-based access control
**Capabilities:** ### **Data Flow**
- **Database:** Client → DatabaseClient → RQLite Leader → Raft Consensus → All Nodes
- **Storage:** Client → StorageClient → Node → Replication
- **PubSub:** Client → PubSubClient → Node → Topic Router → Subscribers
- ACID transactions with strong consistency ---
- Automatic leader election and failover
- Multi-node replication with conflict resolution
- Schema management and migrations
**Query Types:**
- Read operations: Served from any node
- Write operations: Routed to leader node
- Transactions: Atomic across multiple statements
### 5. Storage System (`pkg/storage/`)
Distributed key-value store with eventual consistency.
**Operations:**
- `Put(key, value)`: Store value with key
- `Get(key)`: Retrieve value by key
- `Delete(key)`: Remove key-value pair
- `List(prefix, limit)`: Enumerate keys with prefix
- `Exists(key)`: Check key existence
## Network Protocol
### Connection Establishment
1. **Bootstrap Connection**: New nodes connect to bootstrap peers
2. **DHT Bootstrap**: Initialize Kademlia DHT for routing
3. **Peer Discovery**: Discover additional peers through DHT
4. **Service Registration**: Register available services (database, storage, pubsub)
### Message Types
- **Control Messages**: Node status, heartbeats, topology updates
- **Database Messages**: SQL queries, transactions, schema operations
- **Storage Messages**: Key-value operations, replication data
- **PubSub Messages**: Topic subscriptions, published content
### Security Model
- **Transport Security**: All connections use TLS/Noise encryption
- **Peer Authentication**: Cryptographic peer identity verification
- **Message Integrity**: Hash-based message authentication codes
- **Namespace Isolation**: Application-level access control
## Data Flow
### Database Operation Flow
```
Client App → DatabaseClient → RQLite Leader → Raft Consensus → All Nodes
↑ ↓
└─────────────────── Query Result ←─────────────────────────────┘
```
### Storage Operation Flow
```
Client App → StorageClient → DHT Routing → Target Nodes → Replication
↑ ↓
└─────────────── Response ←─────────────────────────────────┘
```
### PubSub Message Flow
```
Publisher → PubSub Manager → Topic Router → All Subscribers → Message Handlers
```
## Build & Development ## Build & Development
### Prerequisites ### **Prerequisites**
- Go 1.21+
- Go 1.19+ - RQLite
- Make
- Git - Git
- Make
### Build Commands ### **Build Commands**
```bash ```bash
# Build all executables make build # Build all executables
make build make test # Run tests
make run-node # Start node (auto-detects bootstrap vs regular)
# Run tests
make test
# Clean build artifacts
make clean
# Start network node (auto-detects bootstrap vs regular)
make run-node
# Start additional node
make run-node
``` ```
### Development Workflow ### **Development Workflow**
- Use `make run-node` for local development.
- Edit YAML configs for node settings.
- Use CLI for network operations and testing.
1. **Local Development**: Use `make run-node` (auto-detects bootstrap vs regular) ---
2. **Testing**: Run `make test` for unit tests
3. **Integration Testing**: Use `scripts/test-multinode.sh`
4. **Configuration**: Edit `configs/*.yaml` files
### Configuration Files
#### Bootstrap Node (`configs/bootstrap.yaml`)
```yaml
node:
data_dir: "./data/bootstrap"
listen_addresses:
- "/ip4/0.0.0.0/tcp/4001"
- "/ip4/0.0.0.0/udp/4001/quic"
database:
rqlite_port: 5001
rqlite_raft_port: 7001
```
#### Regular Node (`configs/node.yaml`)
```yaml
node:
data_dir: "./data/node"
listen_addresses:
- "/ip4/0.0.0.0/tcp/4001"
discovery:
bootstrap_peers:
- "/ip4/127.0.0.1/tcp/4001/p2p/{BOOTSTRAP_PEER_ID}"
discovery_interval: "10s"
database:
rqlite_port: 5001
rqlite_raft_port: 7001
rqlite_join_address: "localhost:7001"
```
## API Reference ## API Reference
### Client Creation ### **Client Creation**
```go ```go
import "git.debros.io/DeBros/network/pkg/client" import "git.debros.io/DeBros/network/pkg/client"
config := client.DefaultClientConfig("my-app") config := client.DefaultClientConfig("my-app")
config.BootstrapPeers = []string{"/ip4/127.0.0.1/tcp/4001/p2p/{PEER_ID}"} config.BootstrapPeers = []string{"/ip4/127.0.0.1/tcp/4001/p2p/{PEER_ID}"}
client, err := client.NewClient(config) client, err := client.NewClient(config)
if err != nil {
log.Fatal(err)
}
err = client.Connect() err = client.Connect()
if err != nil {
log.Fatal(err)
}
defer client.Disconnect() defer client.Disconnect()
``` ```
### Centralized Defaults & Endpoint Precedence ### **Database Operations**
- Defaults are centralized in the client package:
- `client.DefaultBootstrapPeers()` exposes default multiaddrs from `pkg/constants/bootstrap.go`.
- `client.DefaultDatabaseEndpoints()` derives HTTP DB endpoints from bootstrap peers (default port 5001 or `RQLITE_PORT`).
- `ClientConfig` now includes `DatabaseEndpoints []string` to explicitly set DB URLs.
- Resolution order used by the database client:
1. `ClientConfig.DatabaseEndpoints`
2. `RQLITE_NODES` environment variable (comma/space separated)
3. `client.DefaultDatabaseEndpoints()`
- Endpoints are normalized to include scheme and port; duplicates are removed.
Example:
```go ```go
cfg := client.DefaultClientConfig("app") result, err := client.Database().Query(ctx, "SELECT * FROM users")
cfg.BootstrapPeers = client.DefaultBootstrapPeers() err := client.Database().CreateTable(ctx, "CREATE TABLE ...")
// Optionally pin DB endpoints
cfg.DatabaseEndpoints = []string{"http://db1:5001","db2:5001"}
cli, _ := client.NewClient(cfg)
_ = cli.Connect()
``` ```
### Database Operations ### **Storage Operations**
```go ```go
// Create table err := client.Storage().Put(ctx, "key", []byte("value"))
err := client.Database().CreateTable(ctx, ` data, err := client.Storage().Get(ctx, "key")
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE
)
`)
// Insert data
result, err := client.Database().Query(ctx,
"INSERT INTO users (name, email) VALUES (?, ?)",
"Alice", "alice@example.com")
// Query data
result, err := client.Database().Query(ctx,
"SELECT id, name, email FROM users WHERE name = ?", "Alice")
``` ```
### Storage Operations ### **PubSub Operations**
```go ```go
// Store data err := client.PubSub().Subscribe(ctx, "topic", handler)
err := client.Storage().Put(ctx, "user:123", []byte(`{"name":"Alice"}`)) err := client.PubSub().Publish(ctx, "topic", []byte("msg"))
// Retrieve data
data, err := client.Storage().Get(ctx, "user:123")
// List keys
keys, err := client.Storage().List(ctx, "user:", 10)
// Check existence
exists, err := client.Storage().Exists(ctx, "user:123")
``` ```
### PubSub Operations ### **Network Information**
```go ```go
// Subscribe to messages
handler := func(topic string, data []byte) error {
fmt.Printf("Received on %s: %s\n", topic, string(data))
return nil
}
err := client.PubSub().Subscribe(ctx, "notifications", handler)
// Publish message
err := client.PubSub().Publish(ctx, "notifications", []byte("Hello, World!"))
// List subscribed topics
topics, err := client.PubSub().ListTopics(ctx)
```
### Network Information
```go
// Get network status
status, err := client.Network().GetStatus(ctx) status, err := client.Network().GetStatus(ctx)
fmt.Printf("Node ID: %s, Peers: %d\n", status.NodeID, status.PeerCount)
// Get connected peers
peers, err := client.Network().GetPeers(ctx) peers, err := client.Network().GetPeers(ctx)
for _, peer := range peers {
fmt.Printf("Peer: %s, Connected: %v\n", peer.ID, peer.Connected)
}
// Connect to specific peer
err := client.Network().ConnectToPeer(ctx, "/ip4/192.168.1.100/tcp/4001/p2p/{PEER_ID}")
``` ```
---
## Troubleshooting ## Troubleshooting
### Common Issues ### **Common Issues**
- **Bootstrap Connection Failed:** Check peer ID, port, firewall, and node status.
- **Database Timeout:** Ensure RQLite ports are open, leader election is complete, and join address is correct.
- **Message Delivery Failures:** Verify topic names, subscription status, and network connectivity.
- **High Memory Usage:** Unsubscribe from topics when done, monitor connection pool size.
#### 1. Bootstrap Connection Failed ### **Debugging**
- Enable debug logging: `export LOG_LEVEL=debug`
**Symptoms**: `Failed to connect to bootstrap peer` - Check service logs: `sudo journalctl -u debros-node.service -f`
**Solutions**: - Use CLI for health and peer checks: `./bin/network-cli health`, `./bin/network-cli peers`
- Verify bootstrap node is running and accessible
- Check firewall settings and port availability
- Validate peer ID in bootstrap address
#### 2. Database Operations Timeout
**Symptoms**: `Query timeout` or `No RQLite connection available`
**Solutions**:
- Ensure RQLite ports are not blocked
- Check if leader election has completed
- Verify cluster join configuration
#### 3. Message Delivery Failures
**Symptoms**: Messages not received by subscribers
**Solutions**:
- Verify topic names match exactly
- Check subscription is active before publishing
- Ensure network connectivity between peers
#### 4. High Memory Usage
**Symptoms**: Memory usage grows continuously
**Solutions**:
- Check for subscription leaks (unsubscribe when done)
- Monitor connection pool size
- Review message retention policies
### Debug Mode
Enable debug logging by setting environment variable:
```bash
export LOG_LEVEL=debug
```
### Health Checks
```go
health, err := client.Health()
if health.Status != "healthy" {
log.Printf("Unhealthy: %+v", health.Checks)
}
```
### Network Diagnostics
```bash
# Check node connectivity
./bin/network-cli peers
# Verify database status
./bin/network-cli query "SELECT 1"
# Test pub/sub
./bin/network-cli pubsub publish test "hello"
./bin/network-cli pubsub subscribe test 10s
```
--- ---
## Example Application: Anchat ## Example Application: Anchat
The `anchat/` directory contains a complete example application demonstrating how to build a decentralized chat system using the DeBros network. It showcases: The `anchat/` directory contains a full-featured decentralized chat app built on DeBros Network. Features include:
- Solana wallet integration
- User registration with Solana wallet integration
- End-to-end encrypted messaging - End-to-end encrypted messaging
- IRC-style chat rooms - Real-time pub/sub chat rooms
- Real-time message delivery - Persistent history
- Persistent chat history
This serves as both a practical example and a reference implementation for building applications on the DeBros network platform.
--- ---
_This document provides comprehensive context for AI systems to understand the DeBros Network Cluster project architecture, implementation details, and usage patterns._ _This document provides a modern, accurate context for understanding the DeBros Network Cluster architecture, configuration, and usage patterns. All details reflect the current codebase and best practices._

805
README.md
View File

@ -1,323 +1,180 @@
# Network - Distributed P2P Database System v0.19.0-beta # DeBros Network - Distributed P2P Database System
A distributed peer-to-peer network built with Go and LibP2P, providing decentralized database capabilities with RQLite consensus and replication. A robust, decentralized peer-to-peer network built in Go, providing distributed SQL database, key-value storage, pub/sub messaging, and resilient peer management. Designed for applications needing reliable, scalable, and secure data sharing without centralized infrastructure.
---
## Table of Contents ## Table of Contents
- [Features](#features) - [Features](#features)
- [Architecture Overview](#architecture-overview)
- [System Requirements](#system-requirements) - [System Requirements](#system-requirements)
- [Software Dependencies](#software-dependencies)
- [Installation](#installation)
- [macOS](#macos)
- [Ubuntu/Debian](#ubuntudebian)
- [Windows](#windows)
- [Hardware Requirements](#hardware-requirements)
- [Network Ports](#network-ports)
- [Quick Start](#quick-start) - [Quick Start](#quick-start)
- [1. Clone and Setup Environment](#1-clone-and-setup-environment) - [Deployment & Installation](#deployment--installation)
- [2. Generate Bootstrap Identity (Development Only)](#2-generate-bootstrap-identity-development-only)
- [3. Build the Project](#3-build-the-project)
- [4. Start the Network](#4-start-the-network)
- [5. Test with CLI](#5-test-with-cli)
- [Deployment](#deployment)
- [Production Installation Script](#production-installation-script)
- [One-Command Installation](#one-command-installation)
- [What the Script Does](#what-the-script-does)
- [Directory Structure](#directory-structure)
- [Node Setup](#node-setup)
- [Service Management](#service-management)
- [Configuration Files](#configuration-files)
- [Security Features](#security-features)
- [Network Discovery](#network-discovery)
- [Updates and Maintenance](#updates-and-maintenance)
- [Monitoring and Troubleshooting](#monitoring-and-troubleshooting)
- [Configuration](#configuration) - [Configuration](#configuration)
- [Bootstrap and Ports (via flags)](#bootstrap-and-ports-via-flags) - [CLI Usage](#cli-usage)
- [CLI Commands](#cli-commands)
- [Network Operations](#network-operations)
- [Storage Operations](#storage-operations)
- [Database Operations](#database-operations)
- [Pub/Sub Messaging](#pubsub-messaging)
- [CLI Options](#cli-options)
- [Development](#development) - [Development](#development)
- [Project Structure](#project-structure)
- [Building and Testing](#building-and-testing)
- [Development Workflow](#development-workflow)
- [Environment Setup](#environment-setup)
- [Configuration System](#configuration-system)
- [Client Library Usage](#client-library-usage)
- [Troubleshooting](#troubleshooting) - [Troubleshooting](#troubleshooting)
- [Common Issues](#common-issues)
- [Debug Commands](#debug-commands)
- [Environment-specific Issues](#environment-specific-issues)
- [Configuration Validation](#configuration-validation)
- [Logs and Data](#logs-and-data)
- [License](#license) - [License](#license)
---
## Features ## Features
- **Peer-to-Peer Networking**: Built on LibP2P for robust P2P communication - **Distributed SQL Database:** RQLite-backed, Raft-consensus, ACID transactions, automatic failover.
- **Distributed Database**: RQLite-based distributed SQLite with Raft consensus - **Key-Value Storage:** Namespaced, replicated, CRUD operations, prefix queries.
- **Automatic Peer Discovery**: Nodes help new peers join the network - **Pub/Sub Messaging:** Topic-based, real-time, namespaced, automatic cleanup.
- **CLI Tool**: Command-line interface for network operations and testing - **Peer Discovery & Management:** Nodes discover peers, bootstrap support, health monitoring.
- **Client Library**: Simple Go API for applications to interact with the network - **Application Isolation:** Namespace-based multi-tenancy, per-app config.
- **Application Isolation**: Namespaced storage and messaging per application - **Secure by Default:** Noise/TLS transport, peer identity, systemd hardening.
- **Simple Client API:** Lightweight Go client for apps and CLI tools.
---
## Architecture Overview
```
┌─────────────────────────────────────────────────────────────┐
│ DeBros Network Cluster │
├─────────────────────────────────────────────────────────────┤
│ Application Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌────────────────────────┐ │
│ │ Anchat │ │ Custom App │ │ CLI Tools │ │
│ └─────────────┘ └─────────────┘ └────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Client API │
│ ┌─────────────┐ ┌─────────────┐ ┌────────────────────────┐ │
│ │ Database │ │ Storage │ │ PubSub │ │
│ │ Client │ │ Client │ │ Client │ │
│ └─────────────┘ └─────────────┘ └────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Network Node Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌────────────────────────┐ │
│ │ Discovery │ │ PubSub │ │ Database │ │
│ │ Manager │ │ Manager │ │ (RQLite) │ │
│ └─────────────┘ └─────────────┘ └────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Transport Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌────────────────────────┐ │
│ │ LibP2P │ │ Noise/TLS │ │ RQLite │ │
│ │ Host │ │ Encryption │ │ Database │ │
│ └─────────────┘ └─────────────┘ └────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
- **Node:** Full P2P participant, runs services, handles peer discovery, database, storage, pubsub.
- **Client:** Lightweight, connects only to bootstrap peers, consumes services, no peer discovery.
---
## System Requirements ## System Requirements
### Software Dependencies ### Software
- **Go**: Version 1.21 or later - **Go:** 1.21+ (recommended)
- **RQLite**: Distributed SQLite database - **RQLite:** 8.x (distributed SQLite)
- **Git**: For cloning the repository - **Git:** For source management
- **Make**: For build automation (optional but recommended) - **Make:** For build automation (recommended)
### Installation ### Hardware
#### macOS - **Minimum:** 2 CPU cores, 4GB RAM, 10GB disk, stable internet
- **Recommended:** 4+ cores, 8GB+ RAM, 50GB+ SSD, low-latency network
```bash
# Install Homebrew if you don't have it
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Install dependencies
brew install go rqlite git make
# Verify installation
go version # Should show Go 1.21+
rqlited --version
```
#### Ubuntu/Debian
```bash
# Install Go (latest version)
sudo rm -rf /usr/local/go
wget https://go.dev/dl/go1.21.6.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.21.6.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
# Install RQLite
wget https://github.com/rqlite/rqlite/releases/download/v8.43.0/rqlite-v8.43.0-linux-amd64.tar.gz
tar -xzf rqlite-v8.43.0-linux-amd64.tar.gz
sudo mv rqlite-v8.43.0-linux-amd64/rqlited /usr/local/bin/
# Install other dependencies
sudo apt update
sudo apt install git make
# Verify installation
go version
rqlited --version
```
#### Windows
```powershell
# Install Go from https://golang.org/dl/
# Install Git from https://git-scm.com/download/win
# Install RQLite from https://github.com/rqlite/rqlite/releases
# Or use Chocolatey
choco install golang git make
# Download RQLite manually from releases page
```
### Hardware Requirements
**Minimum:**
- CPU: 2 cores
- RAM: 4GB
- Storage: 10GB free space
- Network: Stable internet connection
**Recommended:**
- CPU: 4+ cores
- RAM: 8GB+
- Storage: 50GB+ SSD
- Network: Low-latency internet connection
### Network Ports ### Network Ports
The system uses these ports by default: - **4001:** LibP2P P2P communication
- **5001:** RQLite HTTP API
- **7001:** RQLite Raft consensus
- **4001**: LibP2P communication ---
- **5001**: RQLite HTTP API
- **7001**: RQLite Raft consensus
Ensure these ports are available or configure firewall rules accordingly. The system will also use +1 for each extra node started. For example 4002, 5002, 7002
## Quick Start ## Quick Start
### 1. Clone and Setup Environment ### 1. Clone and Setup
```bash ```bash
# Clone the repository
git clone https://git.debros.io/DeBros/network.git git clone https://git.debros.io/DeBros/network.git
cd network cd network
``` ```
### 2. Build the Project ### 2. Build All Executables
```bash ```bash
# Build all network executables
make build make build
``` ```
```bash ### 3. Start a Bootstrap Node
# Build all network executables
make build
```
### 3. Start the Network
**Terminal 1 - Bootstrap Node:**
```bash ```bash
# Start the bootstrap node (LibP2P 4001, RQLite 5001/7001)
make run-node make run-node
# Or manually:
go run ./cmd/node -data ./data/bootstrap -p2p-port 4001 -rqlite-http-port 5001 -rqlite-raft-port 7001
``` ```
**Terminal 2 - Regular Node:** ### 4. Start Additional Nodes
```bash ```bash
# Start a regular node and join the cluster using the bootstrap node's RQLite HTTP address go run ./cmd/node -id node2 -data ./data/node2 -rqlite-http-port 5002 -rqlite-raft-port 7002 -p2p-port 4002 --disable-anonrc
go run ./cmd/node --id node2 --data ./data/node2 --p2p-port 4002 --rqlite-http-port 5002 --rqlite-raft-port 7002 --rqlite-join-address http://127.0.0.1:5001 --disable-anonrc
```
**Terminal 3 - Another Node (optional):**
```bash
go run ./cmd/node --id node3 --data ./data/node3 --p2p-port 4003 --rqlite-http-port 5003 --rqlite-raft-port 7003 --rqlite-join-address http://127.0.0.1:5001 --disable-anonrc
``` ```
### 5. Test with CLI ### 5. Test with CLI
```bash ```bash
# Check current bootstrap configuration
make show-bootstrap
# Check network health
./bin/network-cli health ./bin/network-cli health
./bin/network-cli peers
# Test storage operations
./bin/network-cli storage put test-key "Hello Network" ./bin/network-cli storage put test-key "Hello Network"
./bin/network-cli storage get test-key ./bin/network-cli storage get test-key
./bin/network-cli pubsub publish notifications "Hello World"
# List connected peers ./bin/network-cli pubsub subscribe notifications 10s
./bin/network-cli peers
``` ```
## Deployment ---
### Production Installation Script ## Deployment & Installation
For production deployments on Linux servers, we provide an automated installation script that handles all dependencies, configuration, and service setup. ### Automated Production Install
#### One-Command Installation Run the install script for a secure, production-ready setup:
```bash ```bash
# Download and run the installation script
curl -sSL https://git.debros.io/DeBros/network/raw/branch/main/scripts/install-debros-network.sh | sudo bash curl -sSL https://git.debros.io/DeBros/network/raw/branch/main/scripts/install-debros-network.sh | sudo bash
``` ```
#### What the Script Does **What the Script Does:**
- Detects OS, installs Go, RQLite, dependencies
1. **System Setup**: - Creates `debros` system user, secure directory structure
- Generates LibP2P identity keys
- Detects OS (Ubuntu/Debian/CentOS/RHEL/Fedora) - Clones source, builds binaries
- Installs Go 1.21+ with architecture detection - Sets up systemd service (`debros-node`)
- Installs system dependencies (git, make, build tools) - Configures firewall (UFW) for required ports
- Checks port availability (4001, 5001, 7001) - Generates YAML config in `/opt/debros/configs/node.yaml`
2. **Configuration Wizard**:
- Solana wallet address for node operator rewards
- Installation directory (default: `/opt/debros`)
- Automatic firewall configuration (UFW)
3. **Secure Installation**:
- Creates dedicated `debros` system user
- Sets up secure directory structure with proper permissions
- Generates LibP2P identity keys with secure storage
- Clones source code and builds binaries
4. **Service Management**:
- Creates systemd service with security hardening
- Enables automatic startup and restart on failure
- Configures structured logging to systemd journal
#### Directory Structure
The script creates a production-ready directory structure:
**Directory Structure:**
``` ```
/opt/debros/ /opt/debros/
├── bin/ # Compiled binaries ├── bin/ # Binaries
│ ├── bootstrap # Bootstrap node executable ├── configs/ # YAML configs
│ ├── node # Node executable ├── keys/ # Identity keys
│ └── cli # CLI tools ├── data/ # RQLite DB, storage
├── configs/ # Configuration files ├── logs/ # Node logs
│ └── node.yaml # Node configuration ├── src/ # Source code
├── keys/ # Identity keys (secure 700 permissions)
│ └── node/
│ └── identity.key
├── data/ # Runtime data
│ └── node/
│ ├── rqlite/ # RQLite database files
│ └── storage/ # P2P storage data
├── logs/ # Application logs
│ └── node.log
└── src/ # Source code (for updates)
``` ```
#### Node Setup **Service Management:**
The installation script sets up a **network node**:
- Runs on ports: 4001 (P2P), 5001 (RQLite), 7001 (Raft)
- Participates in DHT for peer discovery and data replication
- Can be deployed on any server or VPS
For setup, please run these commands with adequate permissions:
- Ensure you have elevated privileges or run as a user with the necessary permissions for server setup.
- Follow the installation steps correctly to ensure a smooth deployment.
#### Service Management
After installation, manage your node with these commands:
```bash ```bash
# Check service status
sudo systemctl status debros-node sudo systemctl status debros-node
# Start/stop/restart service
sudo systemctl start debros-node sudo systemctl start debros-node
sudo systemctl stop debros-node sudo systemctl stop debros-node
sudo systemctl restart debros-node sudo systemctl restart debros-node
# View real-time logs
sudo journalctl -u debros-node.service -f sudo journalctl -u debros-node.service -f
# Enable/disable auto-start
sudo systemctl enable debros-node
sudo systemctl disable debros-node
# Use CLI tools
/opt/debros/bin/network-cli health
/opt/debros/bin/network-cli peers
/opt/debros/bin/network-cli storage put key value
``` ```
#### Configuration Files ---
The script generates YAML configuration files: ## Configuration
**Node Configuration (`/opt/debros/configs/node.yaml`)**: ### YAML Config Example (`/opt/debros/configs/node.yaml`)
```yaml ```yaml
node: node:
@ -336,200 +193,21 @@ logging:
file: "/opt/debros/logs/node.log" file: "/opt/debros/logs/node.log"
``` ```
#### Security Features ### Flags & Environment Variables
The installation script implements production security best practices: - **Flags**: Override config at startup (`--data`, `--p2p-port`, `--rqlite-http-port`, etc.)
- **Env Vars**: Override config and flags (`NODE_ID`, `RQLITE_PORT`, `BOOTSTRAP_PEERS`, etc.)
- **Precedence**: Flags > Env Vars > YAML > Defaults
- **Dedicated User**: Runs as `debros` system user (not root) ### Bootstrap & Database Endpoints
- **File Permissions**: Key files have 600 permissions, directories have proper ownership
- **Systemd Security**: Service runs with `NoNewPrivileges`, `PrivateTmp`, `ProtectSystem=strict`
- **Firewall**: Automatic UFW configuration for required ports
- **Network Isolation**: Proper port management to avoid conflicts
#### Network Discovery - **Bootstrap peers**: Set in config or via `BOOTSTRAP_PEERS` env var.
- **Database endpoints**: Set in config or via `RQLITE_NODES` env var.
- **Development mode**: Use `NETWORK_DEV_LOCAL=1` for localhost defaults.
- **Network Peers**: Hardcoded in the application for automatic connection ---
- **DHT Discovery**: Nodes automatically join Kademlia DHT for peer discovery
- **Peer Exchange**: Connected nodes share information about other peers
- **No Manual Configuration**: Nodes connect automatically without user intervention
#### Updates and Maintenance ## CLI Usage
```bash
# Update to latest version (re-run the installation script)
curl -sSL https://git.debros.io/DeBros/network/raw/branch/main/scripts/install-debros-network.sh | bash
# Manual source update
cd /opt/debros/src
sudo -u debros git pull
sudo -u debros make build
sudo cp bin/* /opt/debros/bin/
sudo systemctl restart debros-node
# Backup configuration and keys
sudo cp -r /opt/debros/configs /backup/
sudo cp -r /opt/debros/keys /backup/
```
#### Monitoring and Troubleshooting
```bash
# Check if ports are open
sudo netstat -tuln | grep -E "(4001|5001|7001)"
# Check service logs
sudo journalctl -u debros-node.service --since "1 hour ago"
# Check network connectivity
/opt/debros/bin/network-cli health
/opt/debros/bin/network-cli peers
# Check disk usage
du -sh /opt/debros/data/*
# Process information
ps aux | grep debros
```
For more advanced configuration options and development setup, see the sections below.
## Configuration
### Node Startup Flags
- **Bootstrap node**: Just run `make run-node` (auto-selects data dir and identity)
- **Regular node**: Use `--id`, `--data`, `--p2p-port`, `--rqlite-http-port`, `--rqlite-raft-port`, and `--rqlite-join-address <http://bootstrap_host:5001>`
- **Disable anonymous routing**: `--disable-anonrc` (optional)
- **Development localhost defaults**: Use `--disable-anonrc` for local-only testing; 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.
### Environment Variables
Precedence: CLI flags > Environment variables > Code defaults. Set any of the following in your shell or `.env`:
- NODE_ID: custom node identifier (e.g. "node2")
- NODE_TYPE: "bootstrap" or "node"
- NODE_LISTEN_ADDRESSES: comma-separated multiaddrs (e.g. "/ip4/0.0.0.0/tcp/4001,/ip4/0.0.0.0/udp/4001/quic")
- DATA_DIR: node data directory (default `./data`)
- MAX_CONNECTIONS: max peer connections (int)
- DB_DATA_DIR: database data directory (default `./data/db`)
- REPLICATION_FACTOR: int (default 3)
- SHARD_COUNT: int (default 16)
- MAX_DB_SIZE: e.g. "1g", "512m", or bytes
- BACKUP_INTERVAL: Go duration (e.g. "24h")
- RQLITE_HTTP_PORT: int (default 5001)
- RQLITE_RAFT_PORT: int (default 7001)
- 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/<ID>`)
- ADVERTISE_MODE: "auto" | "localhost" | "ip"
- BOOTSTRAP_PEERS: comma-separated multiaddrs for bootstrap peers
- ENABLE_MDNS: true/false
- ENABLE_DHT: true/false
- DHT_PREFIX: string (default `/network/kad/1.0.0`)
- DISCOVERY_INTERVAL: duration (e.g. "5m")
- ENABLE_TLS: true/false
- PRIVATE_KEY_FILE: path
- CERT_FILE: path
- AUTH_ENABLED: true/false
- LOG_LEVEL: "debug" | "info" | "warn" | "error"
- LOG_FORMAT: "json" | "console"
- LOG_OUTPUT_FILE: path (empty = stdout)
### Centralized Flag/Env Mapping
Flag and environment variable mapping is centralized in `cmd/node/configmap.go` via `MapFlagsAndEnvToConfig`.
This enforces precedence (flags > env > defaults) consistently across the node startup path.
### Centralized Defaults: Bootstrap & Database
- The network library is the single source of truth for defaults.
- Bootstrap peers: `pkg/constants/bootstrap.go` exposed via `client.DefaultBootstrapPeers()`.
- Database HTTP endpoints: derived from bootstrap peers via `client.DefaultDatabaseEndpoints()`.
#### Database Endpoints Precedence
When the client connects to RQLite, endpoints are resolved with this precedence:
1. `ClientConfig.DatabaseEndpoints` (explicitly set by the app)
2. `RQLITE_NODES` environment variable (comma/space separated), e.g. `http://x:5001,http://y:5001`
3. `client.DefaultDatabaseEndpoints()` (constructed from default bootstrap peers)
Notes:
- Default DB port is 5001. Override with `RQLITE_PORT` when constructing defaults.
- Endpoints are normalized to include scheme and port; duplicates are removed.
#### Client Usage Example
```go
cfg := client.DefaultClientConfig("my-app")
// Optional: override bootstrap peers
cfg.BootstrapPeers = []string{"/ip4/127.0.0.1/tcp/4001/p2p/<PEER_ID>"}
// Optional: prefer explicit DB endpoints
cfg.DatabaseEndpoints = []string{"http://127.0.0.1:5001"}
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/<BOOTSTRAP_PEER_ID>"
# 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.
- When `NETWORK_DEV_LOCAL` is set and `LOCAL_BOOTSTRAP_MULTIADDR` is NOT set, the client attempts to auto-load the local bootstrap multiaddr (with peer ID) from `./data/bootstrap/peer.info` (or `LOCAL_BOOTSTRAP_INFO` path if provided). Only if no file is found does it fall back to `/ip4/127.0.0.1/tcp/4001`.
### Migration Guide for Apps (e.g., anchat)
- **Stop hardcoding endpoints**: Replace any hardcoded bootstrap peers and DB URLs with calls to
`client.DefaultBootstrapPeers()` and, if needed, set `ClientConfig.DatabaseEndpoints`.
- **Prefer config over env**: Set `ClientConfig.DatabaseEndpoints` in your app config. If not set,
the library will read `RQLITE_NODES` for backward compatibility.
- **Keep env compatibility**: Existing environments using `RQLITE_NODES` and `RQLITE_PORT` continue to work.
- **Minimal changes**: Most apps only need to populate `ClientConfig.DatabaseEndpoints` and/or rely on
`client.DefaultDatabaseEndpoints()`; no other code changes required.
Example migration snippet:
```go
import netclient "git.debros.io/DeBros/network/pkg/client"
cfg := netclient.DefaultClientConfig("anchat")
// Use library defaults for bootstrap peers
cfg.BootstrapPeers = netclient.DefaultBootstrapPeers()
// Prefer explicit DB endpoints (can also leave empty to use env or defaults)
cfg.DatabaseEndpoints = []string{"http://127.0.0.1:5001"}
c, err := netclient.NewClient(cfg)
if err != nil { /* handle */ }
if err := c.Connect(); err != nil { /* handle */ }
defer c.Disconnect()
```
## CLI Commands
The CLI can still accept `--bootstrap <multiaddr>` to override discovery when needed.
### Network Operations ### Network Operations
@ -568,8 +246,12 @@ The CLI can still accept `--bootstrap <multiaddr>` to override discovery when ne
--format json # Output in JSON format --format json # Output in JSON format
--timeout 30s # Set operation timeout --timeout 30s # Set operation timeout
--bootstrap <multiaddr> # Override bootstrap peer --bootstrap <multiaddr> # Override bootstrap peer
--production # Use production bootstrap peers
--disable-anonrc # Disable anonymous routing (Tor/SOCKS5)
``` ```
---
## Development ## Development
### Project Structure ### Project Structure
@ -577,249 +259,92 @@ The CLI can still accept `--bootstrap <multiaddr>` to override discovery when ne
``` ```
network/ network/
├── cmd/ ├── cmd/
│ ├── node/ # Network node (bootstrap via flag) │ ├── node/ # Network node executable
│ │ ├── main.go # Entrypoint
│ │ └── configmap.go # Centralized flags/env → config mapping
│ └── cli/ # Command-line interface │ └── cli/ # Command-line interface
├── pkg/ ├── pkg/
│ ├── client/ # Client library │ ├── client/ # Client library
│ ├── node/ # Node implementation │ ├── node/ # Node implementation
│ ├── database/ # RQLite integration │ ├── database/ # RQLite integration
│ ├── storage/ # Storage service │ ├── storage/ # Storage service
│ ├── constants/ # Bootstrap configuration │ ├── pubsub/ # Pub/Sub messaging
│ └── config/ # System configuration │ ├── config/ # Centralized config
├── scripts/ # Helper scripts (install, security, tests) │ └── discovery/ # Peer discovery (node only)
├── scripts/ # Install, test scripts
├── configs/ # YAML configs
├── bin/ # Built executables ├── bin/ # Built executables
``` ```
### Building and Testing ### Build & Test
```bash ```bash
# Build all network executables make build # Build all executables
make build make test # Run unit tests
make clean # Clean build artifacts
# Show current bootstrap configuration
make show-bootstrap
# Run node (auto-detects bootstrap vs regular based on .env)
make run-node
# Clean data directories
make clean
# Run tests
go test ./...
# Full development workflow
make dev
``` ```
### Development Workflow ### Local Multi-Node Testing
1. **Initial Setup:** ```bash
scripts/test-multinode.sh
```bash
# Copy environment templates
cp .env.example .env
# Generate consistent bootstrap identity
go run scripts/generate-bootstrap-identity.go
# Update .env files with the generated peer ID
```
2. **Build Everything:**
```bash
make build # Build network components
```
3. **Start Development Cluster:**
```bash
# Terminal 1: Bootstrap node (auto-detected)
make run-node
# Terminal 2: Regular node (auto-connects via .env)
make run-node
# Terminal 3: Test with CLI
./bin/network-cli health
./bin/network-cli peers
```
### Environment Setup
1. **Install Dependencies:**
```bash
# macOS
brew install go rqlite git make
# Ubuntu/Debian
sudo apt install golang-go git make
# Install RQLite from https://github.com/rqlite/rqlite/releases
```
2. **Verify Installation:**
```bash
go version # Should be 1.21+
rqlited --version
make --version
```
3. **Configure Environment:**
```bash
# Setup .env files
cp .env.example .env
# Generate bootstrap identity
go run scripts/generate-bootstrap-identity.go
# Update .env files with generated peer ID
```
### Configuration System
The network uses a dual configuration system:
1. **Environment Variables (.env files):** Primary configuration method
2. **Hardcoded Constants:** Fallback when .env files are not found
#### Bootstrap Configuration Priority:
1. Command line flags (if provided)
2. Environment variables from `.env` files
3. Hardcoded constants in `pkg/constants/bootstrap.go`
4. Auto-discovery from running bootstrap nodes
This ensures the network can start even without configuration files, while allowing easy customization for different environments.
## Client Library Usage
```go
package main
import (
"context"
"log"
"git.debros.io/DeBros/network/pkg/client"
)
func main() {
// Create client (bootstrap peer discovered automatically)
config := client.DefaultClientConfig("my-app")
networkClient, err := client.NewClient(config)
if err != nil {
log.Fatal(err)
}
// Connect to network
if err := networkClient.Connect(); err != nil {
log.Fatal(err)
}
defer networkClient.Disconnect()
// Use storage
ctx := context.Background()
storage := networkClient.Storage()
err = storage.Put(ctx, "user:123", []byte("user data"))
if err != nil {
log.Fatal(err)
}
data, err := storage.Get(ctx, "user:123")
if err != nil {
log.Fatal(err)
}
log.Printf("Retrieved: %s", string(data))
}
``` ```
---
## Troubleshooting ## Troubleshooting
### Common Issues ### Common Issues
**Bootstrap peer not found / Peer ID mismatch:** #### Bootstrap Connection Failed
- Generate a new bootstrap identity: `go run scripts/generate-bootstrap-identity.go` - **Symptoms:** `Failed to connect to bootstrap peer`
- Update `.env` with the new peer ID - **Solutions:** Check node is running, firewall settings, peer ID validity.
- Restart the bootstrap node: `make run-node`
- Check configuration: `make show-bootstrap`
**Nodes can't connect:** #### Database Operations Timeout
- Verify `.env` files have the correct bootstrap peer ID - **Symptoms:** `Query timeout` or `No RQLite connection available`
- Check that the bootstrap node is running: `ps aux | grep node` - **Solutions:** Ensure RQLite ports are open, leader election completed, cluster join config correct.
- Verify firewall settings and port availability (4001, 5001, 7001)
- Try restarting with clean data: `make clean && make run-node`
**Storage operations fail:** #### Message Delivery Failures
- Ensure at least one node is running and connected - **Symptoms:** Messages not received by subscribers
- Check network health: `./bin/cli health` - **Solutions:** Verify topic names, active subscriptions, network connectivity.
- Verify RQLite is properly installed: `rqlited --version`
- Check for port conflicts: `netstat -an | grep -E "(4001|5001|7001)"`
### Debug Commands #### High Memory Usage
- **Symptoms:** Memory usage grows continuously
- **Solutions:** Unsubscribe when done, monitor connection pool, review message retention.
### Debugging & Health Checks
```bash ```bash
# Check current configuration export LOG_LEVEL=debug
make show-bootstrap ./bin/network-cli health
cat .env ./bin/network-cli peers
./bin/network-cli query "SELECT 1"
# Check running processes ./bin/network-cli pubsub publish test "hello"
ps aux | grep -E "(bootstrap|node|rqlite)" ./bin/network-cli pubsub subscribe test 10s
# Check port usage
netstat -an | grep -E "(4001|5001|7001)"
# Check bootstrap peer info
cat data/bootstrap/peer.info
# Clean and restart everything
make clean
make run-node # In one terminal (auto-detects as bootstrap)
make run-node # In another terminal (runs as regular node)
``` ```
### Environment-specific Issues ### Service Logs
**Development Environment:**
- Always run `go run scripts/generate-bootstrap-identity.go` first
- Update `.env` files with the generated peer ID
- Use `make run-node` - the system auto-detects if it should run as bootstrap
**Production Environment:**
- Use stable, external bootstrap peer addresses
- Configure multiple bootstrap peers for redundancy
- Set `ENVIRONMENT=production` in `.env` files
### Configuration Validation
```bash ```bash
# Test bootstrap configuration loading sudo journalctl -u debros-node.service --since "1 hour ago"
go run -c 'package main; import "fmt"; import "network/pkg/constants"; func main() { fmt.Printf("Bootstrap peers: %v\n", constants.GetBootstrapPeers()) }'
# Verify .env file syntax
grep -E "^[A-Z_]+=.*" .env
``` ```
### Logs and Data ---
- Node logs: Console output from each running process
- Data directories: `./data/bootstrap/`, `./data/node/`, etc.
- RQLite data: `./data/<node>/rqlite/`
- Peer info: `./data/<node>/peer.info`
- Bootstrap identity: `./data/bootstrap/identity.key`
- Environment config: `./.env`
## License ## License
MIT License - see LICENSE file for details. Distributed under the MIT License. See [LICENSE](LICENSE) for details.
---
## Further Reading
- [DeBros Network Documentation](https://docs.debros.io)
- [RQLite Documentation](https://github.com/rqlite/rqlite)
- [LibP2P Documentation](https://libp2p.io)
---
_This README reflects the latest architecture, configuration, and operational practices for the DeBros Network. For questions or contributions, please open an issue or pull request._

View File

@ -1,6 +1,10 @@
#!/bin/bash #!/bin/bash
set -e # Exit on any error # DeBros Network Node Installation Script (Modern Node-Only Setup)
# Installs, configures, and manages a DeBros network node with secure defaults.
# Supports update-in-place, systemd service, and CLI management.
set -e
trap 'echo -e "${RED}An error occurred. Installation aborted.${NOCOLOR}"; exit 1' ERR trap 'echo -e "${RED}An error occurred. Installation aborted.${NOCOLOR}"; exit 1' ERR
# Color codes # Color codes
@ -11,39 +15,28 @@ BLUE='\033[38;2;2;128;175m'
YELLOW='\033[1;33m' YELLOW='\033[1;33m'
NOCOLOR='\033[0m' NOCOLOR='\033[0m'
# Default values # Defaults
INSTALL_DIR="/opt/debros" INSTALL_DIR="/opt/debros"
REPO_URL="https://git.debros.io/DeBros/network.git" REPO_URL="https://git.debros.io/DeBros/network.git"
MIN_GO_VERSION="1.19" MIN_GO_VERSION="1.21"
NODE_PORT="4001" # LibP2P port for peer-to-peer communication NODE_PORT="4001"
RQLITE_PORT="5001" # All nodes use same RQLite HTTP port to join same cluster RQLITE_PORT="5001"
RAFT_PORT="7001" # All nodes use same Raft port RAFT_PORT="7001"
UPDATE_MODE=false UPDATE_MODE=false
NON_INTERACTIVE=false NON_INTERACTIVE=false
log() { log() { echo -e "${CYAN}[$(date '+%Y-%m-%d %H:%M:%S')]${NOCOLOR} $1"; }
echo -e "${CYAN}[$(date '+%Y-%m-%d %H:%M:%S')]${NOCOLOR} $1" error() { echo -e "${RED}[ERROR]${NOCOLOR} $1"; }
} success() { echo -e "${GREEN}[SUCCESS]${NOCOLOR} $1"; }
warning() { echo -e "${YELLOW}[WARNING]${NOCOLOR} $1"; }
# Check if running non-interactively (piped from curl) # Detect non-interactive mode
if [ ! -t 0 ]; then if [ ! -t 0 ]; then
NON_INTERACTIVE=true NON_INTERACTIVE=true
log "Running in non-interactive mode" log "Running in non-interactive mode"
fi fi
error() { # Root/sudo checks
echo -e "${RED}[ERROR]${NOCOLOR} $1"
}
success() {
echo -e "${GREEN}[SUCCESS]${NOCOLOR} $1"
}
warning() {
echo -e "${YELLOW}[WARNING]${NOCOLOR} $1"
}
# Check if running as root and warn user
if [[ $EUID -eq 0 ]]; then if [[ $EUID -eq 0 ]]; then
warning "Running as root is not recommended for security reasons." warning "Running as root is not recommended for security reasons."
if [ "$NON_INTERACTIVE" != true ]; then if [ "$NON_INTERACTIVE" != true ]; then
@ -56,17 +49,15 @@ if [[ $EUID -eq 0 ]]; then
else else
log "Non-interactive mode: proceeding with root (use at your own risk)" log "Non-interactive mode: proceeding with root (use at your own risk)"
fi fi
# Create sudo alias that does nothing when running as root
alias sudo='' alias sudo=''
else else
# Check if sudo is available for non-root users
if ! command -v sudo &>/dev/null; then if ! command -v sudo &>/dev/null; then
error "sudo command not found. Please ensure you have sudo privileges." error "sudo command not found. Please ensure you have sudo privileges."
exit 1 exit 1
fi fi
fi fi
# Detect OS # Detect OS and package manager
detect_os() { detect_os() {
if [ -f /etc/os-release ]; then if [ -f /etc/os-release ]; then
. /etc/os-release . /etc/os-release
@ -76,72 +67,43 @@ detect_os() {
error "Cannot detect operating system" error "Cannot detect operating system"
exit 1 exit 1
fi fi
case $OS in case $OS in
ubuntu|debian) ubuntu|debian) PACKAGE_MANAGER="apt" ;;
PACKAGE_MANAGER="apt"
;;
centos|rhel|fedora) centos|rhel|fedora)
PACKAGE_MANAGER="yum" PACKAGE_MANAGER="yum"
if command -v dnf &> /dev/null; then if command -v dnf &> /dev/null; then PACKAGE_MANAGER="dnf"; fi
PACKAGE_MANAGER="dnf"
fi
;;
*)
error "Unsupported operating system: $OS"
exit 1
;; ;;
*) error "Unsupported operating system: $OS"; exit 1 ;;
esac esac
log "Detected OS: $OS $VERSION" log "Detected OS: $OS $VERSION"
} }
# Check if DeBros Network is already installed # Check for existing install
check_existing_installation() { check_existing_installation() {
if [ -d "$INSTALL_DIR" ] && [ -f "$INSTALL_DIR/bin/node" ]; then if [ -d "$INSTALL_DIR" ] && [ -f "$INSTALL_DIR/bin/node" ]; then
log "Found existing DeBros Network installation at $INSTALL_DIR" log "Found existing DeBros Network installation at $INSTALL_DIR"
# Check if service is running
NODE_RUNNING=false NODE_RUNNING=false
if systemctl is-active --quiet debros-node.service 2>/dev/null; then if systemctl is-active --quiet debros-node.service 2>/dev/null; then
NODE_RUNNING=true NODE_RUNNING=true
log "Node service is currently running" log "Node service is currently running"
fi fi
if [ "$NON_INTERACTIVE" = true ]; then if [ "$NON_INTERACTIVE" = true ]; then
log "Non-interactive mode: updating existing installation" log "Non-interactive mode: updating existing installation"
UPDATE_MODE=true UPDATE_MODE=true
return 0 return 0
fi fi
echo -e "${YELLOW}Existing installation detected!${NOCOLOR}" echo -e "${YELLOW}Existing installation detected!${NOCOLOR}"
echo -e "${CYAN}Options:${NOCOLOR}" echo -e "${CYAN}Options:${NOCOLOR}"
echo -e "${CYAN}1) Update existing installation${NOCOLOR}" echo -e "${CYAN}1) Update existing installation${NOCOLOR}"
echo -e "${CYAN}2) Remove and reinstall${NOCOLOR}" echo -e "${CYAN}2) Remove and reinstall${NOCOLOR}"
echo -e "${CYAN}3) Exit installer${NOCOLOR}" echo -e "${CYAN}3) Exit installer${NOCOLOR}"
while true; do while true; do
read -rp "Enter your choice (1, 2, or 3): " EXISTING_CHOICE read -rp "Enter your choice (1, 2, or 3): " EXISTING_CHOICE
case $EXISTING_CHOICE in case $EXISTING_CHOICE in
1) 1) UPDATE_MODE=true; log "Will update existing installation"; return 0 ;;
UPDATE_MODE=true 2) log "Will remove and reinstall"; remove_existing_installation; UPDATE_MODE=false; return 0 ;;
log "Will update existing installation" 3) log "Installation cancelled by user"; exit 0 ;;
return 0 *) error "Invalid choice. Please enter 1, 2, or 3." ;;
;;
2)
log "Will remove and reinstall"
remove_existing_installation
UPDATE_MODE=false
return 0
;;
3)
log "Installation cancelled by user"
exit 0
;;
*)
error "Invalid choice. Please enter 1, 2, or 3."
;;
esac esac
done done
else else
@ -150,12 +112,9 @@ check_existing_installation() {
fi fi
} }
# Remove existing installation
remove_existing_installation() { remove_existing_installation() {
log "Removing existing installation..." log "Removing existing installation..."
for service in debros-node; do
# Stop services if they exist
for service in debros-bootstrap debros-node; do
if systemctl list-unit-files | grep -q "$service.service"; then if systemctl list-unit-files | grep -q "$service.service"; then
log "Stopping $service service..." log "Stopping $service service..."
sudo systemctl stop $service.service 2>/dev/null || true sudo systemctl stop $service.service 2>/dev/null || true
@ -163,31 +122,22 @@ remove_existing_installation() {
sudo rm -f /etc/systemd/system/$service.service sudo rm -f /etc/systemd/system/$service.service
fi fi
done done
sudo systemctl daemon-reload sudo systemctl daemon-reload
# Remove installation directory
if [ -d "$INSTALL_DIR" ]; then if [ -d "$INSTALL_DIR" ]; then
sudo rm -rf "$INSTALL_DIR" sudo rm -rf "$INSTALL_DIR"
log "Removed installation directory" log "Removed installation directory"
fi fi
# Remove debros user
if id "debros" &>/dev/null; then if id "debros" &>/dev/null; then
sudo userdel debros 2>/dev/null || true sudo userdel debros 2>/dev/null || true
log "Removed debros user" log "Removed debros user"
fi fi
success "Existing installation removed" success "Existing installation removed"
} }
# Check Go installation and version
check_go_installation() { check_go_installation() {
if command -v go &> /dev/null; then if command -v go &> /dev/null; then
GO_VERSION=$(go version | awk '{print $3}' | sed 's/go//') GO_VERSION=$(go version | awk '{print $3}' | sed 's/go//')
log "Found Go version: $GO_VERSION" log "Found Go version: $GO_VERSION"
# Compare versions (simplified)
if [ "$(printf '%s\n' "$MIN_GO_VERSION" "$GO_VERSION" | sort -V | head -n1)" = "$MIN_GO_VERSION" ]; then if [ "$(printf '%s\n' "$MIN_GO_VERSION" "$GO_VERSION" | sort -V | head -n1)" = "$MIN_GO_VERSION" ]; then
success "Go version is sufficient" success "Go version is sufficient"
return 0 return 0
@ -201,65 +151,37 @@ check_go_installation() {
fi fi
} }
# Install Go
install_go() { install_go() {
log "Installing Go..." log "Installing Go..."
case $PACKAGE_MANAGER in case $PACKAGE_MANAGER in
apt) apt) sudo apt update; sudo apt install -y wget ;;
sudo apt update yum|dnf) sudo $PACKAGE_MANAGER install -y wget ;;
sudo apt install -y wget
;;
yum|dnf)
sudo $PACKAGE_MANAGER install -y wget
;;
esac esac
GO_TARBALL="go1.21.6.linux-amd64.tar.gz"
# Download and install Go
GO_TARBALL="go1.21.0.linux-amd64.tar.gz"
ARCH=$(uname -m) ARCH=$(uname -m)
if [ "$ARCH" = "aarch64" ]; then GO_TARBALL="go1.21.6.linux-arm64.tar.gz"; fi
if [ "$ARCH" = "aarch64" ]; then
GO_TARBALL="go1.21.0.linux-arm64.tar.gz"
fi
cd /tmp cd /tmp
wget -q "https://golang.org/dl/$GO_TARBALL" wget -q "https://go.dev/dl/$GO_TARBALL"
sudo rm -rf /usr/local/go sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "$GO_TARBALL" sudo tar -C /usr/local -xzf "$GO_TARBALL"
# Add Go to system-wide PATH
if ! grep -q "/usr/local/go/bin" /etc/environment 2>/dev/null; then if ! grep -q "/usr/local/go/bin" /etc/environment 2>/dev/null; then
echo 'PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/go/bin"' | sudo tee /etc/environment > /dev/null echo 'PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/go/bin"' | sudo tee /etc/environment > /dev/null
fi fi
# Also add to current user's bashrc for compatibility
if ! grep -q "/usr/local/go/bin" ~/.bashrc; then if ! grep -q "/usr/local/go/bin" ~/.bashrc; then
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
fi fi
# Update current session PATH
export PATH=$PATH:/usr/local/go/bin export PATH=$PATH:/usr/local/go/bin
success "Go installed successfully" success "Go installed successfully"
} }
# Install system dependencies
install_dependencies() { install_dependencies() {
log "Checking system dependencies..." log "Checking system dependencies..."
# Check which dependencies are missing
MISSING_DEPS=() MISSING_DEPS=()
case $PACKAGE_MANAGER in case $PACKAGE_MANAGER in
apt) apt)
# Check for required packages
for pkg in git make build-essential curl; do for pkg in git make build-essential curl; do
if ! dpkg -l | grep -q "^ii $pkg "; then if ! dpkg -l | grep -q "^ii $pkg "; then MISSING_DEPS+=($pkg); fi
MISSING_DEPS+=($pkg)
fi
done done
if [ ${#MISSING_DEPS[@]} -gt 0 ]; then if [ ${#MISSING_DEPS[@]} -gt 0 ]; then
log "Installing missing dependencies: ${MISSING_DEPS[*]}" log "Installing missing dependencies: ${MISSING_DEPS[*]}"
sudo apt update sudo apt update
@ -269,24 +191,15 @@ install_dependencies() {
fi fi
;; ;;
yum|dnf) yum|dnf)
# Check for required packages
for pkg in git make curl; do for pkg in git make curl; do
if ! rpm -q $pkg &>/dev/null; then if ! rpm -q $pkg &>/dev/null; then MISSING_DEPS+=($pkg); fi
MISSING_DEPS+=($pkg)
fi
done done
if ! rpm -q gcc &>/dev/null; then MISSING_DEPS+=("Development Tools"); fi
# Check for development tools
if ! rpm -q gcc &>/dev/null; then
MISSING_DEPS+=("Development Tools")
fi
if [ ${#MISSING_DEPS[@]} -gt 0 ]; then if [ ${#MISSING_DEPS[@]} -gt 0 ]; then
log "Installing missing dependencies: ${MISSING_DEPS[*]}" log "Installing missing dependencies: ${MISSING_DEPS[*]}"
if [[ " ${MISSING_DEPS[*]} " =~ " Development Tools " ]]; then if [[ " ${MISSING_DEPS[*]} " =~ " Development Tools " ]]; then
sudo $PACKAGE_MANAGER groupinstall -y "Development Tools" sudo $PACKAGE_MANAGER groupinstall -y "Development Tools"
fi fi
# Remove "Development Tools" from array for individual package installation
MISSING_DEPS=($(printf '%s\n' "${MISSING_DEPS[@]}" | grep -v "Development Tools")) MISSING_DEPS=($(printf '%s\n' "${MISSING_DEPS[@]}" | grep -v "Development Tools"))
if [ ${#MISSING_DEPS[@]} -gt 0 ]; then if [ ${#MISSING_DEPS[@]} -gt 0 ]; then
sudo $PACKAGE_MANAGER install -y "${MISSING_DEPS[@]}" sudo $PACKAGE_MANAGER install -y "${MISSING_DEPS[@]}"
@ -296,65 +209,36 @@ install_dependencies() {
fi fi
;; ;;
esac esac
success "System dependencies ready" success "System dependencies ready"
} }
# Install RQLite
install_rqlite() { install_rqlite() {
# Check if RQLite is already installed
if command -v rqlited &> /dev/null; then if command -v rqlited &> /dev/null; then
RQLITE_VERSION=$(rqlited -version | head -n1 | awk '{print $2}') RQLITE_VERSION=$(rqlited -version | head -n1 | awk '{print $2}')
log "Found RQLite version: $RQLITE_VERSION" log "Found RQLite version: $RQLITE_VERSION"
success "RQLite already installed" success "RQLite already installed"
return 0 return 0
fi fi
log "Installing RQLite..." log "Installing RQLite..."
# Determine architecture
ARCH=$(uname -m) ARCH=$(uname -m)
case $ARCH in case $ARCH in
x86_64) x86_64) RQLITE_ARCH="amd64" ;;
RQLITE_ARCH="amd64" aarch64|arm64) RQLITE_ARCH="arm64" ;;
;; armv7l) RQLITE_ARCH="arm" ;;
aarch64|arm64) *) error "Unsupported architecture: $ARCH"; exit 1 ;;
RQLITE_ARCH="arm64"
;;
armv7l)
RQLITE_ARCH="arm"
;;
*)
error "Unsupported architecture: $ARCH"
exit 1
;;
esac esac
RQLITE_VERSION="8.43.0"
# Download and install RQLite
RQLITE_VERSION="8.30.0"
RQLITE_TARBALL="rqlite-v${RQLITE_VERSION}-linux-${RQLITE_ARCH}.tar.gz" RQLITE_TARBALL="rqlite-v${RQLITE_VERSION}-linux-${RQLITE_ARCH}.tar.gz"
RQLITE_URL="https://github.com/rqlite/rqlite/releases/download/v${RQLITE_VERSION}/${RQLITE_TARBALL}" RQLITE_URL="https://github.com/rqlite/rqlite/releases/download/v${RQLITE_VERSION}/${RQLITE_TARBALL}"
cd /tmp cd /tmp
if ! wget -q "$RQLITE_URL"; then if ! wget -q "$RQLITE_URL"; then error "Failed to download RQLite from $RQLITE_URL"; exit 1; fi
error "Failed to download RQLite from $RQLITE_URL"
exit 1
fi
# Extract and install RQLite binaries
tar -xzf "$RQLITE_TARBALL" tar -xzf "$RQLITE_TARBALL"
RQLITE_DIR="rqlite-v${RQLITE_VERSION}-linux-${RQLITE_ARCH}" RQLITE_DIR="rqlite-v${RQLITE_VERSION}-linux-${RQLITE_ARCH}"
# Install RQLite binaries to system PATH
sudo cp "$RQLITE_DIR/rqlited" /usr/local/bin/ sudo cp "$RQLITE_DIR/rqlited" /usr/local/bin/
sudo cp "$RQLITE_DIR/rqlite" /usr/local/bin/ sudo cp "$RQLITE_DIR/rqlite" /usr/local/bin/
sudo chmod +x /usr/local/bin/rqlited sudo chmod +x /usr/local/bin/rqlited
sudo chmod +x /usr/local/bin/rqlite sudo chmod +x /usr/local/bin/rqlite
# Cleanup
rm -rf "$RQLITE_TARBALL" "$RQLITE_DIR" rm -rf "$RQLITE_TARBALL" "$RQLITE_DIR"
# Verify installation
if command -v rqlited &> /dev/null; then if command -v rqlited &> /dev/null; then
INSTALLED_VERSION=$(rqlited -version | head -n1 | awk '{print $2}') INSTALLED_VERSION=$(rqlited -version | head -n1 | awk '{print $2}')
success "RQLite v$INSTALLED_VERSION installed successfully" success "RQLite v$INSTALLED_VERSION installed successfully"
@ -364,102 +248,67 @@ install_rqlite() {
fi fi
} }
# Check port availability
check_ports() { check_ports() {
local ports=($NODE_PORT $RQLITE_PORT $RAFT_PORT) local ports=($NODE_PORT $RQLITE_PORT $RAFT_PORT)
for port in "${ports[@]}"; do for port in "${ports[@]}"; do
if sudo netstat -tuln 2>/dev/null | grep -q ":$port " || ss -tuln 2>/dev/null | grep -q ":$port "; then if sudo netstat -tuln 2>/dev/null | grep -q ":$port " || ss -tuln 2>/dev/null | grep -q ":$port "; then
error "Port $port is already in use. Please free it up and try again." error "Port $port is already in use. Please free it up and try again."
exit 1 exit 1
fi fi
done done
success "All required ports are available" success "All required ports are available"
} }
# Configuration wizard
configuration_wizard() { configuration_wizard() {
log "${BLUE}==================================================${NOCOLOR}" log "${BLUE}==================================================${NOCOLOR}"
log "${GREEN} DeBros Network Configuration Wizard ${NOCOLOR}" log "${GREEN} DeBros Network Configuration Wizard ${NOCOLOR}"
log "${BLUE}==================================================${NOCOLOR}" log "${BLUE}==================================================${NOCOLOR}"
if [ "$NON_INTERACTIVE" = true ]; then if [ "$NON_INTERACTIVE" = true ]; then
log "Non-interactive mode: using default configuration" log "Non-interactive mode: using default configuration"
NODE_TYPE="node" SOLANA_WALLET="11111111111111111111111111111111"
SOLANA_WALLET="11111111111111111111111111111111" # Placeholder wallet
CONFIGURE_FIREWALL="yes" CONFIGURE_FIREWALL="yes"
log "Node Type: $NODE_TYPE"
log "Installation Directory: $INSTALL_DIR" log "Installation Directory: $INSTALL_DIR"
log "Firewall Configuration: $CONFIGURE_FIREWALL" log "Firewall Configuration: $CONFIGURE_FIREWALL"
success "Configuration completed with defaults" success "Configuration completed with defaults"
return 0 return 0
fi fi
log "${GREEN}Enter your Solana wallet address for node operator rewards:${NOCOLOR}"
# Setting default node type to "node"
NODE_TYPE="node"
# Solana wallet address
log "${GREEN}Enter your Solana wallet address to be eligible for node operator rewards:${NOCOLOR}"
while true; do while true; do
read -rp "Solana Wallet Address: " SOLANA_WALLET read -rp "Solana Wallet Address: " SOLANA_WALLET
if [[ -n "$SOLANA_WALLET" && ${#SOLANA_WALLET} -ge 32 ]]; then if [[ -n "$SOLANA_WALLET" && ${#SOLANA_WALLET} -ge 32 ]]; then break; else error "Please enter a valid Solana wallet address"; fi
break
else
error "Please enter a valid Solana wallet address"
fi
done done
# Data directory
read -rp "Installation directory [default: $INSTALL_DIR]: " CUSTOM_INSTALL_DIR read -rp "Installation directory [default: $INSTALL_DIR]: " CUSTOM_INSTALL_DIR
if [[ -n "$CUSTOM_INSTALL_DIR" ]]; then if [[ -n "$CUSTOM_INSTALL_DIR" ]]; then INSTALL_DIR="$CUSTOM_INSTALL_DIR"; fi
INSTALL_DIR="$CUSTOM_INSTALL_DIR"
fi
# Firewall configuration
read -rp "Configure firewall automatically? (yes/no) [default: yes]: " CONFIGURE_FIREWALL read -rp "Configure firewall automatically? (yes/no) [default: yes]: " CONFIGURE_FIREWALL
CONFIGURE_FIREWALL="${CONFIGURE_FIREWALL:-yes}" CONFIGURE_FIREWALL="${CONFIGURE_FIREWALL:-yes}"
success "Configuration completed" success "Configuration completed"
} }
# Create user and directories
setup_directories() { setup_directories() {
log "Setting up directories and permissions..." log "Setting up directories and permissions..."
# Create debros user if it doesn't exist
if ! id "debros" &>/dev/null; then if ! id "debros" &>/dev/null; then
sudo useradd -r -s /bin/false -d "$INSTALL_DIR" debros sudo useradd -r -s /bin/false -d "$INSTALL_DIR" debros
log "Created debros user" log "Created debros user"
else else
log "User 'debros' already exists" log "User 'debros' already exists"
fi fi
sudo mkdir -p "$INSTALL_DIR"/{bin,configs,keys,data,logs,src}
# Create directory structure sudo mkdir -p "$INSTALL_DIR/keys/node"
sudo mkdir -p "$INSTALL_DIR"/{bin,configs,keys,data,logs} sudo mkdir -p "$INSTALL_DIR/data/node"/{rqlite,storage}
sudo mkdir -p "$INSTALL_DIR/keys/$NODE_TYPE"
sudo mkdir -p "$INSTALL_DIR/data/$NODE_TYPE"/{rqlite,storage}
# Set ownership first, then permissions
sudo chown -R debros:debros "$INSTALL_DIR" sudo chown -R debros:debros "$INSTALL_DIR"
sudo chmod 755 "$INSTALL_DIR" sudo chmod 755 "$INSTALL_DIR"
sudo chmod 700 "$INSTALL_DIR/keys" sudo chmod 700 "$INSTALL_DIR/keys"
sudo chmod 700 "$INSTALL_DIR/keys/$NODE_TYPE" sudo chmod 700 "$INSTALL_DIR/keys/node"
# Ensure the debros user can write to the keys directory
sudo chmod 755 "$INSTALL_DIR/data" sudo chmod 755 "$INSTALL_DIR/data"
sudo chmod 755 "$INSTALL_DIR/logs" sudo chmod 755 "$INSTALL_DIR/logs"
sudo chmod 755 "$INSTALL_DIR/configs" sudo chmod 755 "$INSTALL_DIR/configs"
sudo chmod 755 "$INSTALL_DIR/bin" sudo chmod 755 "$INSTALL_DIR/bin"
success "Directory structure ready" success "Directory structure ready"
} }
# Clone or update repository
setup_source_code() { setup_source_code() {
log "Setting up source code..." log "Setting up source code..."
if [ -d "$INSTALL_DIR/src/.git" ]; then
if [ -d "$INSTALL_DIR/src" ]; then
log "Updating existing repository..." log "Updating existing repository..."
cd "$INSTALL_DIR/src" cd "$INSTALL_DIR/src"
sudo -u debros git pull sudo -u debros git pull
@ -468,14 +317,11 @@ setup_source_code() {
sudo -u debros git clone "$REPO_URL" "$INSTALL_DIR/src" sudo -u debros git clone "$REPO_URL" "$INSTALL_DIR/src"
cd "$INSTALL_DIR/src" cd "$INSTALL_DIR/src"
fi fi
success "Source code ready" success "Source code ready"
} }
# Generate identity key
generate_identity() { generate_identity() {
local identity_file="$INSTALL_DIR/keys/$NODE_TYPE/identity.key" local identity_file="$INSTALL_DIR/keys/node/identity.key"
if [ -f "$identity_file" ]; then if [ -f "$identity_file" ]; then
if [ "$UPDATE_MODE" = true ]; then if [ "$UPDATE_MODE" = true ]; then
log "Identity key already exists, keeping existing key" log "Identity key already exists, keeping existing key"
@ -486,110 +332,65 @@ generate_identity() {
sudo rm -f "$identity_file" sudo rm -f "$identity_file"
fi fi
fi fi
log "Generating node identity..." log "Generating node identity..."
cd "$INSTALL_DIR/src" cd "$INSTALL_DIR/src"
# Create a custom identity generation script with output path support
cat > /tmp/generate_identity_custom.go << 'EOF' cat > /tmp/generate_identity_custom.go << 'EOF'
package main package main
import ( import (
"crypto/rand" "crypto/rand"
"flag" "flag"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peer"
) )
func main() { func main() {
var outputPath string var outputPath string
flag.StringVar(&outputPath, "output", "", "Output path for identity key") flag.StringVar(&outputPath, "output", "", "Output path for identity key")
flag.Parse() flag.Parse()
if outputPath == "" { if outputPath == "" {
fmt.Println("Usage: go run generate_identity_custom.go -output <path>") fmt.Println("Usage: go run generate_identity_custom.go -output <path>")
os.Exit(1) os.Exit(1)
} }
// Generate identity
priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, rand.Reader) priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, rand.Reader)
if err != nil { if err != nil { panic(err) }
panic(err)
}
// Get peer ID
peerID, err := peer.IDFromPublicKey(pub) peerID, err := peer.IDFromPublicKey(pub)
if err != nil { if err != nil { panic(err) }
panic(err)
}
// Marshal private key
data, err := crypto.MarshalPrivateKey(priv) data, err := crypto.MarshalPrivateKey(priv)
if err != nil { if err != nil { panic(err) }
panic(err) if err := os.MkdirAll(filepath.Dir(outputPath), 0700); err != nil { panic(err) }
} if err := os.WriteFile(outputPath, data, 0600); err != nil { panic(err) }
// Create directory
if err := os.MkdirAll(filepath.Dir(outputPath), 0700); err != nil {
panic(err)
}
// Save identity
if err := os.WriteFile(outputPath, data, 0600); err != nil {
panic(err)
}
fmt.Printf("Generated Peer ID: %s\n", peerID.String()) fmt.Printf("Generated Peer ID: %s\n", peerID.String())
fmt.Printf("Identity saved to: %s\n", outputPath) fmt.Printf("Identity saved to: %s\n", outputPath)
} }
EOF EOF
# Ensure Go is in PATH and generate the identity key
export PATH=$PATH:/usr/local/go/bin export PATH=$PATH:/usr/local/go/bin
sudo -u debros env "PATH=$PATH:/usr/local/go/bin" "GOMOD=$(pwd)" go run /tmp/generate_identity_custom.go -output "$identity_file" sudo -u debros env "PATH=$PATH:/usr/local/go/bin" "GOMOD=$(pwd)" go run /tmp/generate_identity_custom.go -output "$identity_file"
rm /tmp/generate_identity_custom.go rm /tmp/generate_identity_custom.go
success "Node identity generated" success "Node identity generated"
} }
# Build binaries
build_binaries() { build_binaries() {
log "Building DeBros Network binaries..." log "Building DeBros Network binaries..."
cd "$INSTALL_DIR/src" cd "$INSTALL_DIR/src"
# Ensure Go is in PATH and build all binaries
export PATH=$PATH:/usr/local/go/bin export PATH=$PATH:/usr/local/go/bin
sudo -u debros env "PATH=$PATH:/usr/local/go/bin" make build sudo -u debros env "PATH=$PATH:/usr/local/go/bin" make build
# If in update mode, stop services before copying binaries to avoid "Text file busy" error
local services_were_running=() local services_were_running=()
if [ "$UPDATE_MODE" = true ]; then if [ "$UPDATE_MODE" = true ]; then
log "Update mode: checking for running services before binary update..." log "Update mode: checking for running services before binary update..."
if systemctl is-active --quiet debros-node.service 2>/dev/null; then if systemctl is-active --quiet debros-node.service 2>/dev/null; then
log "Stopping debros-node service to update binaries..." log "Stopping debros-node service to update binaries..."
sudo systemctl stop debros-node.service sudo systemctl stop debros-node.service
services_were_running+=("debros-node") services_were_running+=("debros-node")
fi fi
# Give services a moment to fully stop
if [ ${#services_were_running[@]} -gt 0 ]; then if [ ${#services_were_running[@]} -gt 0 ]; then
log "Waiting for services to stop completely..." log "Waiting for services to stop completely..."
sleep 3 sleep 3
fi fi
fi fi
# Copy binaries to installation directory
sudo cp bin/* "$INSTALL_DIR/bin/" sudo cp bin/* "$INSTALL_DIR/bin/"
sudo chown debros:debros "$INSTALL_DIR/bin/"* sudo chown debros:debros "$INSTALL_DIR/bin/"*
# If in update mode and services were running, restart them
if [ "$UPDATE_MODE" = true ] && [ ${#services_were_running[@]} -gt 0 ]; then if [ "$UPDATE_MODE" = true ] && [ ${#services_were_running[@]} -gt 0 ]; then
log "Restarting previously running services..." log "Restarting previously running services..."
for service in "${services_were_running[@]}"; do for service in "${services_were_running[@]}"; do
@ -597,48 +398,35 @@ build_binaries() {
sudo systemctl start $service.service sudo systemctl start $service.service
done done
fi fi
success "Binaries built and installed" success "Binaries built and installed"
} }
# Generate configuration files
generate_configs() { generate_configs() {
log "Generating configuration files..." log "Generating configuration files..."
cat > /tmp/node.yaml << EOF
cat > /tmp/config.yaml << EOF
node: node:
data_dir: "$INSTALL_DIR/data/node" data_dir: "$INSTALL_DIR/data/node"
key_file: "$INSTALL_DIR/keys/node/identity.key" key_file: "$INSTALL_DIR/keys/node/identity.key"
listen_addresses: listen_addresses:
- "/ip4/0.0.0.0/tcp/$NODE_PORT" - "/ip4/0.0.0.0/tcp/$NODE_PORT"
solana_wallet: "$SOLANA_WALLET" solana_wallet: "$SOLANA_WALLET"
database: database:
rqlite_port: $RQLITE_PORT rqlite_port: $RQLITE_PORT
rqlite_raft_port: $RAFT_PORT rqlite_raft_port: $RAFT_PORT
logging: logging:
level: "info" level: "info"
file: "$INSTALL_DIR/logs/node.log" file: "$INSTALL_DIR/logs/node.log"
EOF EOF
sudo mv /tmp/node.yaml "$INSTALL_DIR/configs/node.yaml"
sudo mv /tmp/config.yaml "$INSTALL_DIR/configs/$NODE_TYPE.yaml" sudo chown debros:debros "$INSTALL_DIR/configs/node.yaml"
sudo chown debros:debros "$INSTALL_DIR/configs/$NODE_TYPE.yaml"
success "Configuration files generated" success "Configuration files generated"
} }
# Configure firewall
configure_firewall() { configure_firewall() {
if [[ "$CONFIGURE_FIREWALL" == "yes" ]]; then if [[ "$CONFIGURE_FIREWALL" == "yes" ]]; then
log "Configuring firewall rules..." log "Configuring firewall rules..."
if command -v ufw &> /dev/null; then if command -v ufw &> /dev/null; then
# Add firewall rules regardless of UFW status
# This allows the rules to be ready when UFW is enabled
log "Adding UFW rules for DeBros Network ports..." log "Adding UFW rules for DeBros Network ports..."
# Add ports for node
for port in $NODE_PORT $RQLITE_PORT $RAFT_PORT; do for port in $NODE_PORT $RQLITE_PORT $RAFT_PORT; do
if ! sudo ufw allow $port; then if ! sudo ufw allow $port; then
error "Failed to allow port $port" error "Failed to allow port $port"
@ -646,10 +434,7 @@ configure_firewall() {
fi fi
log "Added UFW rule: allow port $port" log "Added UFW rule: allow port $port"
done done
# Check UFW status and inform user
UFW_STATUS=$(sudo ufw status | grep -o "Status: [a-z]\+" | awk '{print $2}' || echo "inactive") UFW_STATUS=$(sudo ufw status | grep -o "Status: [a-z]\+" | awk '{print $2}' || echo "inactive")
if [[ "$UFW_STATUS" == "active" ]]; then if [[ "$UFW_STATUS" == "active" ]]; then
success "Firewall rules added and active" success "Firewall rules added and active"
else else
@ -666,30 +451,20 @@ configure_firewall() {
fi fi
} }
# Create systemd service
create_systemd_service() { create_systemd_service() {
local service_file="/etc/systemd/system/debros-$NODE_TYPE.service" local service_file="/etc/systemd/system/debros-node.service"
if [ -f "$service_file" ]; then
# Always clean up any existing service files to ensure fresh start log "Cleaning up existing node service..."
for service in debros-bootstrap debros-node; do sudo systemctl stop debros-node.service 2>/dev/null || true
if [ -f "/etc/systemd/system/$service.service" ]; then sudo systemctl disable debros-node.service 2>/dev/null || true
log "Cleaning up existing $service service..." sudo rm -f "$service_file"
sudo systemctl stop $service.service 2>/dev/null || true
sudo systemctl disable $service.service 2>/dev/null || true
sudo rm -f /etc/systemd/system/$service.service
fi fi
done
sudo systemctl daemon-reload sudo systemctl daemon-reload
log "Creating new systemd service..." log "Creating new systemd service..."
local exec_start="$INSTALL_DIR/bin/node -data $INSTALL_DIR/data/node"
# Determine the correct ExecStart command based on node type cat > /tmp/debros-node.service << EOF
local exec_start=""
exec_start="$INSTALL_DIR/bin/node -data $INSTALL_DIR/data/node"
cat > /tmp/debros-$NODE_TYPE.service << EOF
[Unit] [Unit]
Description=DeBros Network $NODE_TYPE Node Description=DeBros Network Node
After=network.target After=network.target
Wants=network-online.target Wants=network-online.target
@ -704,9 +479,8 @@ Restart=always
RestartSec=10 RestartSec=10
StandardOutput=journal StandardOutput=journal
StandardError=journal StandardError=journal
SyslogIdentifier=debros-$NODE_TYPE SyslogIdentifier=debros-node
# Security settings
NoNewPrivileges=yes NoNewPrivileges=yes
PrivateTmp=yes PrivateTmp=yes
ProtectSystem=strict ProtectSystem=strict
@ -716,96 +490,65 @@ ReadWritePaths=$INSTALL_DIR
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
EOF EOF
sudo mv /tmp/debros-node.service "$service_file"
sudo mv /tmp/debros-$NODE_TYPE.service "$service_file"
sudo systemctl daemon-reload sudo systemctl daemon-reload
sudo systemctl enable debros-$NODE_TYPE.service sudo systemctl enable debros-node.service
success "Systemd service ready" success "Systemd service ready"
} }
# Start the service
start_service() { start_service() {
log "Starting DeBros Network service..." log "Starting DeBros Network service..."
sudo systemctl start debros-node.service
sudo systemctl start debros-$NODE_TYPE.service
sleep 3 sleep 3
if systemctl is-active --quiet debros-node.service; then
if systemctl is-active --quiet debros-$NODE_TYPE.service; then
success "DeBros Network service started successfully" success "DeBros Network service started successfully"
else else
error "Failed to start DeBros Network service" error "Failed to start DeBros Network service"
log "Check logs with: sudo journalctl -u debros-$NODE_TYPE.service" log "Check logs with: sudo journalctl -u debros-node.service"
exit 1 exit 1
fi fi
} }
# Display banner
display_banner() { display_banner() {
echo -e "${BLUE}========================================================================${NOCOLOR}" echo -e "${BLUE}========================================================================${NOCOLOR}"
echo -e "${CYAN} echo -e "${CYAN}
____ ____ _ _ _ _ ____ ____ _ _ _ _
| _ \ ___| __ ) _ __ ___ ___ | \ | | ___| |___ _____ _ __| | __ | _ \\ ___| __ ) _ __ ___ ___ | \\ | | ___| |___ _____ _ __| | __
| | | |/ _ \ _ \| __/ _ \/ __| | \| |/ _ \ __\ \ /\ / / _ \| __| |/ / | | | |/ _ \\ _ \\| __/ _ \\/ __| | \\| |/ _ \\ __\\ \\ /\\ / / _ \\| __| |/ /
| |_| | __/ |_) | | | (_) \__ \ | |\ | __/ |_ \ V V / (_) | | | < | |_| | __/ |_) | | | (_) \\__ \\ | |\\ | __/ |_ \\ V V / (_) | | | <
|____/ \___|____/|_| \___/|___/ |_| \_|\___|\__| \_/\_/ \___/|_| |_|\_\\ |____/ \\___|____/|_| \\___/|___/ |_| \\_|\\___|\\__| \\_/\\_/ \\___/|_| |_|\\_\\
${NOCOLOR}" ${NOCOLOR}"
echo -e "${BLUE}========================================================================${NOCOLOR}" echo -e "${BLUE}========================================================================${NOCOLOR}"
} }
# Main installation function
main() { main() {
display_banner display_banner
log "${BLUE}==================================================${NOCOLOR}" log "${BLUE}==================================================${NOCOLOR}"
log "${GREEN} Starting DeBros Network Installation ${NOCOLOR}" log "${GREEN} Starting DeBros Network Installation ${NOCOLOR}"
log "${BLUE}==================================================${NOCOLOR}" log "${BLUE}==================================================${NOCOLOR}"
detect_os detect_os
check_existing_installation check_existing_installation
if [ "$UPDATE_MODE" != true ]; then check_ports; else log "Update mode: skipping port availability check"; fi
# Skip port check in update mode since services are already running if ! check_go_installation; then install_go; fi
if [ "$UPDATE_MODE" != true ]; then
check_ports
else
log "Update mode: skipping port availability check"
fi
# Check and install Go if needed
if ! check_go_installation; then
install_go
fi
install_dependencies install_dependencies
install_rqlite install_rqlite
if [ "$UPDATE_MODE" != true ]; then configuration_wizard; else
# Skip configuration wizard in update mode
if [ "$UPDATE_MODE" != true ]; then
configuration_wizard
else
log "Update mode: skipping configuration wizard" log "Update mode: skipping configuration wizard"
# Force node type to 'node' for consistent terminology SOLANA_WALLET="11111111111111111111111111111111"
NODE_TYPE="node" CONFIGURE_FIREWALL="yes"
log "Using node type: $NODE_TYPE (standardized from any previous bootstrap configuration)"
fi fi
setup_directories setup_directories
setup_source_code setup_source_code
generate_identity generate_identity
build_binaries build_binaries
# Only generate new configs if not in update mode
if [ "$UPDATE_MODE" != true ]; then if [ "$UPDATE_MODE" != true ]; then
generate_configs generate_configs
configure_firewall configure_firewall
else else
log "Update mode: keeping existing configuration" log "Update mode: keeping existing configuration"
fi fi
create_systemd_service create_systemd_service
start_service start_service
# Display completion information
log "${BLUE}==================================================${NOCOLOR}" log "${BLUE}==================================================${NOCOLOR}"
if [ "$UPDATE_MODE" = true ]; then if [ "$UPDATE_MODE" = true ]; then
log "${GREEN} Update Complete! ${NOCOLOR}" log "${GREEN} Update Complete! ${NOCOLOR}"
@ -813,25 +556,21 @@ main() {
log "${GREEN} Installation Complete! ${NOCOLOR}" log "${GREEN} Installation Complete! ${NOCOLOR}"
fi fi
log "${BLUE}==================================================${NOCOLOR}" log "${BLUE}==================================================${NOCOLOR}"
log "${GREEN}Installation Directory:${NOCOLOR} ${CYAN}$INSTALL_DIR${NOCOLOR}" log "${GREEN}Installation Directory:${NOCOLOR} ${CYAN}$INSTALL_DIR${NOCOLOR}"
log "${GREEN}Configuration:${NOCOLOR} ${CYAN}$INSTALL_DIR/configs/$NODE_TYPE.yaml${NOCOLOR}" log "${GREEN}Configuration:${NOCOLOR} ${CYAN}$INSTALL_DIR/configs/node.yaml${NOCOLOR}"
log "${GREEN}Logs:${NOCOLOR} ${CYAN}$INSTALL_DIR/logs/$NODE_TYPE.log${NOCOLOR}" log "${GREEN}Logs:${NOCOLOR} ${CYAN}$INSTALL_DIR/logs/node.log${NOCOLOR}"
log "${GREEN}Node Port:${NOCOLOR} ${CYAN}$NODE_PORT${NOCOLOR}" log "${GREEN}Node Port:${NOCOLOR} ${CYAN}$NODE_PORT${NOCOLOR}"
log "${GREEN}RQLite Port:${NOCOLOR} ${CYAN}$RQLITE_PORT${NOCOLOR}" log "${GREEN}RQLite Port:${NOCOLOR} ${CYAN}$RQLITE_PORT${NOCOLOR}"
log "${GREEN}Raft Port:${NOCOLOR} ${CYAN}$RAFT_PORT${NOCOLOR}" log "${GREEN}Raft Port:${NOCOLOR} ${CYAN}$RAFT_PORT${NOCOLOR}"
log "${BLUE}==================================================${NOCOLOR}" log "${BLUE}==================================================${NOCOLOR}"
log "${GREEN}Management Commands:${NOCOLOR}" log "${GREEN}Management Commands:${NOCOLOR}"
log "${CYAN} - sudo systemctl status debros-$NODE_TYPE${NOCOLOR} (Check status)" log "${CYAN} - sudo systemctl status debros-node${NOCOLOR} (Check status)"
log "${CYAN} - sudo systemctl restart debros-$NODE_TYPE${NOCOLOR} (Restart service)" log "${CYAN} - sudo systemctl restart debros-node${NOCOLOR} (Restart service)"
log "${CYAN} - sudo systemctl stop debros-$NODE_TYPE${NOCOLOR} (Stop service)" log "${CYAN} - sudo systemctl stop debros-node${NOCOLOR} (Stop service)"
log "${CYAN} - sudo systemctl start debros-$NODE_TYPE${NOCOLOR} (Start service)" log "${CYAN} - sudo systemctl start debros-node${NOCOLOR} (Start service)"
log "${CYAN} - sudo journalctl -u debros-$NODE_TYPE.service -f${NOCOLOR} (View logs)" log "${CYAN} - sudo journalctl -u debros-node.service -f${NOCOLOR} (View logs)"
log "${CYAN} - $INSTALL_DIR/bin/network-cli${NOCOLOR} (Use CLI tools)" log "${CYAN} - $INSTALL_DIR/bin/network-cli${NOCOLOR} (Use CLI tools)"
log "${BLUE}==================================================${NOCOLOR}" log "${BLUE}==================================================${NOCOLOR}"
if [ "$UPDATE_MODE" = true ]; then if [ "$UPDATE_MODE" = true ]; then
success "DeBros Network has been updated and is running!" success "DeBros Network has been updated and is running!"
else else
@ -840,5 +579,4 @@ main() {
log "${CYAN}For documentation visit: https://docs.debros.io${NOCOLOR}" log "${CYAN}For documentation visit: https://docs.debros.io${NOCOLOR}"
} }
# Run main function
main "$@" main "$@"