diff --git a/.zed/debug.json b/.zed/debug.json index 70e0ab6..93376b0 100644 --- a/.zed/debug.json +++ b/.zed/debug.json @@ -27,5 +27,34 @@ "GATEWAY_API_KEY": "ak_iGustrsFk9H8uXpwczCATe5U:default" }, "args": ["-test.v"] + }, + { + "adapter": "Delve", + "label": "Gateway Go 8005 Port (Delve)", + "request": "launch", + "mode": "debug", + "program": "./cmd/gateway", + "env": { + "GATEWAY_ADDR": ":8005", + "GATEWAY_BOOTSTRAP_PEERS": "/ip4/127.0.0.1/tcp/4001/p2p/12D3KooWSHHwEY6cga3ng7tD1rzStAU58ogQXVMX3LZJ6Gqf6dee", + "GATEWAY_NAMESPACE": "default", + "GATEWAY_API_KEY": "ak_iGustrsFk9H8uXpwczCATe5U:default" + } + }, + { + "adapter": "Delve", + "label": "Network CLI - peers (Delve)", + "request": "launch", + "mode": "debug", + "program": "./cmd/cli", + "args": ["peers"] + }, + { + "adapter": "Delve", + "label": "Network CLI - PubSub Subscribe (Delve)", + "request": "launch", + "mode": "debug", + "program": "./cmd/cli", + "args": ["pubsub", "subscribe", "monitoring"] } ] diff --git a/Makefile b/Makefile index e39702d..360c233 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ test-e2e: .PHONY: build clean test run-node run-node2 run-node3 run-example deps tidy fmt vet lint clear-ports -VERSION := 0.42.0-beta +VERSION := 0.42.1-beta COMMIT ?= $(shell git rev-parse --short HEAD 2>/dev/null || echo unknown) DATE ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ) LDFLAGS := -X 'main.version=$(VERSION)' -X 'main.commit=$(COMMIT)' -X 'main.date=$(DATE)' diff --git a/cli b/cli new file mode 100755 index 0000000..0651ee2 Binary files /dev/null and b/cli differ diff --git a/cmd/cli/main.go b/cmd/cli/main.go index 8e6ae00..794bef1 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -421,38 +421,25 @@ func handlePeerID() { func createClient() (client.NetworkClient, error) { config := client.DefaultClientConfig("network-cli") - // Check for existing credentials - creds, err := auth.GetValidCredentials() + // Check for existing credentials using enhanced authentication + creds, err := auth.GetValidEnhancedCredentials() if err != nil { - // No valid credentials found, trigger authentication flow - fmt.Printf("🔐 Authentication required for DeBros Network CLI\n") - fmt.Printf("💡 This will open your browser to authenticate with your wallet\n") - + // No valid credentials found, use the enhanced authentication flow gatewayURL := auth.GetDefaultGatewayURL() - fmt.Printf("🌐 Gateway: %s\n\n", gatewayURL) - // Perform wallet authentication - newCreds, authErr := auth.PerformWalletAuthentication(gatewayURL) + newCreds, authErr := auth.GetOrPromptForCredentials(gatewayURL) if authErr != nil { return nil, fmt.Errorf("authentication failed: %w", authErr) } - // Save credentials - if saveErr := auth.SaveCredentialsForDefaultGateway(newCreds); saveErr != nil { - fmt.Printf("⚠️ Warning: failed to save credentials: %v\n", saveErr) - } else { - fmt.Printf("💾 Credentials saved to ~/.debros/credentials.json\n") - } - creds = newCreds } // Configure client with API key config.APIKey = creds.APIKey - // Update last used time + // Update last used time - the enhanced store handles saving automatically creds.UpdateLastUsed() - auth.SaveCredentialsForDefaultGateway(creds) // Best effort save networkClient, err := client.NewClient(config) if err != nil { diff --git a/network-cli b/network-cli new file mode 100755 index 0000000..ffa12b0 Binary files /dev/null and b/network-cli differ diff --git a/pkg/auth/credentials.go b/pkg/auth/credentials.go index 7e1f9bd..7176eb6 100644 --- a/pkg/auth/credentials.go +++ b/pkg/auth/credentials.go @@ -189,27 +189,6 @@ func HasValidCredentials() (bool, error) { return exists && creds.IsValid(), nil } -// GetValidCredentials returns valid credentials for the default gateway -func GetValidCredentials() (*Credentials, error) { - store, err := LoadCredentials() - if err != nil { - return nil, err - } - - gatewayURL := GetDefaultGatewayURL() - creds, exists := store.GetCredentialsForGateway(gatewayURL) - - if !exists { - return nil, fmt.Errorf("no credentials found for gateway %s", gatewayURL) - } - - if !creds.IsValid() { - return nil, fmt.Errorf("credentials for gateway %s are expired or invalid", gatewayURL) - } - - return creds, nil -} - // SaveCredentialsForDefaultGateway saves credentials for the default gateway func SaveCredentialsForDefaultGateway(creds *Credentials) error { store, err := LoadCredentials() diff --git a/pkg/auth/enhanced_auth.go b/pkg/auth/enhanced_auth.go index 412364a..3e5a057 100644 --- a/pkg/auth/enhanced_auth.go +++ b/pkg/auth/enhanced_auth.go @@ -32,7 +32,7 @@ const ( AuthChoiceExit ) -// LoadEnhancedCredentials loads the enhanced credential store +// LoadEnhancedCredentials loads the enhanced credential store, with migration support from legacy v2.0 format func LoadEnhancedCredentials() (*EnhancedCredentialStore, error) { credPath, err := GetCredentialsPath() if err != nil { @@ -52,39 +52,94 @@ func LoadEnhancedCredentials() (*EnhancedCredentialStore, error) { return nil, fmt.Errorf("failed to read credentials file: %w", err) } - // Try to parse as enhanced store first + // First, try to parse as the proper enhanced store var enhancedStore EnhancedCredentialStore if err := json.Unmarshal(data, &enhancedStore); err == nil && enhancedStore.Version == "2.0" { - // Initialize maps if nil - if enhancedStore.Gateways == nil { - enhancedStore.Gateways = make(map[string]*GatewayCredentials) + // Check if it's already in the enhanced format (has credentials arrays) + hasCredentialsArrays := true + for _, gwCreds := range enhancedStore.Gateways { + if gwCreds == nil || gwCreds.Credentials == nil { + hasCredentialsArrays = false + break + } + } + + if hasCredentialsArrays { + // Already in enhanced format, just sanitize indices + if enhancedStore.Gateways == nil { + enhancedStore.Gateways = make(map[string]*GatewayCredentials) + } + for _, gw := range enhancedStore.Gateways { + if len(gw.Credentials) == 0 { + gw.DefaultIndex = 0 + gw.LastUsedIndex = 0 + continue + } + if gw.DefaultIndex < 0 || gw.DefaultIndex >= len(gw.Credentials) { + gw.DefaultIndex = 0 + } + if gw.LastUsedIndex < 0 || gw.LastUsedIndex >= len(gw.Credentials) { + gw.LastUsedIndex = gw.DefaultIndex + } + } + return &enhancedStore, nil } - return &enhancedStore, nil } - // Fall back to old format and migrate - var oldStore CredentialStore - if err := json.Unmarshal(data, &oldStore); err != nil { - return nil, fmt.Errorf("failed to parse credentials file: %w", err) + // Parse as legacy v2.0 format (single credential per gateway) and migrate + var legacyStore struct { + Gateways map[string]*Credentials `json:"gateways"` + Version string `json:"version"` } - // Migrate old format to new - enhancedStore = EnhancedCredentialStore{ + if err := json.Unmarshal(data, &legacyStore); err != nil { + return nil, fmt.Errorf("invalid credentials file format: %w", err) + } + + if legacyStore.Version != "2.0" { + return nil, fmt.Errorf("unsupported credentials version %q; expected \"2.0\"", legacyStore.Version) + } + + // Convert legacy format to enhanced format + enhanced := &EnhancedCredentialStore{ Gateways: make(map[string]*GatewayCredentials), Version: "2.0", } - for gatewayURL, creds := range oldStore.Gateways { - if creds != nil { - enhancedStore.Gateways[gatewayURL] = &GatewayCredentials{ - Credentials: []*Credentials{creds}, + for gwURL, legacyCred := range legacyStore.Gateways { + if legacyCred == nil { + // Create empty gateway entry + enhanced.Gateways[gwURL] = &GatewayCredentials{ + Credentials: []*Credentials{}, + DefaultIndex: 0, + LastUsedIndex: 0, + } + continue + } + + // Only add if it looks like a valid credential (has wallet or api key) + if legacyCred.Wallet != "" || legacyCred.APIKey != "" { + enhanced.Gateways[gwURL] = &GatewayCredentials{ + Credentials: []*Credentials{legacyCred}, + DefaultIndex: 0, + LastUsedIndex: 0, + } + } else { + // Create empty gateway entry + enhanced.Gateways[gwURL] = &GatewayCredentials{ + Credentials: []*Credentials{}, DefaultIndex: 0, LastUsedIndex: 0, } } } - return &enhancedStore, nil + // Auto-save the migrated format + if err := enhanced.Save(); err != nil { + fmt.Fprintf(os.Stderr, "Warning: failed to save migrated credentials: %v\n", err) + } + + return enhanced, nil } // Save saves the enhanced credential store diff --git a/pkg/node/monitoring.go b/pkg/node/monitoring.go index 4dcddea..602fa72 100644 --- a/pkg/node/monitoring.go +++ b/pkg/node/monitoring.go @@ -3,6 +3,7 @@ package node import ( "context" "encoding/json" + "errors" "time" "github.com/libp2p/go-libp2p/core/peer" @@ -44,16 +45,37 @@ func logDetailedPeerInfo(n *Node, currentPeerCount int, peers []peer.ID) { } } +func GetCPUUsagePercent(n *Node, interval time.Duration) (uint64, error) { + before, err := cpu.Get() + if err != nil { + return 0, err + } + time.Sleep(interval) + after, err := cpu.Get() + if err != nil { + return 0, err + } + idle := float64(after.Idle - before.Idle) + total := float64(after.Total - before.Total) + if total == 0 { + return 0, errors.New("Failed to get CPU usage") + } + usagePercent := (1.0 - idle/total) * 100.0 + return uint64(usagePercent), nil +} + func logSystemUsage(n *Node) (*memory.Stats, uint64) { mem, _ := memory.Get() - cpuBefore, _ := cpu.Get() - time.Sleep(3 * time.Second) - cpuAfter, _ := cpu.Get() - totalCpu := cpuAfter.Total - cpuBefore.Total + + totalCpu, err := GetCPUUsagePercent(n, 3*time.Second) + if err != nil { + n.logger.Error("Failed to get CPU usage", zap.Error(err)) + return mem, 0 + } n.logger.Debug("Node CPU usage", zap.Float64("cpu_usage", float64(totalCpu)), - zap.Float64("memory_usage", float64(mem.Used))) + zap.Float64("memory_usage_percent", float64(mem.Used)/float64(mem.Total)*100)) return mem, totalCpu }