Skip to content

Commit edbb5ed

Browse files
committed
resolved re-register issue
1 parent 4d82de1 commit edbb5ed

File tree

2 files changed

+156
-6
lines changed

2 files changed

+156
-6
lines changed

blox/kubo_proxy.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,10 @@ func registerKuboProtocols(kuboAPI string) error {
4646
}
4747

4848
func registerSingleProtocol(kuboAPI, protocol, target string) error {
49-
// First close any existing listener for this protocol (idempotent)
50-
closeURL := fmt.Sprintf("http://%s/api/v0/p2p/close?arg=%s&listen-address=%s",
51-
kuboAPI, protocol, target)
49+
// First close any existing listener for this protocol (idempotent).
50+
// Use only arg=<protocol> so it matches regardless of listen/target address.
51+
closeURL := fmt.Sprintf("http://%s/api/v0/p2p/close?arg=%s",
52+
kuboAPI, protocol)
5253
closeResp, err := http.Post(closeURL, "", nil)
5354
if err != nil {
5455
log.Debugw("Could not close existing p2p listener (may not exist)", "protocol", protocol, "err", err)
@@ -66,10 +67,15 @@ func registerSingleProtocol(kuboAPI, protocol, target string) error {
6667
defer resp.Body.Close()
6768

6869
if resp.StatusCode != http.StatusOK {
69-
var body []byte
70-
body = make([]byte, 512)
70+
body := make([]byte, 512)
7171
n, _ := resp.Body.Read(body)
72-
return fmt.Errorf("kubo API returned status %d: %s", resp.StatusCode, string(body[:n]))
72+
bodyStr := string(body[:n])
73+
// "listener already registered" means the protocol is active — not an error
74+
if strings.Contains(bodyStr, "listener already registered") {
75+
log.Debugw("Protocol already registered, treating as success", "protocol", protocol)
76+
return nil
77+
}
78+
return fmt.Errorf("kubo API returned status %d: %s", resp.StatusCode, bodyStr)
7379
}
7480
return nil
7581
}

mobile/device_test.go

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package fulamobile
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"testing"
7+
"time"
8+
9+
"github.com/libp2p/go-libp2p/core/crypto"
10+
"github.com/libp2p/go-libp2p/core/peer"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
// Test flags — pass via:
15+
//
16+
// go test ./mobile/ -run TestRealDeviceConnection -v -timeout 120s \
17+
// -blox-peer-id 12D3KooW... -mode direct -blox-ip 192.168.x.x
18+
//
19+
// Modes:
20+
//
21+
// direct — connect to blox IP directly (requires -blox-ip)
22+
// relay — connect through fx.land static relay
23+
// dht — bogus IP + no relays, only IPFS DHT fallback works
24+
var (
25+
flagBloxPeerID = flag.String("blox-peer-id", "", "Peer ID of the blox/kubo node (required)")
26+
flagBloxIP = flag.String("blox-ip", "", "IP address of the blox (required for direct mode)")
27+
flagMode = flag.String("mode", "direct", "Connection mode: direct, relay, or dht")
28+
)
29+
30+
// Fixed seed so the client peer ID is deterministic across runs.
31+
const testIdentitySeed = "fula-mobile-device-test-identity-seed"
32+
33+
func TestRealDeviceConnection(t *testing.T) {
34+
if *flagBloxPeerID == "" {
35+
t.Skip("Skipping: -blox-peer-id not provided. Run with: go test ./mobile/ -run TestRealDeviceConnection -v -timeout 120s -blox-peer-id <PEER_ID> -mode <direct|relay|dht> [-blox-ip <IP>]")
36+
}
37+
38+
// Validate peer ID early
39+
_, err := peer.Decode(*flagBloxPeerID)
40+
require.NoError(t, err, "Invalid -blox-peer-id")
41+
42+
// Generate deterministic identity
43+
identity, err := GenerateEd25519KeyFromString(testIdentitySeed)
44+
require.NoError(t, err)
45+
46+
pk, err := crypto.UnmarshalPrivateKey(identity)
47+
require.NoError(t, err)
48+
clientPeerID, err := peer.IDFromPrivateKey(pk)
49+
require.NoError(t, err)
50+
51+
t.Logf("========================================")
52+
t.Logf(" CLIENT PEER ID: %s", clientPeerID)
53+
t.Logf("========================================")
54+
t.Logf("Whitelist this peer ID on your blox before running.")
55+
t.Logf("")
56+
57+
cfg := NewConfig()
58+
cfg.Identity = identity
59+
cfg.StorePath = t.TempDir()
60+
cfg.AllowTransientConnection = true
61+
62+
switch *flagMode {
63+
case "direct":
64+
if *flagBloxIP == "" {
65+
t.Fatal("-blox-ip is required for direct mode")
66+
}
67+
cfg.BloxAddr = fmt.Sprintf("/ip4/%s/tcp/4001/p2p/%s", *flagBloxIP, *flagBloxPeerID)
68+
cfg.IpfsDHTLookupDisabled = true // Only test direct path
69+
t.Logf("Mode: DIRECT")
70+
t.Logf("BloxAddr: %s", cfg.BloxAddr)
71+
72+
case "relay":
73+
cfg.BloxAddr = fmt.Sprintf(
74+
"/dns/relay.dev.fx.land/tcp/4001/p2p/12D3KooWDRrBaAfPwsGJivBoUw5fE7ZpDiyfUjqgiURq2DEcL835/p2p-circuit/p2p/%s",
75+
*flagBloxPeerID,
76+
)
77+
cfg.IpfsDHTLookupDisabled = true // Only test relay path
78+
t.Logf("Mode: RELAY (via fx.land)")
79+
t.Logf("BloxAddr: %s", cfg.BloxAddr)
80+
81+
case "dht":
82+
// Bogus IP so direct dial fails; empty relays so relay fails; DHT must find the peer
83+
cfg.BloxAddr = fmt.Sprintf("/ip4/192.168.99.99/tcp/4001/p2p/%s", *flagBloxPeerID)
84+
cfg.StaticRelays = []string{}
85+
cfg.IpfsDHTLookupDisabled = false
86+
t.Logf("Mode: DHT (bogus IP, no relays — IPFS DHT fallback only)")
87+
t.Logf("BloxAddr: %s", cfg.BloxAddr)
88+
89+
default:
90+
t.Fatalf("Unknown -mode %q. Use: direct, relay, or dht", *flagMode)
91+
}
92+
93+
t.Logf("")
94+
t.Logf("Creating client...")
95+
client, err := NewClient(cfg)
96+
require.NoError(t, err, "NewClient failed")
97+
defer func() {
98+
t.Logf("Shutting down client...")
99+
if err := client.Shutdown(); err != nil {
100+
t.Logf("Shutdown error: %v", err)
101+
}
102+
}()
103+
104+
t.Logf("Client ready, peer ID confirmed: %s", client.ID())
105+
106+
if *flagMode == "dht" {
107+
t.Logf("Waiting 20s for IPFS DHT bootstrap to warm up...")
108+
time.Sleep(20 * time.Second)
109+
}
110+
111+
// --- Test 1: PoolList (read-only, safe to call) ---
112+
t.Run("PoolList", func(t *testing.T) {
113+
t.Logf("Calling PoolList...")
114+
result, err := client.PoolList()
115+
if err != nil {
116+
t.Errorf("PoolList failed: %v", err)
117+
} else {
118+
t.Logf("PoolList response: %s", string(result))
119+
}
120+
})
121+
122+
// --- Test 2: BloxFreeSpace (read-only, safe to call) ---
123+
t.Run("BloxFreeSpace", func(t *testing.T) {
124+
t.Logf("Calling BloxFreeSpace...")
125+
result, err := client.BloxFreeSpace()
126+
if err != nil {
127+
t.Errorf("BloxFreeSpace failed: %v", err)
128+
} else {
129+
t.Logf("BloxFreeSpace response: %s", string(result))
130+
}
131+
})
132+
133+
// --- Test 3: AccountExists (read-only, safe to call) ---
134+
t.Run("AccountExists", func(t *testing.T) {
135+
testAccount := "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
136+
t.Logf("Calling AccountExists(%s)...", testAccount)
137+
result, err := client.AccountExists(testAccount)
138+
if err != nil {
139+
t.Errorf("AccountExists failed: %v", err)
140+
} else {
141+
t.Logf("AccountExists response: %s", string(result))
142+
}
143+
})
144+
}

0 commit comments

Comments
 (0)