Fix P2P Connectivity Regression + Dynamic Versioning System #12

Merged
tony merged 10 commits from feature/phase-4-real-providers into main 2025-09-26 06:10:01 +00:00
2 changed files with 56 additions and 54 deletions
Showing only changes of commit 14b5125c12 - Show all commits

View File

@@ -9,10 +9,11 @@ import (
"chorus/internal/logging" "chorus/internal/logging"
"chorus/pubsub" "chorus/pubsub"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
// HTTPServer provides HTTP API endpoints for Bzzz // HTTPServer provides HTTP API endpoints for CHORUS
type HTTPServer struct { type HTTPServer struct {
port int port int
hypercoreLog *logging.HypercoreLog hypercoreLog *logging.HypercoreLog
@@ -20,7 +21,7 @@ type HTTPServer struct {
server *http.Server server *http.Server
} }
// NewHTTPServer creates a new HTTP server for Bzzz API // NewHTTPServer creates a new HTTP server for CHORUS API
func NewHTTPServer(port int, hlog *logging.HypercoreLog, ps *pubsub.PubSub) *HTTPServer { func NewHTTPServer(port int, hlog *logging.HypercoreLog, ps *pubsub.PubSub) *HTTPServer {
return &HTTPServer{ return &HTTPServer{
port: port, port: port,
@@ -32,38 +33,38 @@ func NewHTTPServer(port int, hlog *logging.HypercoreLog, ps *pubsub.PubSub) *HTT
// Start starts the HTTP server // Start starts the HTTP server
func (h *HTTPServer) Start() error { func (h *HTTPServer) Start() error {
router := mux.NewRouter() router := mux.NewRouter()
// Enable CORS for all routes // Enable CORS for all routes
router.Use(func(next http.Handler) http.Handler { router.Use(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if r.Method == "OPTIONS" { if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
return return
} }
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
}) })
}) })
// API routes // API routes
api := router.PathPrefix("/api").Subrouter() api := router.PathPrefix("/api").Subrouter()
// Hypercore log endpoints // Hypercore log endpoints
api.HandleFunc("/hypercore/logs", h.handleGetLogs).Methods("GET") api.HandleFunc("/hypercore/logs", h.handleGetLogs).Methods("GET")
api.HandleFunc("/hypercore/logs/recent", h.handleGetRecentLogs).Methods("GET") api.HandleFunc("/hypercore/logs/recent", h.handleGetRecentLogs).Methods("GET")
api.HandleFunc("/hypercore/logs/stats", h.handleGetLogStats).Methods("GET") api.HandleFunc("/hypercore/logs/stats", h.handleGetLogStats).Methods("GET")
api.HandleFunc("/hypercore/logs/since/{index}", h.handleGetLogsSince).Methods("GET") api.HandleFunc("/hypercore/logs/since/{index}", h.handleGetLogsSince).Methods("GET")
// Health check // Health check
api.HandleFunc("/health", h.handleHealth).Methods("GET") api.HandleFunc("/health", h.handleHealth).Methods("GET")
// Status endpoint // Status endpoint
api.HandleFunc("/status", h.handleStatus).Methods("GET") api.HandleFunc("/status", h.handleStatus).Methods("GET")
h.server = &http.Server{ h.server = &http.Server{
Addr: fmt.Sprintf(":%d", h.port), Addr: fmt.Sprintf(":%d", h.port),
Handler: router, Handler: router,
@@ -71,7 +72,7 @@ func (h *HTTPServer) Start() error {
WriteTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second,
IdleTimeout: 60 * time.Second, IdleTimeout: 60 * time.Second,
} }
fmt.Printf("🌐 Starting HTTP API server on port %d\n", h.port) fmt.Printf("🌐 Starting HTTP API server on port %d\n", h.port)
return h.server.ListenAndServe() return h.server.ListenAndServe()
} }
@@ -87,16 +88,16 @@ func (h *HTTPServer) Stop() error {
// handleGetLogs returns hypercore log entries // handleGetLogs returns hypercore log entries
func (h *HTTPServer) handleGetLogs(w http.ResponseWriter, r *http.Request) { func (h *HTTPServer) handleGetLogs(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
// Parse query parameters // Parse query parameters
query := r.URL.Query() query := r.URL.Query()
startStr := query.Get("start") startStr := query.Get("start")
endStr := query.Get("end") endStr := query.Get("end")
limitStr := query.Get("limit") limitStr := query.Get("limit")
var start, end uint64 var start, end uint64
var err error var err error
if startStr != "" { if startStr != "" {
start, err = strconv.ParseUint(startStr, 10, 64) start, err = strconv.ParseUint(startStr, 10, 64)
if err != nil { if err != nil {
@@ -104,7 +105,7 @@ func (h *HTTPServer) handleGetLogs(w http.ResponseWriter, r *http.Request) {
return return
} }
} }
if endStr != "" { if endStr != "" {
end, err = strconv.ParseUint(endStr, 10, 64) end, err = strconv.ParseUint(endStr, 10, 64)
if err != nil { if err != nil {
@@ -114,7 +115,7 @@ func (h *HTTPServer) handleGetLogs(w http.ResponseWriter, r *http.Request) {
} else { } else {
end = h.hypercoreLog.Length() end = h.hypercoreLog.Length()
} }
var limit int = 100 // Default limit var limit int = 100 // Default limit
if limitStr != "" { if limitStr != "" {
limit, err = strconv.Atoi(limitStr) limit, err = strconv.Atoi(limitStr)
@@ -122,7 +123,7 @@ func (h *HTTPServer) handleGetLogs(w http.ResponseWriter, r *http.Request) {
limit = 100 limit = 100
} }
} }
// Get log entries // Get log entries
var entries []logging.LogEntry var entries []logging.LogEntry
if endStr != "" || startStr != "" { if endStr != "" || startStr != "" {
@@ -130,87 +131,87 @@ func (h *HTTPServer) handleGetLogs(w http.ResponseWriter, r *http.Request) {
} else { } else {
entries, err = h.hypercoreLog.GetRecentEntries(limit) entries, err = h.hypercoreLog.GetRecentEntries(limit)
} }
if err != nil { if err != nil {
http.Error(w, fmt.Sprintf("Failed to get log entries: %v", err), http.StatusInternalServerError) http.Error(w, fmt.Sprintf("Failed to get log entries: %v", err), http.StatusInternalServerError)
return return
} }
response := map[string]interface{}{ response := map[string]interface{}{
"entries": entries, "entries": entries,
"count": len(entries), "count": len(entries),
"timestamp": time.Now().Unix(), "timestamp": time.Now().Unix(),
"total": h.hypercoreLog.Length(), "total": h.hypercoreLog.Length(),
} }
json.NewEncoder(w).Encode(response) json.NewEncoder(w).Encode(response)
} }
// handleGetRecentLogs returns the most recent log entries // handleGetRecentLogs returns the most recent log entries
func (h *HTTPServer) handleGetRecentLogs(w http.ResponseWriter, r *http.Request) { func (h *HTTPServer) handleGetRecentLogs(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
// Parse limit parameter // Parse limit parameter
query := r.URL.Query() query := r.URL.Query()
limitStr := query.Get("limit") limitStr := query.Get("limit")
limit := 50 // Default limit := 50 // Default
if limitStr != "" { if limitStr != "" {
if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 1000 { if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 1000 {
limit = l limit = l
} }
} }
entries, err := h.hypercoreLog.GetRecentEntries(limit) entries, err := h.hypercoreLog.GetRecentEntries(limit)
if err != nil { if err != nil {
http.Error(w, fmt.Sprintf("Failed to get recent entries: %v", err), http.StatusInternalServerError) http.Error(w, fmt.Sprintf("Failed to get recent entries: %v", err), http.StatusInternalServerError)
return return
} }
response := map[string]interface{}{ response := map[string]interface{}{
"entries": entries, "entries": entries,
"count": len(entries), "count": len(entries),
"timestamp": time.Now().Unix(), "timestamp": time.Now().Unix(),
"total": h.hypercoreLog.Length(), "total": h.hypercoreLog.Length(),
} }
json.NewEncoder(w).Encode(response) json.NewEncoder(w).Encode(response)
} }
// handleGetLogsSince returns log entries since a given index // handleGetLogsSince returns log entries since a given index
func (h *HTTPServer) handleGetLogsSince(w http.ResponseWriter, r *http.Request) { func (h *HTTPServer) handleGetLogsSince(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
vars := mux.Vars(r) vars := mux.Vars(r)
indexStr := vars["index"] indexStr := vars["index"]
index, err := strconv.ParseUint(indexStr, 10, 64) index, err := strconv.ParseUint(indexStr, 10, 64)
if err != nil { if err != nil {
http.Error(w, "Invalid index parameter", http.StatusBadRequest) http.Error(w, "Invalid index parameter", http.StatusBadRequest)
return return
} }
entries, err := h.hypercoreLog.GetEntriesSince(index) entries, err := h.hypercoreLog.GetEntriesSince(index)
if err != nil { if err != nil {
http.Error(w, fmt.Sprintf("Failed to get entries since index: %v", err), http.StatusInternalServerError) http.Error(w, fmt.Sprintf("Failed to get entries since index: %v", err), http.StatusInternalServerError)
return return
} }
response := map[string]interface{}{ response := map[string]interface{}{
"entries": entries, "entries": entries,
"count": len(entries), "count": len(entries),
"since_index": index, "since_index": index,
"timestamp": time.Now().Unix(), "timestamp": time.Now().Unix(),
"total": h.hypercoreLog.Length(), "total": h.hypercoreLog.Length(),
} }
json.NewEncoder(w).Encode(response) json.NewEncoder(w).Encode(response)
} }
// handleGetLogStats returns statistics about the hypercore log // handleGetLogStats returns statistics about the hypercore log
func (h *HTTPServer) handleGetLogStats(w http.ResponseWriter, r *http.Request) { func (h *HTTPServer) handleGetLogStats(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
stats := h.hypercoreLog.GetStats() stats := h.hypercoreLog.GetStats()
json.NewEncoder(w).Encode(stats) json.NewEncoder(w).Encode(stats)
} }
@@ -218,26 +219,26 @@ func (h *HTTPServer) handleGetLogStats(w http.ResponseWriter, r *http.Request) {
// handleHealth returns health status // handleHealth returns health status
func (h *HTTPServer) handleHealth(w http.ResponseWriter, r *http.Request) { func (h *HTTPServer) handleHealth(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
health := map[string]interface{}{ health := map[string]interface{}{
"status": "healthy", "status": "healthy",
"timestamp": time.Now().Unix(), "timestamp": time.Now().Unix(),
"log_entries": h.hypercoreLog.Length(), "log_entries": h.hypercoreLog.Length(),
} }
json.NewEncoder(w).Encode(health) json.NewEncoder(w).Encode(health)
} }
// handleStatus returns detailed status information // handleStatus returns detailed status information
func (h *HTTPServer) handleStatus(w http.ResponseWriter, r *http.Request) { func (h *HTTPServer) handleStatus(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
status := map[string]interface{}{ status := map[string]interface{}{
"status": "running", "status": "running",
"timestamp": time.Now().Unix(), "timestamp": time.Now().Unix(),
"hypercore": h.hypercoreLog.GetStats(), "hypercore": h.hypercoreLog.GetStats(),
"api_version": "1.0.0", "api_version": "1.0.0",
} }
json.NewEncoder(w).Encode(status) json.NewEncoder(w).Encode(status)
} }

View File

@@ -6,17 +6,18 @@ import (
"time" "time"
"chorus/pkg/dht" "chorus/pkg/dht"
"github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p"
kaddht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p/core/host" "github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/p2p/net/connmgr" "github.com/libp2p/go-libp2p/p2p/net/connmgr"
"github.com/libp2p/go-libp2p/p2p/security/noise" "github.com/libp2p/go-libp2p/p2p/security/noise"
"github.com/libp2p/go-libp2p/p2p/transport/tcp" "github.com/libp2p/go-libp2p/p2p/transport/tcp"
kaddht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/multiformats/go-multiaddr" "github.com/multiformats/go-multiaddr"
) )
// Node represents a Bzzz P2P node // Node represents a CHORUS P2P node
type Node struct { type Node struct {
host host.Host host host.Host
ctx context.Context ctx context.Context
@@ -47,8 +48,8 @@ func NewNode(ctx context.Context, opts ...Option) (*Node, error) {
// Create connection manager with scaling-optimized limits // Create connection manager with scaling-optimized limits
connManager, err := connmgr.NewConnManager( connManager, err := connmgr.NewConnManager(
config.LowWatermark, // Low watermark (32) config.LowWatermark, // Low watermark (32)
config.HighWatermark, // High watermark (128) config.HighWatermark, // High watermark (128)
connmgr.WithGracePeriod(30*time.Second), // Grace period before pruning connmgr.WithGracePeriod(30*time.Second), // Grace period before pruning
) )
if err != nil { if err != nil {
@@ -64,7 +65,7 @@ func NewNode(ctx context.Context, opts ...Option) (*Node, error) {
libp2p.DefaultMuxers, libp2p.DefaultMuxers,
libp2p.EnableRelay(), libp2p.EnableRelay(),
libp2p.ConnectionManager(connManager), // Add connection management libp2p.ConnectionManager(connManager), // Add connection management
libp2p.EnableAutoRelay(), // Enable AutoRelay for container environments libp2p.EnableAutoRelay(), // Enable AutoRelay for container environments
) )
if err != nil { if err != nil {
cancel() cancel()
@@ -171,9 +172,9 @@ func (n *Node) startBackgroundTasks() {
// logConnectionStatus logs the current connection status // logConnectionStatus logs the current connection status
func (n *Node) logConnectionStatus() { func (n *Node) logConnectionStatus() {
peers := n.Peers() peers := n.Peers()
fmt.Printf("🐝 Bzzz Node Status - ID: %s, Connected Peers: %d\n", fmt.Printf("CHORUS Node Status - ID: %s, Connected Peers: %d\n",
n.ID().ShortString(), len(peers)) n.ID().ShortString(), len(peers))
if len(peers) > 0 { if len(peers) > 0 {
fmt.Printf(" Connected to: ") fmt.Printf(" Connected to: ")
for i, p := range peers { for i, p := range peers {
@@ -211,4 +212,4 @@ func (n *Node) Close() error {
} }
n.cancel() n.cancel()
return n.host.Close() return n.host.Close()
} }