diff --git a/core/cli/api/p2p.go b/core/cli/api/p2p.go
index a2ecfe3febd7..0dd6ecde4800 100644
--- a/core/cli/api/p2p.go
+++ b/core/cli/api/p2p.go
@@ -8,12 +8,13 @@ import (
"strings"
"github.com/mudler/LocalAI/core/p2p"
+ p2pConfig "github.com/mudler/edgevpn/pkg/config"
"github.com/mudler/edgevpn/pkg/node"
"github.com/rs/zerolog/log"
)
-func StartP2PStack(ctx context.Context, address, token, networkID string, federated bool) error {
+func StartP2PStack(ctx context.Context, p2pCfg p2pConfig.Config, address, networkID string, federated bool) error {
var n *node.Node
// Here we are avoiding creating multiple nodes:
// - if the federated mode is enabled, we create a federated node and expose a service
@@ -29,12 +30,12 @@ func StartP2PStack(ctx context.Context, address, token, networkID string, federa
// Here a new node is created and started
// and a service is exposed by the node
- node, err := p2p.ExposeService(ctx, "localhost", port, token, p2p.NetworkID(networkID, p2p.FederatedID))
+ node, err := p2p.ExposeService(ctx, p2pCfg, "localhost", port, p2p.NetworkID(networkID, p2p.FederatedID))
if err != nil {
return err
}
- if err := p2p.ServiceDiscoverer(ctx, node, token, p2p.NetworkID(networkID, p2p.FederatedID), nil, false); err != nil {
+ if err := p2p.ServiceDiscoverer(ctx, node, p2p.NetworkID(networkID, p2p.FederatedID), nil, false); err != nil {
return err
}
@@ -42,10 +43,10 @@ func StartP2PStack(ctx context.Context, address, token, networkID string, federa
}
// If the p2p mode is enabled, we start the service discovery
- if token != "" {
+ if p2pCfg.NetworkToken != "" {
// If a node wasn't created previously, create it
if n == nil {
- node, err := p2p.NewNode(token)
+ node, err := p2p.NewNode(p2pCfg)
if err != nil {
return err
}
@@ -58,7 +59,7 @@ func StartP2PStack(ctx context.Context, address, token, networkID string, federa
// Attach a ServiceDiscoverer to the p2p node
log.Info().Msg("Starting P2P server discovery...")
- if err := p2p.ServiceDiscoverer(ctx, n, token, p2p.NetworkID(networkID, p2p.WorkerID), func(serviceID string, node p2p.NodeData) {
+ if err := p2p.ServiceDiscoverer(ctx, n, p2p.NetworkID(networkID, p2p.WorkerID), func(serviceID string, node p2p.NodeData) {
var tunnelAddresses []string
for _, v := range p2p.GetAvailableNodes(p2p.NetworkID(networkID, p2p.WorkerID)) {
if v.IsOnline() {
diff --git a/core/cli/explorer.go b/core/cli/explorer.go
index 67d25304165d..9e35c3b2ea88 100644
--- a/core/cli/explorer.go
+++ b/core/cli/explorer.go
@@ -5,11 +5,14 @@ import (
"time"
cliContext "github.com/mudler/LocalAI/core/cli/context"
+ cliP2P "github.com/mudler/LocalAI/core/cli/p2p"
"github.com/mudler/LocalAI/core/explorer"
"github.com/mudler/LocalAI/core/http"
)
type ExplorerCMD struct {
+ cliP2P.P2PCommonFlags `embed:""`
+
Address string `env:"LOCALAI_ADDRESS,ADDRESS" default:":8080" help:"Bind address for the API server" group:"api"`
PoolDatabase string `env:"LOCALAI_POOL_DATABASE,POOL_DATABASE" default:"explorer.json" help:"Path to the pool database" group:"api"`
ConnectionTimeout string `env:"LOCALAI_CONNECTION_TIMEOUT,CONNECTION_TIMEOUT" default:"2m" help:"Connection timeout for the explorer" group:"api"`
@@ -33,14 +36,14 @@ func (e *ExplorerCMD) Run(ctx *cliContext.Context) error {
if e.WithSync {
ds := explorer.NewDiscoveryServer(db, dur, e.ConnectionErrorThreshold)
- go ds.Start(context.Background(), true)
+ go ds.Start(context.Background(), e.P2PCommonFlags, true)
}
if e.OnlySync {
ds := explorer.NewDiscoveryServer(db, dur, e.ConnectionErrorThreshold)
ctx := context.Background()
- return ds.Start(ctx, false)
+ return ds.Start(ctx, e.P2PCommonFlags, false)
}
appHTTP := http.Explorer(db)
diff --git a/core/cli/federated.go b/core/cli/federated.go
index b917812ce5a8..8e5cfdccba52 100644
--- a/core/cli/federated.go
+++ b/core/cli/federated.go
@@ -2,22 +2,43 @@ package cli
import (
"context"
+ "fmt"
cliContext "github.com/mudler/LocalAI/core/cli/context"
+ cliP2P "github.com/mudler/LocalAI/core/cli/p2p"
"github.com/mudler/LocalAI/core/p2p"
+ "github.com/rs/zerolog/log"
)
type FederatedCLI struct {
- Address string `env:"LOCALAI_ADDRESS,ADDRESS" default:":8080" help:"Bind address for the API server" group:"api"`
- Peer2PeerToken string `env:"LOCALAI_P2P_TOKEN,P2P_TOKEN,TOKEN" name:"p2ptoken" help:"Token for P2P mode (optional)" group:"p2p"`
- RandomWorker bool `env:"LOCALAI_RANDOM_WORKER,RANDOM_WORKER" default:"false" help:"Select a random worker from the pool" group:"p2p"`
- Peer2PeerNetworkID string `env:"LOCALAI_P2P_NETWORK_ID,P2P_NETWORK_ID" help:"Network ID for P2P mode, can be set arbitrarly by the user for grouping a set of instances." group:"p2p"`
- TargetWorker string `env:"LOCALAI_TARGET_WORKER,TARGET_WORKER" help:"Target worker to run the federated server on" group:"p2p"`
+ cliP2P.P2PCommonFlags `embed:""`
+
+ Address string `env:"LOCALAI_ADDRESS,ADDRESS" default:":8080" help:"Bind address for the API server" group:"api"`
+ RandomWorker bool `env:"LOCALAI_RANDOM_WORKER,RANDOM_WORKER" default:"false" help:"Select a random worker from the pool" group:"p2p"`
+ TargetWorker string `env:"LOCALAI_TARGET_WORKER,TARGET_WORKER" help:"Target worker to run the federated server on" group:"p2p"`
}
func (f *FederatedCLI) Run(ctx *cliContext.Context) error {
+ if f.Peer2PeerToken == "" {
+ log.Info().Msg("No token provided, generating one")
+ connectionData, err := p2p.GenerateNewConnectionData(
+ f.Peer2PeerDHTInterval, f.Peer2PeerOTPInterval,
+ f.Peer2PeerPrivkey, f.Peer2PeerUsePeerguard,
+ )
+ if err != nil {
+ log.Warn().Msgf("Error generating token: %s", err.Error())
+ }
+ f.Peer2PeerToken = connectionData.Base64()
+
+ log.Info().Msg("Generated Token:")
+ fmt.Println(f.Peer2PeerToken)
+
+ log.Info().Msg("To use the token, you can run the following command in another node or terminal:")
+ fmt.Printf("export TOKEN=\"%s\"\nlocal-ai worker p2p-llama-cpp-rpc\n", f.Peer2PeerToken)
+ }
+
fs := p2p.NewFederatedServer(f.Address, p2p.NetworkID(f.Peer2PeerNetworkID, p2p.FederatedID), f.Peer2PeerToken, !f.RandomWorker, f.TargetWorker)
- return fs.Start(context.Background())
+ return fs.Start(context.Background(), f.P2PCommonFlags)
}
diff --git a/core/cli/p2p/p2p.go b/core/cli/p2p/p2p.go
new file mode 100644
index 000000000000..74a442641ac7
--- /dev/null
+++ b/core/cli/p2p/p2p.go
@@ -0,0 +1,17 @@
+package cli
+
+type P2PCommonFlags struct {
+ Peer2PeerNoDHT bool `env:"LOCALAI_P2P_DISABLE_DHT,P2P_DISABLE_DHT" name:"p2p-disable-dht" help:"Disable DHT" group:"p2p"`
+ Peer2PeerLimit bool `env:"LOCALAI_P2P_ENABLE_LIMITS,P2P_ENABLE_LIMITS" name:"p2p-enable-limits" help:"Enable Limits" group:"p2p"`
+ Peer2PeerListenAddrs []string `env:"LOCALAI_P2P_LISTEN_MADDRS,P2P_LISTEN_MADDRS" name:"p2p-listen-maddrs" help:"A list of listen multiaddresses" group:"p2p"`
+ Peer2PeerBootAddrs []string `env:"LOCALAI_P2P_BOOTSTRAP_PEERS_MADDRS,P2P_BOOTSTRAP_PEERS_MADDRS" name:"p2p-bootstrap-peers-maddrs" help:"A list of bootstrap peers multiaddresses" group:"p2p"`
+ Peer2PeerDHTAnnounceAddrs []string `env:"LOCALAI_P2P_DHT_ANNOUNCE_MADDRS,P2P_DHT_ANNOUNCE_MADDRS" name:"p2p-dht-announce-maddrs" help:"A list of DHT announce maddrs" group:"p2p"`
+ Peer2PeerLibLoglevel string `env:"LOCALAI_P2P_LIB_LOGLEVEL,P2P_LIB_LOGLEVEL" name:"p2p-lib-loglevel" help:"libp2p specific loglevel" group:"p2p"`
+ Peer2PeerDHTInterval int `env:"LOCALAI_P2P_DHT_INTERVAL,P2P_DHT_INTERVAL" default:"360" name:"p2p-dht-interval" help:"Interval for DHT refresh (used during token generation)" group:"p2p"`
+ Peer2PeerOTPInterval int `env:"LOCALAI_P2P_OTP_INTERVAL,P2P_OTP_INTERVAL" default:"9000" name:"p2p-otp-interval" help:"Interval for OTP refresh (used during token generation)" group:"p2p"`
+ Peer2PeerToken string `env:"LOCALAI_P2P_TOKEN,P2P_TOKEN,TOKEN" name:"p2ptoken" help:"Token for P2P mode (optional)" group:"p2p"`
+ Peer2PeerPrivkey string `env:"LOCALAI_P2P_PRIVKEY,P2P_PRIVKEY" name:"p2pprivkey" help:"A base64 encoded protobuf serialized private key used for fixed ID (edgevpn can be used for generating one)" group:"p2p"`
+ Peer2PeerUsePeerguard bool `env:"LOCALAI_P2P_PEERGUARD,P2P_PEERGUARD" name:"p2ppeerguard" help:"Enable peerguarding through ecdsa authorization of nodes" group:"p2p"`
+ Peer2PeerAuthProvders string `env:"LOCALAI_P2P_PEERGATE_AUTH,P2P_PEERGATE_AUTH" name:"p2pauth" help:"JSON dict string with '{authProviderName: {providerOpt: value}}' structure, see edgevpn project" group:"p2p"`
+ Peer2PeerNetworkID string `env:"LOCALAI_P2P_NETWORK_ID,P2P_NETWORK_ID" help:"Network ID for P2P mode, can be set arbitrarly by the user for grouping a set of instances" group:"p2p"`
+}
diff --git a/core/cli/run.go b/core/cli/run.go
index 3162ef1452e4..d058f013c78f 100644
--- a/core/cli/run.go
+++ b/core/cli/run.go
@@ -9,6 +9,7 @@ import (
"github.com/mudler/LocalAI/core/application"
cli_api "github.com/mudler/LocalAI/core/cli/api"
cliContext "github.com/mudler/LocalAI/core/cli/context"
+ cliP2P "github.com/mudler/LocalAI/core/cli/p2p"
"github.com/mudler/LocalAI/core/config"
"github.com/mudler/LocalAI/core/http"
"github.com/mudler/LocalAI/core/p2p"
@@ -55,10 +56,7 @@ type RunCMD struct {
DisableMetricsEndpoint bool `env:"LOCALAI_DISABLE_METRICS_ENDPOINT,DISABLE_METRICS_ENDPOINT" default:"false" help:"Disable the /metrics endpoint" group:"api"`
HttpGetExemptedEndpoints []string `env:"LOCALAI_HTTP_GET_EXEMPTED_ENDPOINTS" default:"^/$,^/browse/?$,^/talk/?$,^/p2p/?$,^/chat/?$,^/text2image/?$,^/tts/?$,^/static/.*$,^/swagger.*$" help:"If LOCALAI_DISABLE_API_KEY_REQUIREMENT_FOR_HTTP_GET is overriden to true, this is the list of endpoints to exempt. Only adjust this in case of a security incident or as a result of a personal security posture review" group:"hardening"`
Peer2Peer bool `env:"LOCALAI_P2P,P2P" name:"p2p" default:"false" help:"Enable P2P mode" group:"p2p"`
- Peer2PeerDHTInterval int `env:"LOCALAI_P2P_DHT_INTERVAL,P2P_DHT_INTERVAL" default:"360" name:"p2p-dht-interval" help:"Interval for DHT refresh (used during token generation)" group:"p2p"`
- Peer2PeerOTPInterval int `env:"LOCALAI_P2P_OTP_INTERVAL,P2P_OTP_INTERVAL" default:"9000" name:"p2p-otp-interval" help:"Interval for OTP refresh (used during token generation)" group:"p2p"`
- Peer2PeerToken string `env:"LOCALAI_P2P_TOKEN,P2P_TOKEN,TOKEN" name:"p2ptoken" help:"Token for P2P mode (optional)" group:"p2p"`
- Peer2PeerNetworkID string `env:"LOCALAI_P2P_NETWORK_ID,P2P_NETWORK_ID" help:"Network ID for P2P mode, can be set arbitrarly by the user for grouping a set of instances" group:"p2p"`
+ cliP2P.P2PCommonFlags `embed:""`
ParallelRequests bool `env:"LOCALAI_PARALLEL_REQUESTS,PARALLEL_REQUESTS" help:"Enable backends to handle multiple requests in parallel if they support it (e.g.: llama.cpp or vllm)" group:"backends"`
SingleActiveBackend bool `env:"LOCALAI_SINGLE_ACTIVE_BACKEND,SINGLE_ACTIVE_BACKEND" help:"Allow only one backend to be run at a time" group:"backends"`
PreloadBackendOnly bool `env:"LOCALAI_PRELOAD_BACKEND_ONLY,PRELOAD_BACKEND_ONLY" default:"false" help:"Do not launch the API services, only the preloaded models / backends are started (useful for multi-node setups)" group:"backends"`
@@ -114,14 +112,24 @@ func (r *RunCMD) Run(ctx *cliContext.Context) error {
}
token := ""
+ p2pCfg := p2p.NewP2PConfig(r.P2PCommonFlags)
if r.Peer2Peer || r.Peer2PeerToken != "" {
+
log.Info().Msg("P2P mode enabled")
token = r.Peer2PeerToken
if token == "" {
// IF no token is provided, and p2p is enabled,
// we generate one and wait for the user to pick up the token (this is for interactive)
log.Info().Msg("No token provided, generating one")
- token = p2p.GenerateToken(r.Peer2PeerDHTInterval, r.Peer2PeerOTPInterval)
+ connectionData, err := p2p.GenerateNewConnectionData(
+ r.Peer2PeerDHTInterval, r.Peer2PeerOTPInterval,
+ r.Peer2PeerPrivkey, r.Peer2PeerUsePeerguard,
+ )
+ if err != nil {
+ log.Warn().Msgf("Error generating token: %s", err.Error())
+ }
+ token = connectionData.Base64()
+
log.Info().Msg("Generated Token:")
fmt.Println(token)
@@ -129,11 +137,13 @@ func (r *RunCMD) Run(ctx *cliContext.Context) error {
fmt.Printf("export TOKEN=\"%s\"\nlocal-ai worker p2p-llama-cpp-rpc\n", token)
}
opts = append(opts, config.WithP2PToken(token))
+
+ p2pCfg.NetworkToken = token
}
backgroundCtx := context.Background()
- if err := cli_api.StartP2PStack(backgroundCtx, r.Address, token, r.Peer2PeerNetworkID, r.Federated); err != nil {
+ if err := cli_api.StartP2PStack(backgroundCtx, p2pCfg, r.Address, r.Peer2PeerNetworkID, r.Federated); err != nil {
return err
}
diff --git a/core/cli/worker/worker_p2p.go b/core/cli/worker/worker_p2p.go
index aa7a8f1abb9e..de551b852092 100644
--- a/core/cli/worker/worker_p2p.go
+++ b/core/cli/worker/worker_p2p.go
@@ -12,6 +12,7 @@ import (
"time"
cliContext "github.com/mudler/LocalAI/core/cli/context"
+ cliP2P "github.com/mudler/LocalAI/core/cli/p2p"
"github.com/mudler/LocalAI/core/p2p"
"github.com/mudler/LocalAI/pkg/assets"
"github.com/mudler/LocalAI/pkg/library"
@@ -20,12 +21,13 @@ import (
)
type P2P struct {
- WorkerFlags `embed:""`
- Token string `env:"LOCALAI_TOKEN,LOCALAI_P2P_TOKEN,TOKEN" help:"P2P token to use"`
- NoRunner bool `env:"LOCALAI_NO_RUNNER,NO_RUNNER" help:"Do not start the llama-cpp-rpc-server"`
- RunnerAddress string `env:"LOCALAI_RUNNER_ADDRESS,RUNNER_ADDRESS" help:"Address of the llama-cpp-rpc-server"`
- RunnerPort string `env:"LOCALAI_RUNNER_PORT,RUNNER_PORT" help:"Port of the llama-cpp-rpc-server"`
- Peer2PeerNetworkID string `env:"LOCALAI_P2P_NETWORK_ID,P2P_NETWORK_ID" help:"Network ID for P2P mode, can be set arbitrarly by the user for grouping a set of instances" group:"p2p"`
+ WorkerFlags `embed:""`
+ cliP2P.P2PCommonFlags `embed:""`
+
+ Token string `env:"LOCALAI_TOKEN,LOCALAI_P2P_TOKEN,TOKEN" help:"P2P token to use"`
+ NoRunner bool `env:"LOCALAI_NO_RUNNER,NO_RUNNER" help:"Do not start the llama-cpp-rpc-server"`
+ RunnerAddress string `env:"LOCALAI_RUNNER_ADDRESS,RUNNER_ADDRESS" help:"Address of the llama-cpp-rpc-server"`
+ RunnerPort string `env:"LOCALAI_RUNNER_PORT,RUNNER_PORT" help:"Port of the llama-cpp-rpc-server"`
}
func (r *P2P) Run(ctx *cliContext.Context) error {
@@ -41,6 +43,8 @@ func (r *P2P) Run(ctx *cliContext.Context) error {
if r.Token == "" {
return fmt.Errorf("Token is required")
}
+ p2pCfg := p2p.NewP2PConfig(r.P2PCommonFlags)
+ p2pCfg.NetworkToken = r.Token
port, err := freeport.GetFreePort()
if err != nil {
@@ -60,7 +64,7 @@ func (r *P2P) Run(ctx *cliContext.Context) error {
p = r.RunnerPort
}
- _, err = p2p.ExposeService(context.Background(), address, p, r.Token, p2p.NetworkID(r.Peer2PeerNetworkID, p2p.WorkerID))
+ _, err = p2p.ExposeService(context.Background(), p2pCfg, address, p, p2p.NetworkID(r.Peer2PeerNetworkID, p2p.WorkerID))
if err != nil {
return err
}
@@ -103,7 +107,7 @@ func (r *P2P) Run(ctx *cliContext.Context) error {
}
}()
- _, err = p2p.ExposeService(context.Background(), address, fmt.Sprint(port), r.Token, p2p.NetworkID(r.Peer2PeerNetworkID, p2p.WorkerID))
+ _, err = p2p.ExposeService(context.Background(), p2pCfg, address, fmt.Sprint(port), p2p.NetworkID(r.Peer2PeerNetworkID, p2p.WorkerID))
if err != nil {
return err
}
diff --git a/core/explorer/discovery.go b/core/explorer/discovery.go
index fe6470cb825d..296c92658e37 100644
--- a/core/explorer/discovery.go
+++ b/core/explorer/discovery.go
@@ -9,6 +9,7 @@ import (
"github.com/rs/zerolog/log"
+ cliP2P "github.com/mudler/LocalAI/core/cli/p2p"
"github.com/mudler/LocalAI/core/p2p"
"github.com/mudler/edgevpn/pkg/blockchain"
)
@@ -40,7 +41,7 @@ type Network struct {
Clusters []ClusterData
}
-func (s *DiscoveryServer) runBackground() {
+func (s *DiscoveryServer) runBackground(p2pCommonFlags cliP2P.P2PCommonFlags) {
if len(s.database.TokenList()) == 0 {
time.Sleep(5 * time.Second) // avoid busy loop
return
@@ -50,11 +51,14 @@ func (s *DiscoveryServer) runBackground() {
c, cancel := context.WithTimeout(context.Background(), s.connectionTime)
defer cancel()
+ p2pCfg := p2p.NewP2PConfig(p2pCommonFlags)
+ p2pCfg.NetworkToken = token
+
// Connect to the network
// Get the number of nodes
// save it in the current state (mutex)
// do not do in parallel
- n, err := p2p.NewNode(token)
+ n, err := p2p.NewNode(p2pCfg)
if err != nil {
log.Err(err).Msg("Failed to create node")
s.failedToken(token)
@@ -197,14 +201,14 @@ func (s *DiscoveryServer) retrieveNetworkData(c context.Context, ledger *blockch
}
// Start the discovery server. This is meant to be run in to a goroutine.
-func (s *DiscoveryServer) Start(ctx context.Context, keepRunning bool) error {
+func (s *DiscoveryServer) Start(ctx context.Context, p2pCommonFlags cliP2P.P2PCommonFlags, keepRunning bool) error {
for {
select {
case <-ctx.Done():
return fmt.Errorf("context cancelled")
default:
// Collect data
- s.runBackground()
+ s.runBackground(p2pCommonFlags)
if !keepRunning {
return nil
}
diff --git a/core/p2p/federated_server.go b/core/p2p/federated_server.go
index d80af082c94f..81fccaa3cc33 100644
--- a/core/p2p/federated_server.go
+++ b/core/p2p/federated_server.go
@@ -4,18 +4,43 @@
package p2p
import (
+ "bufio"
"context"
+ "encoding/json"
"errors"
"fmt"
"io"
"net"
+ "net/http"
+ "slices"
+ "strings"
+ "time"
+ logP2P "github.com/ipfs/go-log/v2"
+ cliP2P "github.com/mudler/LocalAI/core/cli/p2p"
+ edgevpnConfig "github.com/mudler/edgevpn/pkg/config"
+ "github.com/mudler/edgevpn/pkg/logger"
"github.com/mudler/edgevpn/pkg/node"
+ "github.com/mudler/edgevpn/pkg/trustzone"
"github.com/rs/zerolog/log"
)
-func (f *FederatedServer) Start(ctx context.Context) error {
- n, err := NewNode(f.p2ptoken)
+const Timeout = 20 * time.Second
+
+const (
+ peekBufferSize = 512
+ authHeader = "X-Auth-Token"
+ headerEnd = "\r\n\r\n"
+ lineEnd = "\r\n"
+)
+
+func (fs *FederatedServer) Start(ctx context.Context, p2pCommonFlags cliP2P.P2PCommonFlags) error {
+ p2pCfg := NewP2PConfig(p2pCommonFlags)
+ p2pCfg.NetworkToken = fs.p2ptoken
+ p2pCfg.PeerGuard.Autocleanup = true
+ p2pCfg.PeerGuard.PeerGate = true
+
+ n, err := NewNode(p2pCfg)
if err != nil {
return fmt.Errorf("creating a new node: %w", err)
}
@@ -24,17 +49,32 @@ func (f *FederatedServer) Start(ctx context.Context) error {
return fmt.Errorf("creating a new node: %w", err)
}
- if err := ServiceDiscoverer(ctx, n, f.p2ptoken, f.service, func(servicesID string, tunnel NodeData) {
+ if err := ServiceDiscoverer(ctx, n, fs.service, func(servicesID string, tunnel NodeData) {
log.Debug().Msgf("Discovered node: %s", tunnel.ID)
}, false); err != nil {
return err
}
- return f.proxy(ctx, n)
-}
+ lvl, err := logP2P.LevelFromString(p2pCfg.LogLevel)
+ if err != nil {
+ lvl = logP2P.LevelError
+ }
+ llger := logger.New(lvl)
-func (fs *FederatedServer) proxy(ctx context.Context, node *node.Node) error {
+ aps := []trustzone.AuthProvider{}
+ for ap, providerOpts := range p2pCfg.PeerGuard.AuthProviders {
+ a, err := edgevpnConfig.AuthProvider(llger, ap, providerOpts)
+ if err != nil {
+ log.Warn().Msgf("invalid authprovider: %v", err)
+ continue
+ }
+ aps = append(aps, a)
+ }
+
+ return fs.listener(ctx, n, aps)
+}
+func (fs *FederatedServer) listener(ctx context.Context, node *node.Node, aps []trustzone.AuthProvider) error {
log.Info().Msgf("Allocating service '%s' on: %s", fs.service, fs.listenAddr)
// Open local port for listening
l, err := net.Listen("tcp", fs.listenAddr)
@@ -51,6 +91,7 @@ func (fs *FederatedServer) proxy(ctx context.Context, node *node.Node) error {
nodeAnnounce(ctx, node)
defer l.Close()
+
for {
select {
case <-ctx.Done():
@@ -64,62 +105,243 @@ func (fs *FederatedServer) proxy(ctx context.Context, node *node.Node) error {
continue
}
- // Handle connections in a new goroutine, forwarding to the p2p service
go func() {
- workerID := ""
- if fs.workerTarget != "" {
- workerID = fs.workerTarget
- } else if fs.loadBalanced {
- log.Debug().Msgf("Load balancing request")
-
- workerID = fs.SelectLeastUsedServer()
- if workerID == "" {
- log.Debug().Msgf("Least used server not found, selecting random")
- workerID = fs.RandomServer()
+ if len(aps) > 0 {
+ if fs.handleHTTP(conn, node, aps) {
+ return
}
- } else {
- workerID = fs.RandomServer()
}
+ fs.proxy(ctx, node, conn)
+ }()
+ }
+ }
+}
- if workerID == "" {
- log.Error().Msg("No available nodes yet")
- fs.sendHTMLResponse(conn, 503, "Sorry, waiting for nodes to connect")
- return
- }
+func (fs *FederatedServer) handleHTTP(conn net.Conn, node *node.Node, aps []trustzone.AuthProvider) bool {
+ defer func() {
+ if r := recover(); r != nil {
+ log.Debug().Msgf("Recovered from panic: %v", r)
+ conn.Close()
+ }
+ }()
- log.Debug().Msgf("Selected node %s", workerID)
- nodeData, exists := GetNode(fs.service, workerID)
- if !exists {
- log.Error().Msgf("Node %s not found", workerID)
- fs.sendHTMLResponse(conn, 404, "Node not found")
- return
- }
+ r, err := testForHTTPRequest(conn)
+ if err != nil {
+ return false
+ }
+ defer r.Body.Close()
+ pathParts := strings.Split(strings.TrimPrefix(r.URL.Path, "/ledger/"), "/")
+ announcing := struct{ State string }{"Announcing"}
+
+ // TODO deal with AuthProviders
+ // pubKey := r.Header.Get(authHeader)
+
+ switch r.Method {
+ case http.MethodGet:
+ switch len(pathParts) {
+ case 2: // /ledger/:bucket/:key
+ bucket := pathParts[0]
+ key := pathParts[1]
+
+ ledger, err := node.Ledger()
+ if err != nil {
+ fs.sendRawResponse(conn, http.StatusInternalServerError, "text/plain", []byte(err.Error()))
+ return true
+ }
+
+ fs.sendJSONResponse(conn, http.StatusOK, ledger.CurrentData()[bucket][key])
+
+ case 1: // /ledger/:bucket
+ bucket := pathParts[0]
+
+ ledger, err := node.Ledger()
+ if err != nil {
+ fs.sendRawResponse(conn, http.StatusInternalServerError, "text/plain", []byte(err.Error()))
+ return true
+ }
+
+ fs.sendJSONResponse(conn, http.StatusOK, ledger.CurrentData()[bucket])
+
+ default:
+ fs.sendRawResponse(conn, http.StatusNotFound, "text/plain", []byte("not found"))
+
+ }
+
+ case http.MethodPut:
+ if len(pathParts) == 3 { // /ledger/:bucket/:key/:value
+ bucket := pathParts[0]
+ key := pathParts[1]
+ value := pathParts[2]
+
+ ledger, err := node.Ledger()
+ if err != nil {
+ fs.sendRawResponse(conn, http.StatusInternalServerError, "text/plain", []byte(err.Error()))
+ return true
+ }
+
+ ledger.Persist(context.Background(), DefaultInterval, Timeout, bucket, key, value)
+ fs.sendJSONResponse(conn, http.StatusOK, announcing)
+
+ } else {
+ fs.sendRawResponse(conn, http.StatusNotFound, "text/plain", []byte("not found"))
+ }
+
+ case http.MethodDelete:
+ switch len(pathParts) {
+ case 1: // /ledger/:bucket
+ bucket := pathParts[0]
+
+ ledger, err := node.Ledger()
+ if err != nil {
+ fs.sendRawResponse(conn, http.StatusInternalServerError, "text/plain", []byte(err.Error()))
+ return true
+ }
+
+ ledger.AnnounceDeleteBucket(context.Background(), DefaultInterval, Timeout, bucket)
+ fs.sendJSONResponse(conn, http.StatusOK, announcing)
+
+ case 2: // /ledger/:bucket/:key
+ bucket := pathParts[0]
+ key := pathParts[1]
+
+ ledger, err := node.Ledger()
+ if err != nil {
+ fs.sendRawResponse(conn, http.StatusInternalServerError, "text/plain", []byte(err.Error()))
+ return true
+ }
+
+ ledger.AnnounceDeleteBucketKey(context.Background(), DefaultInterval, Timeout, bucket, key)
+ fs.sendJSONResponse(conn, http.StatusOK, announcing)
+
+ default:
+ fs.sendRawResponse(conn, http.StatusNotFound, "text/plain", []byte("not found"))
- proxyP2PConnection(ctx, node, nodeData.ServiceID, conn)
- if fs.loadBalanced {
- fs.RecordRequest(workerID)
- }
- }()
}
}
+
+ return true
}
-// sendHTMLResponse sends a basic HTML response with a status code and a message.
-// This is extracted to make the HTML content maintainable.
-func (fs *FederatedServer) sendHTMLResponse(conn net.Conn, statusCode int, message string) {
- defer conn.Close()
+// testForHTTPRequest peeking the first N bytes from the accepted conn, and trying to match it
+// against the supported http methods, then against the supported route, then if there is auth header
+func testForHTTPRequest(conn net.Conn) (*http.Request, error) {
+ reader := bufio.NewReader(conn)
- // Define the HTML content separately for easier maintenance.
- htmlContent := fmt.Sprintf("
%s
\r\n", message)
+ peekedData, err := reader.Peek(peekBufferSize)
+ if err != nil && err != bufio.ErrBufferFull {
+ log.Debug().Msgf("Error peeking data: %v", err)
+ return nil, err
+ }
+ peekedString := string(peekedData)
+
+ // 1. Parse Request Line
+ firstLineEnd := strings.Index(peekedString, lineEnd)
+ if firstLineEnd == -1 {
+ log.Debug().Msg("Could not find request line end")
+ return nil, err
+ }
+ requestLine := peekedString[:firstLineEnd]
+ parts := strings.Split(requestLine, " ")
+ if len(parts) != 3 {
+ log.Debug().Msg("Invalid request line format")
+ return nil, err
+ }
+ method := parts[0]
+ uri := parts[1]
+
+ if !slices.Contains([]string{
+ http.MethodGet,
+ http.MethodPut,
+ http.MethodDelete,
+ }, method) {
+ log.Debug().Msg("Unsupported HTTP method")
+ return nil, err
+ }
+ if !strings.HasPrefix(uri, "/ledger") {
+ log.Debug().Msg("Unsupported HTTP route")
+ return nil, err
+ }
+
+ headersPart := peekedString[firstLineEnd+len(lineEnd):]
+ headerEndIndex := strings.Index(headersPart, headerEnd)
+ if headerEndIndex == -1 {
+ log.Debug().Msg("Could not find end of headers within peek buffer")
+ return nil, err
+ }
+ headersString := headersPart[:headerEndIndex]
+ headers := strings.Split(headersString, lineEnd)
+
+ foundAuth := false
+ for _, header := range headers {
+ if strings.HasPrefix(header, authHeader+":") {
+ parts := strings.SplitN(header, ":", 2)
+ if len(parts) == 2 {
+ foundAuth = true
+ break
+ }
+ }
+ }
+
+ if !foundAuth {
+ log.Debug().Msgf("Required header '%s' not found.", authHeader)
+ return nil, err
+ }
+
+ req, err := http.ReadRequest(reader)
+ if err != nil {
+ log.Debug().Msgf("Error reading full request: %v", err)
+ return nil, err
+ }
+ return req, nil
+}
+
+func (fs *FederatedServer) proxy(ctx context.Context, node *node.Node, conn net.Conn) {
+ workerID := ""
+ if fs.workerTarget != "" {
+ workerID = fs.workerTarget
+ } else if fs.loadBalanced {
+ log.Debug().Msgf("Load balancing request")
+
+ workerID = fs.SelectLeastUsedServer()
+ if workerID == "" {
+ log.Debug().Msgf("Least used server not found, selecting random")
+ workerID = fs.RandomServer()
+ }
+ } else {
+ workerID = fs.RandomServer()
+ }
+
+ if workerID == "" {
+ log.Error().Msg("No available nodes yet")
+ fs.sendHTMLResponse(conn, 503, "Sorry, waiting for nodes to connect")
+ return
+ }
+
+ log.Debug().Msgf("Selected node %s", workerID)
+ nodeData, exists := GetNode(fs.service, workerID)
+ if !exists {
+ log.Error().Msgf("Node %s not found", workerID)
+ fs.sendHTMLResponse(conn, 404, "Node not found")
+ return
+ }
+
+ proxyP2PConnection(ctx, node, nodeData.ServiceID, conn)
+ if fs.loadBalanced {
+ fs.RecordRequest(workerID)
+ }
+}
+
+// sendRawResponse sends whatever provided byte data with provided content type header
+func (fs *FederatedServer) sendRawResponse(conn net.Conn, statusCode int, contentType string, data []byte) {
+ defer conn.Close()
- // Create the HTTP response with dynamic status code and content.
response := fmt.Sprintf(
"HTTP/1.1 %d %s\r\n"+
- "Content-Type: text/html\r\n"+
+ "Content-Type: %s\r\n"+
"Connection: close\r\n"+
"\r\n"+
"%s",
- statusCode, getHTTPStatusText(statusCode), htmlContent,
+ statusCode, http.StatusText(statusCode), contentType, data,
)
// Write the response to the client connection.
@@ -129,16 +351,21 @@ func (fs *FederatedServer) sendHTMLResponse(conn net.Conn, statusCode int, messa
}
}
-// getHTTPStatusText returns a textual representation of HTTP status codes.
-func getHTTPStatusText(statusCode int) string {
- switch statusCode {
- case 503:
- return "Service Unavailable"
- case 404:
- return "Not Found"
- case 200:
- return "OK"
- default:
- return "Unknown Status"
+// sendJSONResponse marshals provided data to JSON and sends it
+func (fs *FederatedServer) sendJSONResponse(conn net.Conn, statusCode int, v any) {
+ data, err := json.Marshal(v)
+ if err != nil {
+ log.Error().Err(err).Msg("Error JSON marshaling")
}
+
+ fs.sendRawResponse(conn, statusCode, "application/json", data)
+}
+
+// sendHTMLResponse sends a basic HTML response with a status code and a message.
+// This is extracted to make the HTML content maintainable.
+func (fs *FederatedServer) sendHTMLResponse(conn net.Conn, statusCode int, message string) {
+ // Define the HTML content separately for easier maintenance.
+ htmlContent := fmt.Sprintf("%s
\r\n", message)
+
+ fs.sendRawResponse(conn, statusCode, "text/html", []byte(htmlContent))
}
diff --git a/core/p2p/p2p.go b/core/p2p/p2p.go
index ce0dcc07ad43..d2d47aea20b7 100644
--- a/core/p2p/p2p.go
+++ b/core/p2p/p2p.go
@@ -5,32 +5,35 @@ package p2p
import (
"context"
+ "encoding/json"
"errors"
"fmt"
"io"
"net"
"os"
- "strings"
"sync"
"time"
"github.com/ipfs/go-log"
+ "github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
+ cliP2P "github.com/mudler/LocalAI/core/cli/p2p"
"github.com/mudler/LocalAI/pkg/utils"
- "github.com/mudler/edgevpn/pkg/config"
+ p2pConfig "github.com/mudler/edgevpn/pkg/config"
"github.com/mudler/edgevpn/pkg/node"
"github.com/mudler/edgevpn/pkg/protocol"
"github.com/mudler/edgevpn/pkg/services"
"github.com/mudler/edgevpn/pkg/types"
eutils "github.com/mudler/edgevpn/pkg/utils"
- "github.com/multiformats/go-multiaddr"
"github.com/phayes/freeport"
zlog "github.com/rs/zerolog/log"
"github.com/mudler/edgevpn/pkg/logger"
)
-func generateNewConnectionData(DHTInterval, OTPInterval int) *node.YAMLConnectionConfig {
+const DefaultInterval = 10 * time.Second
+
+func GenerateNewConnectionData(DHTInterval, OTPInterval int, privkey string, peerguardMode bool) (*node.YAMLConnectionConfig, error) {
maxMessSize := 20 << 20 // 20MB
keyLength := 43
if DHTInterval == 0 {
@@ -40,7 +43,7 @@ func generateNewConnectionData(DHTInterval, OTPInterval int) *node.YAMLConnectio
OTPInterval = 9000
}
- return &node.YAMLConnectionConfig{
+ connectionConfig := node.YAMLConnectionConfig{
MaxMessageSize: maxMessSize,
RoomName: eutils.RandStringRunes(keyLength),
Rendezvous: eutils.RandStringRunes(keyLength),
@@ -58,11 +61,27 @@ func generateNewConnectionData(DHTInterval, OTPInterval int) *node.YAMLConnectio
},
},
}
-}
-func GenerateToken(DHTInterval, OTPInterval int) string {
- // Generates a new config and exit
- return generateNewConnectionData(DHTInterval, OTPInterval).Base64()
+ if peerguardMode {
+ key, err := crypto.UnmarshalPrivateKey([]byte(privkey))
+ if err != nil {
+ return &connectionConfig, err
+ }
+ pid, err := peer.IDFromPublicKey(key.GetPublic())
+ if err != nil {
+ return &connectionConfig, err
+ }
+
+ connectionConfig.TrustedPeerIDS = []string{
+ pid.String(),
+ }
+ connectionConfig.ProtectedStoreKeys = []string{
+ "trustzone",
+ "trustzoneAuth",
+ }
+
+ }
+ return &connectionConfig, nil
}
func IsP2PEnabled() bool {
@@ -176,11 +195,11 @@ func allocateLocalService(ctx context.Context, node *node.Node, listenAddr, serv
// This is the main of the server (which keeps the env variable updated)
// This starts a goroutine that keeps LLAMACPP_GRPC_SERVERS updated with the discovered services
-func ServiceDiscoverer(ctx context.Context, n *node.Node, token, servicesID string, discoveryFunc func(serviceID string, node NodeData), allocate bool) error {
+func ServiceDiscoverer(ctx context.Context, n *node.Node, servicesID string, discoveryFunc func(serviceID string, node NodeData), allocate bool) error {
if servicesID == "" {
servicesID = defaultServicesID
}
- tunnels, err := discoveryTunnels(ctx, n, token, servicesID, allocate)
+ tunnels, err := discoveryTunnels(ctx, n, servicesID, allocate)
if err != nil {
return err
}
@@ -207,7 +226,7 @@ func ServiceDiscoverer(ctx context.Context, n *node.Node, token, servicesID stri
return nil
}
-func discoveryTunnels(ctx context.Context, n *node.Node, token, servicesID string, allocate bool) (chan NodeData, error) {
+func discoveryTunnels(ctx context.Context, n *node.Node, servicesID string, allocate bool) (chan NodeData, error) {
tunnels := make(chan NodeData)
ledger, err := n.Ledger()
@@ -316,16 +335,16 @@ func ensureService(ctx context.Context, n *node.Node, nd *NodeData, sserv string
}
// This is the P2P worker main
-func ExposeService(ctx context.Context, host, port, token, servicesID string) (*node.Node, error) {
- if servicesID == "" {
- servicesID = defaultServicesID
- }
+func ExposeService(ctx context.Context, p2pCfg p2pConfig.Config, host, port, servicesID string) (*node.Node, error) {
llger := logger.New(log.LevelFatal)
-
- nodeOpts, err := newNodeOpts(token)
+ nodeOpts, _, err := p2pCfg.ToOpts(llger)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("parsing config for new node: %w", err)
}
+ nodeOpts = append(nodeOpts, node.FromBase64(true, p2pCfg.Discovery.DHT, p2pCfg.NetworkToken, nil, nil))
+
+ nodeOpts = append(nodeOpts, services.Alive(30*time.Second, 900*time.Second, 15*time.Minute)...)
+
// generate a random string for the name
name := utils.RandString(10)
@@ -347,6 +366,9 @@ func ExposeService(ctx context.Context, host, port, token, servicesID string) (*
return n, fmt.Errorf("creating a new node: %w", err)
}
+ if servicesID == "" {
+ servicesID = defaultServicesID
+ }
ledger.Announce(
ctx,
20*time.Second,
@@ -364,11 +386,15 @@ func ExposeService(ctx context.Context, host, port, token, servicesID string) (*
return n, err
}
-func NewNode(token string) (*node.Node, error) {
- nodeOpts, err := newNodeOpts(token)
+func NewNode(p2pCfg p2pConfig.Config) (*node.Node, error) {
+ llger := logger.New(log.LevelFatal)
+ nodeOpts, _, err := p2pCfg.ToOpts(llger)
if err != nil {
- return nil, err
+ return nil, fmt.Errorf("parsing config for new node: %w", err)
}
+ nodeOpts = append(nodeOpts, node.FromBase64(true, p2pCfg.Discovery.DHT, p2pCfg.NetworkToken, nil, nil))
+
+ nodeOpts = append(nodeOpts, services.Alive(30*time.Second, 900*time.Second, 15*time.Minute)...)
n, err := node.New(nodeOpts...)
if err != nil {
@@ -378,89 +404,64 @@ func NewNode(token string) (*node.Node, error) {
return n, nil
}
-func newNodeOpts(token string) ([]node.Option, error) {
- llger := logger.New(log.LevelFatal)
- defaultInterval := 10 * time.Second
-
- // TODO: move this up, expose more config options when creating a node
- noDHT := os.Getenv("LOCALAI_P2P_DISABLE_DHT") == "true"
- noLimits := os.Getenv("LOCALAI_P2P_ENABLE_LIMITS") == "true"
-
- var listenMaddrs []string
- var bootstrapPeers []string
-
- laddrs := os.Getenv("LOCALAI_P2P_LISTEN_MADDRS")
- if laddrs != "" {
- listenMaddrs = strings.Split(laddrs, ",")
- }
-
- bootmaddr := os.Getenv("LOCALAI_P2P_BOOTSTRAP_PEERS_MADDRS")
- if bootmaddr != "" {
- bootstrapPeers = strings.Split(bootmaddr, ",")
- }
-
- dhtAnnounceMaddrs := stringsToMultiAddr(strings.Split(os.Getenv("LOCALAI_P2P_DHT_ANNOUNCE_MADDRS"), ","))
+func NewP2PConfig(p2pCommonFlags cliP2P.P2PCommonFlags) p2pConfig.Config {
+ pa := p2pCommonFlags.Peer2PeerAuthProvders
+ d := map[string]map[string]interface{}{}
+ json.Unmarshal([]byte(pa), &d)
- libp2ploglevel := os.Getenv("LOCALAI_P2P_LIB_LOGLEVEL")
- if libp2ploglevel == "" {
- libp2ploglevel = "fatal"
- }
- c := config.Config{
- ListenMaddrs: listenMaddrs,
- DHTAnnounceMaddrs: dhtAnnounceMaddrs,
- Limit: config.ResourceLimit{
- Enable: noLimits,
+ c := p2pConfig.Config{
+ ListenMaddrs: p2pCommonFlags.Peer2PeerListenAddrs,
+ DHTAnnounceMaddrs: utils.StringsToMultiAddr(p2pCommonFlags.Peer2PeerDHTAnnounceAddrs),
+ Limit: p2pConfig.ResourceLimit{
+ Enable: p2pCommonFlags.Peer2PeerLimit,
MaxConns: 100,
},
- NetworkToken: token,
- LowProfile: false,
- LogLevel: logLevel,
- Libp2pLogLevel: libp2ploglevel,
- Ledger: config.Ledger{
- SyncInterval: defaultInterval,
- AnnounceInterval: defaultInterval,
+ LowProfile: false,
+ LogLevel: logLevel,
+ Ledger: p2pConfig.Ledger{
+ SyncInterval: DefaultInterval,
+ AnnounceInterval: DefaultInterval,
},
- NAT: config.NAT{
+ NAT: p2pConfig.NAT{
Service: true,
Map: true,
RateLimit: true,
RateLimitGlobal: 100,
RateLimitPeer: 100,
- RateLimitInterval: defaultInterval,
+ RateLimitInterval: DefaultInterval,
},
- Discovery: config.Discovery{
- DHT: !noDHT,
+ Discovery: p2pConfig.Discovery{
+ DHT: !p2pCommonFlags.Peer2PeerNoDHT,
MDNS: true,
- Interval: 10 * time.Second,
- BootstrapPeers: bootstrapPeers,
+ Interval: DefaultInterval,
+ BootstrapPeers: p2pCommonFlags.Peer2PeerBootAddrs,
},
- Connection: config.Connection{
+ Connection: p2pConfig.Connection{
HolePunch: true,
AutoRelay: true,
MaxConnections: 1000,
},
- }
+ PeerGuard: p2pConfig.PeerGuard{
+ Enable: p2pCommonFlags.Peer2PeerUsePeerguard,
- nodeOpts, _, err := c.ToOpts(llger)
- if err != nil {
- return nil, fmt.Errorf("parsing options: %w", err)
+ // Default from edgevpn
+ SyncInterval: 120 * time.Second,
+ AuthProviders: d,
+ },
}
- nodeOpts = append(nodeOpts, services.Alive(30*time.Second, 900*time.Second, 15*time.Minute)...)
-
- return nodeOpts, nil
-}
+ privkey := p2pCommonFlags.Peer2PeerPrivkey
+ if privkey != "" {
+ c.Privkey = []byte(privkey)
+ }
-func stringsToMultiAddr(peers []string) []multiaddr.Multiaddr {
- res := []multiaddr.Multiaddr{}
- for _, p := range peers {
- addr, err := multiaddr.NewMultiaddr(p)
- if err != nil {
- continue
- }
- res = append(res, addr)
+ libp2ploglevel := p2pCommonFlags.Peer2PeerLibLoglevel
+ if libp2ploglevel == "" {
+ libp2ploglevel = "fatal"
}
- return res
+ c.Libp2pLogLevel = libp2ploglevel
+
+ return c
}
func copyStream(closer chan struct{}, dst io.Writer, src io.Reader) {
diff --git a/core/p2p/p2p_disabled.go b/core/p2p/p2p_disabled.go
index c5ba98fdab59..f27b13860e7d 100644
--- a/core/p2p/p2p_disabled.go
+++ b/core/p2p/p2p_disabled.go
@@ -7,22 +7,24 @@ import (
"context"
"fmt"
+ cliP2P "github.com/mudler/LocalAI/core/cli/p2p"
+ p2pConfig "github.com/mudler/edgevpn/pkg/config"
"github.com/mudler/edgevpn/pkg/node"
)
-func GenerateToken(DHTInterval, OTPInterval int) string {
- return "not implemented"
+func GenerateNewConnectionData(DHTInterval, OTPInterval int, privkey string, peerguardMode bool) (*node.YAMLConnectionConfig, error) {
+ return nil, fmt.Errorf("not implemented")
}
-func (f *FederatedServer) Start(ctx context.Context) error {
+func (f *FederatedServer) Start(ctx context.Context, p2pCommonFlags cliP2P.P2PCommonFlags) error {
return fmt.Errorf("not implemented")
}
-func ServiceDiscoverer(ctx context.Context, node *node.Node, token, servicesID string, fn func(string, NodeData), allocate bool) error {
+func ServiceDiscoverer(ctx context.Context, n *node.Node, servicesID string, discoveryFunc func(serviceID string, node NodeData), allocate bool) error {
return fmt.Errorf("not implemented")
}
-func ExposeService(ctx context.Context, host, port, token, servicesID string) (*node.Node, error) {
+func ExposeService(ctx context.Context, p2pCfg p2pConfig.Config, host, port, servicesID string) (*node.Node, error) {
return nil, fmt.Errorf("not implemented")
}
@@ -30,6 +32,10 @@ func IsP2PEnabled() bool {
return false
}
-func NewNode(token string) (*node.Node, error) {
+func NewNode(p2pCfg p2pConfig.Config) (*node.Node, error) {
return nil, fmt.Errorf("not implemented")
}
+
+func NewP2PConfig(p2pCommonFlags cliP2P.P2PCommonFlags) p2pConfig.Config {
+ return p2pConfig.Config{}
+}
diff --git a/go.mod b/go.mod
index 856d41f55aed..c1d88669ea8b 100644
--- a/go.mod
+++ b/go.mod
@@ -8,10 +8,8 @@ require (
dario.cat/mergo v1.0.1
github.com/Masterminds/sprig/v3 v3.3.0
github.com/alecthomas/kong v0.9.0
- github.com/census-instrumentation/opencensus-proto v0.4.1
github.com/charmbracelet/glamour v0.7.0
github.com/chasefleming/elem-go v0.26.0
- github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20
github.com/containerd/containerd v1.7.19
github.com/dave-gray101/v2keyauth v0.0.0-20240624150259-c45d584d25e2
github.com/elliotchance/orderedmap/v2 v2.2.0
@@ -22,18 +20,15 @@ require (
github.com/gofiber/fiber/v2 v2.52.5
github.com/gofiber/swagger v1.0.0
github.com/gofiber/template/html/v2 v2.1.2
- github.com/gofiber/websocket/v2 v2.2.1
github.com/gofrs/flock v0.12.1
- github.com/golang/protobuf v1.5.4
github.com/google/go-containerregistry v0.19.2
github.com/google/uuid v1.6.0
- github.com/grpc-ecosystem/grpc-gateway v1.5.0
github.com/hpcloud/tail v1.0.0
github.com/ipfs/go-log v1.0.5
github.com/jaypipes/ghw v0.12.0
github.com/joho/godotenv v1.5.1
github.com/klauspost/cpuid/v2 v2.2.9
- github.com/libp2p/go-libp2p v0.39.1
+ github.com/libp2p/go-libp2p v0.40.0
github.com/mholt/archiver/v3 v3.5.1
github.com/microcosm-cc/bluemonday v1.0.26
github.com/mudler/edgevpn v0.30.1
@@ -41,11 +36,10 @@ require (
github.com/nikolalohinski/gonja/v2 v2.3.2
github.com/onsi/ginkgo/v2 v2.22.2
github.com/onsi/gomega v1.36.2
- github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e
github.com/ory/dockertest/v3 v3.10.0
github.com/otiai10/openaigo v1.7.0
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
- github.com/prometheus/client_golang v1.20.5
+ github.com/prometheus/client_golang v1.21.0
github.com/rs/zerolog v1.33.0
github.com/russross/blackfriday v1.6.0
github.com/sashabaranov/go-openai v1.26.2
@@ -61,7 +55,6 @@ require (
go.opentelemetry.io/otel/exporters/prometheus v0.50.0
go.opentelemetry.io/otel/metric v1.34.0
go.opentelemetry.io/otel/sdk/metric v1.28.0
- google.golang.org/api v0.180.0
google.golang.org/grpc v1.67.1
google.golang.org/protobuf v1.36.5
gopkg.in/yaml.v2 v2.4.0
@@ -70,20 +63,11 @@ require (
)
require (
- cel.dev/expr v0.16.0 // indirect
- cloud.google.com/go/auth v0.4.1 // indirect
- cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
- cloud.google.com/go/compute/metadata v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
- github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect
- github.com/fasthttp/websocket v1.5.3 // indirect
- github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/go-viper/mapstructure/v2 v2.0.0 // indirect
- github.com/google/s2a-go v0.1.7 // indirect
- github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
- github.com/googleapis/gax-go/v2 v2.12.4 // indirect
github.com/json-iterator/go v1.1.12 // indirect
+ github.com/libp2p/go-yamux/v5 v5.0.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
@@ -91,11 +75,9 @@ require (
github.com/pion/datachannel v1.5.10 // indirect
github.com/pion/dtls/v2 v2.2.12 // indirect
github.com/pion/dtls/v3 v3.0.4 // indirect
- github.com/pion/ice/v2 v2.3.37 // indirect
github.com/pion/ice/v4 v4.0.6 // indirect
github.com/pion/interceptor v0.1.37 // indirect
github.com/pion/logging v0.2.3 // indirect
- github.com/pion/mdns v0.0.12 // indirect
github.com/pion/mdns/v2 v2.0.7 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.15 // indirect
@@ -107,18 +89,13 @@ require (
github.com/pion/stun/v3 v3.0.0 // indirect
github.com/pion/transport/v2 v2.2.10 // indirect
github.com/pion/transport/v3 v3.0.7 // indirect
- github.com/pion/turn/v2 v2.1.6 // indirect
github.com/pion/turn/v4 v4.0.0 // indirect
github.com/pion/webrtc/v4 v4.0.9 // indirect
- github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
github.com/shirou/gopsutil/v4 v4.24.7 // indirect
github.com/wlynxg/anet v0.0.5 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect
go.uber.org/mock v0.5.0 // indirect
- golang.org/x/oauth2 v0.24.0 // indirect
golang.org/x/time v0.8.0 // indirect
- google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 // indirect
)
require (
@@ -148,7 +125,7 @@ require (
github.com/creachadair/otp v0.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
- github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
+ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/docker/cli v27.0.3+incompatible // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
@@ -161,7 +138,7 @@ require (
github.com/flynn/noise v1.1.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
- github.com/go-audio/audio v1.0.0
+ github.com/go-audio/audio v1.0.0 // indirect
github.com/go-audio/riff v1.0.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
@@ -193,7 +170,7 @@ require (
github.com/huin/goupnp v1.3.0 // indirect
github.com/ipfs/boxo v0.27.4 // indirect
github.com/ipfs/go-cid v0.5.0 // indirect
- github.com/ipfs/go-datastore v0.6.0 // indirect
+ github.com/ipfs/go-datastore v0.7.0 // indirect
github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/ipld/go-ipld-prime v0.21.0 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
@@ -208,7 +185,7 @@ require (
github.com/libp2p/go-cidranger v1.1.0 // indirect
github.com/libp2p/go-flow-metrics v0.2.0 // indirect
github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
- github.com/libp2p/go-libp2p-kad-dht v0.29.0 // indirect
+ github.com/libp2p/go-libp2p-kad-dht v0.29.1 // indirect
github.com/libp2p/go-libp2p-kbucket v0.6.5 // indirect
github.com/libp2p/go-libp2p-pubsub v0.13.0 // indirect
github.com/libp2p/go-libp2p-record v0.3.1 // indirect
@@ -217,7 +194,6 @@ require (
github.com/libp2p/go-nat v0.2.0 // indirect
github.com/libp2p/go-netroute v0.2.2 // indirect
github.com/libp2p/go-reuseport v0.4.0 // indirect
- github.com/libp2p/go-yamux/v4 v4.0.2 // indirect
github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/lufia/plan9stats v0.0.0-20240819163618-b1d8f4d146e7 // indirect
@@ -308,7 +284,7 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.33.0 // indirect
- golang.org/x/exp v0.0.0-20250215185904-eff6e970281f // indirect
+ golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect
golang.org/x/mod v0.23.0 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/sync v0.11.0 // indirect
@@ -326,3 +302,5 @@ require (
howett.net/plist v1.0.0 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
)
+
+replace github.com/mudler/edgevpn => github.com/swarmind/edgevpn v0.0.0-20250331231759-326a9e7360b0
diff --git a/go.sum b/go.sum
index 06e0238f0835..51154aa1e811 100644
--- a/go.sum
+++ b/go.sum
@@ -1,15 +1,7 @@
-cel.dev/expr v0.16.0 h1:yloc84fytn4zmJX2GU3TkXGsaieaV7dQ057Qs4sIG2Y=
-cel.dev/expr v0.16.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
-cloud.google.com/go/auth v0.4.1 h1:Z7YNIhlWRtrnKlZke7z3GMqzvuYzdc2z98F9D1NV5Hg=
-cloud.google.com/go/auth v0.4.1/go.mod h1:QVBuVEKpCn4Zp58hzRGvL0tjRGU0YqdRTdCHM1IHnro=
-cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4=
-cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q=
-cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
-cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
@@ -69,8 +61,6 @@ github.com/c-robinson/iplib v1.0.8/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szN
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
-github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/glamour v0.7.0 h1:2BtKGZ4iVJCDfMF229EzbeR1QRKLWztO9dMtjmqZSng=
@@ -80,8 +70,6 @@ github.com/chasefleming/elem-go v0.26.0/go.mod h1:hz73qILBIKnTgOujnSMtEj20/epI+f
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20 h1:N+3sFI5GUjRKBi+i0TxYVST9h4Ie192jJWpHvthBBgg=
-github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
@@ -115,10 +103,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU=
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U=
-github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
-github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
+github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
+github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/docker/cli v27.0.3+incompatible h1:usGs0/BoBW8MWxGeEtqPMkzOY56jZ6kYlSN5BLDioCQ=
@@ -149,12 +137,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM=
-github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
-github.com/fasthttp/websocket v1.5.3 h1:TPpQuLwJYfd4LJPXvHDYPMFWbLjsT91n3GpWtCQtdek=
-github.com/fasthttp/websocket v1.5.3/go.mod h1:46gg/UBmTU1kUaTcwQXpUxtRwG2PvIZYeA8oL6vF3Fs=
-github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
-github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg=
github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
@@ -165,8 +147,6 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
-github.com/ggerganov/whisper.cpp/bindings/go v0.0.0-20240626202019-c118733a29ad h1:dQ93Vd6i25o+zH9vvnZ8mu7jtJQ6jT3D+zE3V8Q49n0=
-github.com/ggerganov/whisper.cpp/bindings/go v0.0.0-20240626202019-c118733a29ad/go.mod h1:QIjZ9OktHFG7p+/m3sMvrAJKKdWrr1fZIK0rM6HZlyo=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
@@ -219,8 +199,6 @@ github.com/gofiber/template/html/v2 v2.1.2 h1:wkK/mYJ3nIhongTkG3t0QgV4ADdgOYJYVS
github.com/gofiber/template/html/v2 v2.1.2/go.mod h1:E98Z/FzvpaSib06aWEgYk6GXNf3ctoyaJH8yW5ay5ak=
github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM=
github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0=
-github.com/gofiber/websocket/v2 v2.2.1 h1:C9cjxvloojayOp9AovmpQrk8VqvVnT8Oao3+IUygH7w=
-github.com/gofiber/websocket/v2 v2.2.1/go.mod h1:Ao/+nyNnX5u/hIFPuHl28a+NIkrqK7PRimyKaj4JxVU=
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -244,8 +222,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
-github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -274,20 +250,13 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI
github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc=
github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
-github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
-github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
-github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg=
-github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -296,7 +265,6 @@ github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/grpc-gateway v1.5.0 h1:WcmKMm43DR7RdtlkEXQJyo5ws8iTp98CyhCCbOHMvNI=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
@@ -323,8 +291,8 @@ github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNi
github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM=
github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg=
github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk=
-github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk=
-github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8=
+github.com/ipfs/go-datastore v0.7.0 h1:a6JMuRFKYhw6XXmIVoTthF8ZFm4QQXvLDXFhXRVv8Go=
+github.com/ipfs/go-datastore v0.7.0/go.mod h1:ucOWMfbOPI6ZEyaIB1q/+78RPLBPERfuUVYX1EPnNpQ=
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
github.com/ipfs/go-ipfs-util v0.0.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0=
@@ -395,12 +363,12 @@ github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38y
github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic=
github.com/libp2p/go-flow-metrics v0.2.0 h1:EIZzjmeOE6c8Dav0sNv35vhZxATIXWZg6j/C08XmmDw=
github.com/libp2p/go-flow-metrics v0.2.0/go.mod h1:st3qqfu8+pMfh+9Mzqb2GTiwrAGjIPszEjZmtksN8Jc=
-github.com/libp2p/go-libp2p v0.39.1 h1:1Ur6rPCf3GR+g8jkrnaQaM0ha2IGespsnNlCqJLLALE=
-github.com/libp2p/go-libp2p v0.39.1/go.mod h1:3zicI8Lp7Isun+Afo/JOACUbbJqqR2owK6RQWFsVAbI=
+github.com/libp2p/go-libp2p v0.40.0 h1:1LOMO3gigxeXFs50HGEc1U79OINewUQB7o4gTKGPC3U=
+github.com/libp2p/go-libp2p v0.40.0/go.mod h1:hOzj2EAIYsXpVpBnyA1pRHzpUJGF9nbWiDLjgasnbF0=
github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
-github.com/libp2p/go-libp2p-kad-dht v0.29.0 h1:045eW21lGlMSD9aKSZZGH4fnBMIInPwQLxIQ35P962I=
-github.com/libp2p/go-libp2p-kad-dht v0.29.0/go.mod h1:mIci3rHSwDsxQWcCjfmxD8vMTgh5xLuvwb1D5WP8ZNk=
+github.com/libp2p/go-libp2p-kad-dht v0.29.1 h1:RyD1RnnkXOh1gwBCrMQ6ZVfTJECY5yDOY6qxt9VNqE4=
+github.com/libp2p/go-libp2p-kad-dht v0.29.1/go.mod h1:tZEFTKWCsY0xngypKyAIwNDNZOBiikSUIgd/BjTF5Ms=
github.com/libp2p/go-libp2p-kbucket v0.6.5 h1:Fsl1YvZcMwqrR4DYrTO02yo9PGYs2HBQIT3lGXFMTxg=
github.com/libp2p/go-libp2p-kbucket v0.6.5/go.mod h1:U6WOd0BvnSp03IQSrjgM54tg7zh1UUNsXLJqAQzClTA=
github.com/libp2p/go-libp2p-pubsub v0.13.0 h1:RmFQ2XAy3zQtbt2iNPy7Tt0/3fwTnHpCQSSnmGnt1Ps=
@@ -419,8 +387,8 @@ github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFP
github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE=
github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s=
github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU=
-github.com/libp2p/go-yamux/v4 v4.0.2 h1:nrLh89LN/LEiqcFiqdKDRHjGstN300C1269K/EX0CPU=
-github.com/libp2p/go-yamux/v4 v4.0.2/go.mod h1:C808cCRgOs1iBwY4S71T5oxgMxgLmqUw56qh4AeBW2o=
+github.com/libp2p/go-yamux/v5 v5.0.0 h1:2djUh96d3Jiac/JpGkKs4TO49YhsfLopAoryfPmf+Po=
+github.com/libp2p/go-yamux/v5 v5.0.0/go.mod h1:en+3cdX51U0ZslwRdRLrvQsdayFt3TSUKvBGErzpWbU=
github.com/libp2p/zeroconf/v2 v2.2.0 h1:Cup06Jv6u81HLhIj1KasuNM/RHHrJ8T7wOTS4+Tv53Q=
github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
@@ -489,10 +457,6 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
-github.com/mudler/edgevpn v0.30.1 h1:4yyhNFJX62NpRp50sxiyZE5E/sdAqEZX+aE5Mv7QS60=
-github.com/mudler/edgevpn v0.30.1/go.mod h1:IAJkkJ0oH3rwsSGOGTFT4UBYFqYuD/QyaKzTLB3P/eU=
-github.com/mudler/go-piper v0.0.0-20241023091659-2494246fd9fc h1:RxwneJl1VgvikiX28EkpdAyL4yQVnJMrbquKospjHyA=
-github.com/mudler/go-piper v0.0.0-20241023091659-2494246fd9fc/go.mod h1:O7SwdSWMilAWhBZMK9N9Y/oBDyMMzshE3ju8Xkexwig=
github.com/mudler/go-processmanager v0.0.0-20240820160718-8b802d3ecf82 h1:FVT07EI8njvsD4tC2Hw8Xhactp5AWhsQWD4oTeQuSAU=
github.com/mudler/go-processmanager v0.0.0-20240820160718-8b802d3ecf82/go.mod h1:Urp7LG5jylKoDq0663qeBh0pINGcRl35nXdKx82PSoU=
github.com/mudler/water v0.0.0-20221010214108-8c7313014ce0 h1:Qh6ghkMgTu6siFbTf7L3IszJmshMhXxNL4V+t7IIA6w=
@@ -553,8 +517,6 @@ github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
-github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e h1:s2RNOM/IGdY0Y6qfTeUKhDawdHDpK9RGBdx80qN4Ttw=
-github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e/go.mod h1:nBdnFKj15wFbf94Rwfq4m30eAcyY9V/IyKAGQFtqkW0=
github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4=
github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg=
github.com/otiai10/mint v1.6.1 h1:kgbTJmOpp/0ce7hk3H8jiSuR0MXmpwWRfqUdKww17qg=
@@ -578,8 +540,6 @@ github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk=
github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE=
github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U=
github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg=
-github.com/pion/ice/v2 v2.3.37 h1:ObIdaNDu1rCo7hObhs34YSBcO7fjslJMZV0ux+uZWh0=
-github.com/pion/ice/v2 v2.3.37/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ=
github.com/pion/ice/v4 v4.0.6 h1:jmM9HwI9lfetQV/39uD0nY4y++XZNPhvzIPCb8EwxUM=
github.com/pion/ice/v4 v4.0.6/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw=
github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI=
@@ -587,8 +547,6 @@ github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVm
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI=
github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90=
-github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8=
-github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk=
github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=
github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA=
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
@@ -611,12 +569,8 @@ github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1A
github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q=
github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E=
-github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0=
github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0=
github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
-github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
-github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc=
-github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM=
github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA=
github.com/pion/webrtc/v4 v4.0.9 h1:PyOYMRKJgfy0dzPcYtFD/4oW9zaw3Ze3oZzzbj2LV9E=
@@ -633,8 +587,8 @@ github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
-github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_golang v1.21.0 h1:DIsaGmiaBkSangBgMtWdNfxbMNdku5IK6iNhrEqWvdA=
+github.com/prometheus/client_golang v1.21.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
@@ -670,8 +624,6 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sashabaranov/go-openai v1.26.2 h1:cVlQa3gn3eYqNXRW03pPlpy6zLG52EU4g0FrWXc0EFI=
github.com/sashabaranov/go-openai v1.26.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
-github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
-github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
github.com/schollz/progressbar/v3 v3.14.4 h1:W9ZrDSJk7eqmQhd3uxFNNcTr0QL+xuGNI9dEMrw0r74=
github.com/schollz/progressbar/v3 v3.14.4/go.mod h1:aT3UQ7yGm+2ZjeXPqsjTenwL3ddUiuZ0kfQ/2tHlyNI=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
@@ -747,6 +699,8 @@ github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw
github.com/swaggo/files/v2 v2.0.0/go.mod h1:24kk2Y9NYEJ5lHuCra6iVwkMjIekMCaFq/0JQj66kyM=
github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
+github.com/swarmind/edgevpn v0.0.0-20250331231759-326a9e7360b0 h1:1IzdOtFh9IubHt/7kkSO56chnwHF3Yp7DsWSpXTaMgE=
+github.com/swarmind/edgevpn v0.0.0-20250331231759-326a9e7360b0/go.mod h1:bGUdGQzwLOuMs3SII1N6SazoI1qQ1ekxdxNatOCS5ZM=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/thxcode/gguf-parser-go v0.1.0 h1:J4QruXyEQGjrAKeKZFlsD2na9l4XF5+bjR194d+wJS4=
github.com/thxcode/gguf-parser-go v0.1.0/go.mod h1:Tn1PsO/YDEtLIxm1+QDCjIIH9L/9Sr7+KpxZKm0sEuE=
@@ -811,8 +765,6 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
go.opentelemetry.io/otel/exporters/prometheus v0.50.0 h1:2Ewsda6hejmbhGFyUvWZjUThC98Cf8Zy6g0zkIimOng=
@@ -863,8 +815,8 @@ golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1m
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20250215185904-eff6e970281f h1:oFMYAjX0867ZD2jcNiLBrI9BdpmEkvPyi5YrBGXbamg=
-golang.org/x/exp v0.0.0-20250215185904-eff6e970281f/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
+golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4=
+golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -912,8 +864,6 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
-golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -961,7 +911,6 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1033,8 +982,6 @@ gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
-google.golang.org/api v0.180.0 h1:M2D87Yo0rGBPWpo1orwfCLehUUL6E7/TYe5gvMQWDh4=
-google.golang.org/api v0.180.0/go.mod h1:51AiyoEg1MJPSZ9zvklA8VnRILPXxn1iVen9v25XHAE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1046,10 +993,6 @@ google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda h1:wu/KJm9KJwpfHWhkkZGohVC6KRrc1oJNr4jwtQMOQXw=
-google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda/go.mod h1:g2LLCvCeCSir/JJSWosk19BR4NVxGqHUC6rxIRsd7Aw=
-google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg=
-google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
@@ -1075,7 +1018,6 @@ google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwl
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
diff --git a/pkg/utils/p2p.go b/pkg/utils/p2p.go
new file mode 100644
index 000000000000..f988f364f974
--- /dev/null
+++ b/pkg/utils/p2p.go
@@ -0,0 +1,15 @@
+package utils
+
+import "github.com/multiformats/go-multiaddr"
+
+func StringsToMultiAddr(peers []string) []multiaddr.Multiaddr {
+ res := []multiaddr.Multiaddr{}
+ for _, p := range peers {
+ addr, err := multiaddr.NewMultiaddr(p)
+ if err != nil {
+ continue
+ }
+ res = append(res, addr)
+ }
+ return res
+}