Skip to content

Commit ed6df52

Browse files
committed
chore: reduce examples size
1 parent a98e706 commit ed6df52

5 files changed

Lines changed: 160 additions & 347 deletions

File tree

cbind/examples/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ The bindings are a header-only C API over a C ABI. Every generated method is asy
77
- `echo.c` — two TCP nodes; the server mounts a custom `/cbind/echo/1.0.0` protocol and echoes the bytes it reads, the client dials it and verifies the round-trip. The incoming-stream handler only hands the stream id to `main`, which serves it inline, since calling back into the library from the dispatch thread would deadlock.
88
- `gossipsub.c` — two TCP nodes join a shared topic and exchange one message, delivered to the subscriber through its pub/sub-message listener.
99
- `kad.c` — two TCP nodes form a Kademlia DHT (a server, and a client that lists the server as its bootstrap node), then round-trip a value (`kad_put_value` / `kad_get_value`) and a provider record (`create_cid`, `kad_start_providing` / `kad_get_providers`) over the wire.
10-
- `relay.c` — three TCP nodes: a relay, a destination and a source. The destination reserves a slot on the relay (`circuit_relay_reserve`); the source reaches it over a `/p2p-circuit` address (`dial_circuit_relay`) and runs the echo exchange relayed instead of direct.
11-
- `peerstore.c` — drives one node's peerstore directly from a second node's PeerInfo: `peerstore_add_peer`, `peerstore_get_peers`, `peerstore_get_peer_info`, `peerstore_set_peer_protocols`, then `peerstore_delete_peer`. No dialing required.
12-
- `metrics.c`two TCP nodes connect, then one dumps the process-wide Prometheus registry as JSON via `collect_metrics`.
10+
- `relay.c` — three TCP nodes: a relay, a destination and a source. The destination reserves a slot on the relay (`circuit_relay_reserve`); the source reaches it over a `/p2p-circuit` address (`dial_circuit_relay`) and sends a message the destination reads off its relayed stream.
11+
- `peerstore.c` — drives one node's peerstore directly from a second node's PeerInfo: `peerstore_add_peer`, `peerstore_get_peers`, `peerstore_get_peer_info`, then `peerstore_delete_peer`. No dialing required.
12+
- `metrics.c`a running node dumps the process-wide Prometheus registry as JSON via `collect_metrics`.
1313

1414
## Build
1515

cbind/examples/metrics.c

Lines changed: 20 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,29 @@
1-
// Metrics: two TCP nodes connect, then one dumps the process-wide Prometheus
2-
// registry as JSON via libp2p_ctx_collect_metrics. The registry is global (it
3-
// belongs to the `metrics` module, not a single node), so a running node with a
4-
// live connection is enough to populate real counters. The generated bindings
5-
// are asynchronous, so every call is wrapped with the blocking helpers in
1+
// Metrics: a running node dumps the process-wide Prometheus registry as JSON
2+
// via libp2p_ctx_collect_metrics. The registry is global, so one started node
3+
// is enough to populate it. Calls are made blocking with the helpers in
64
// common.h.
75
#include "common.h"
86

97
// TransportType / MuxerType ordinals, mirrored from libp2p_ffi/config.nim.
108
static const int64_t TransportTcp = 1;
119
static const int64_t MuxerMplex = 0;
1210

13-
// collect_metrics replies with a JSON string (Result[string]), so it needs its
14-
// own waiter. The document can be large, so keep a generous buffer and record
15-
// whether it was truncated for display.
11+
// collect_metrics replies with a JSON string (Result[string]).
1612
typedef struct {
1713
atomic_int done;
1814
int err_code;
1915
char err[256];
2016
char json[1 << 16];
2117
size_t len;
22-
bool truncated;
2318
} MetricsWaiter;
2419

2520
static void on_metrics(int ec, const NimFfiStr *reply, const char *em,
2621
void *ud) {
2722
MetricsWaiter *w = (MetricsWaiter *)ud;
2823
w->err_code = ec;
2924
if (reply && reply->data) {
30-
size_t cap = sizeof(w->json) - 1;
31-
w->truncated = reply->len > cap;
32-
w->len = w->truncated ? cap : reply->len;
25+
w->len =
26+
reply->len < sizeof(w->json) - 1 ? reply->len : sizeof(w->json) - 1;
3327
memcpy(w->json, reply->data, w->len);
3428
w->json[w->len] = '\0';
3529
}
@@ -38,72 +32,44 @@ static void on_metrics(int ec, const NimFfiStr *reply, const char *em,
3832
atomic_store(&w->done, 1);
3933
}
4034

41-
static LibP2PCtx *createNode(const char *listenAddr, const char *label) {
42-
NimFfiStr addrSlot = nimffi_str(listenAddr);
35+
int main(void) {
36+
NimFfiStr addr = nimffi_str("/ip4/127.0.0.1/tcp/5041");
4337
Libp2pConfig cfg;
4438
memset(&cfg, 0, sizeof(cfg));
45-
cfg.addrs.data = &addrSlot;
39+
cfg.addrs.data = &addr;
4640
cfg.addrs.len = 1;
4741
cfg.muxer = MuxerMplex;
4842
cfg.transport = TransportTcp;
49-
return await_create(&cfg, label);
50-
}
5143

52-
int main(void) {
53-
LibP2PCtx *server = createNode("/ip4/127.0.0.1/tcp/5041", "server");
54-
LibP2PCtx *client = createNode("/ip4/127.0.0.1/tcp/5042", "client");
55-
if (!server || !client) {
56-
libp2p_ctx_destroy(server);
57-
libp2p_ctx_destroy(client);
44+
LibP2PCtx *node = await_create(&cfg, "node");
45+
if (!node)
5846
return 1;
59-
}
6047

6148
int status = 1;
6249
BoolWaiter bw;
63-
if (!AWAIT_BOOL(bw, libp2p_ctx_start(server, on_bool, &bw), "start server") ||
64-
!AWAIT_BOOL(bw, libp2p_ctx_start(client, on_bool, &bw), "start client"))
50+
if (!AWAIT_BOOL(bw, libp2p_ctx_start(node, on_bool, &bw), "start"))
6551
goto cleanup;
6652

67-
PeerInfoWaiter pw;
68-
if (!await_peerinfo(server, &pw, "peerinfo"))
69-
goto cleanup;
70-
71-
NimFfiStr connAddrs[MAX_ADDRS];
72-
for (size_t i = 0; i < pw.naddrs; i++)
73-
connAddrs[i] = nimffi_str(pw.addrs[i]);
74-
ConnectRequest connReq = {nimffi_str(pw.peerId), {connAddrs, pw.naddrs}, 0};
75-
if (!AWAIT_BOOL(bw, libp2p_ctx_connect(client, &connReq, on_bool, &bw),
76-
"connect"))
77-
goto cleanup;
78-
79-
// Let identify and the muxer settle so their counters are non-zero.
80-
sleep_ms(500);
81-
8253
MetricsWaiter mw;
8354
memset(&mw, 0, sizeof(mw));
84-
libp2p_ctx_collect_metrics(server, on_metrics, &mw);
55+
libp2p_ctx_collect_metrics(node, on_metrics, &mw);
8556
if (!wait_done(&mw.done) || mw.err_code != 0) {
8657
fprintf(stderr, "collect_metrics: %s\n", mw.err[0] ? mw.err : "unknown");
8758
goto cleanup;
8859
}
8960

90-
// The payload is a JSON array of {name,type,help,labels,value,timestamp}
91-
// objects. Print a short prefix rather than the whole document.
92-
printf("Collected %zu bytes of metrics%s\n", mw.len,
93-
mw.truncated ? " (truncated)" : "");
94-
printf("%.512s%s\n", mw.json, mw.len > 512 ? " ..." : "");
61+
// A JSON array of {name,type,help,labels,value,timestamp} objects; print a
62+
// prefix rather than the whole document.
63+
printf("Collected %zu bytes of metrics\n", mw.len);
64+
printf("%.400s%s\n", mw.json, mw.len > 400 ? " ..." : "");
9565

96-
// A running node always registers libp2p collectors, so a well-formed,
97-
// non-empty JSON array with at least one named metric is the success signal.
98-
if (mw.len > 2 && mw.json[0] == '[' && strstr(mw.json, "\"name\""))
66+
if (mw.json[0] == '[' && strstr(mw.json, "\"name\""))
9967
status = 0;
10068
else
10169
fprintf(stderr, "Error: metrics payload was empty or malformed\n");
10270

10371
cleanup:
104-
AWAIT_BOOL(bw, libp2p_ctx_stop(client, on_bool, &bw), "stop client");
105-
AWAIT_BOOL(bw, libp2p_ctx_stop(server, on_bool, &bw), "stop server");
106-
libp2p_ctx_destroy(client);
107-
libp2p_ctx_destroy(server);
72+
AWAIT_BOOL(bw, libp2p_ctx_stop(node, on_bool, &bw), "stop");
73+
libp2p_ctx_destroy(node);
10874
return status;
10975
}

cbind/examples/peerstore.c

Lines changed: 65 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
// Peerstore: a node's local book of what it knows about other peers. This
2-
// example drives the store directly — no dialing required — by taking a second
3-
// node's real PeerInfo and then adding, inspecting, updating and removing it
4-
// through the peerstore API. The generated bindings are asynchronous, so every
5-
// call is wrapped with the blocking helpers in common.h.
1+
// Peerstore: a node's local record of other peers. This drives the store
2+
// directly — no dialing — using a second node's real PeerInfo: add the peer,
3+
// list it, read it back, then delete it. Calls are made blocking via common.h.
64
#include "common.h"
75

86
// TransportType / MuxerType ordinals, mirrored from libp2p_ffi/config.nim.
97
static const int64_t TransportTcp = 1;
108
static const int64_t MuxerMplex = 0;
119

12-
static const char *CustomProto = "/cbind/peerstore/1.0.0";
10+
static const char *Proto = "/cbind/peerstore/1.0.0";
1311

1412
// get_peers replies with a PeersResponse of peer-id strings.
1513
#define MAX_PEERS 16
@@ -37,61 +35,49 @@ static void on_peers(int ec, const PeersResponse *reply, const char *em,
3735
atomic_store(&w->done, 1);
3836
}
3937

40-
// get_peer_info replies with the full PeerStoreEntryResponse for one peer.
38+
static bool get_peers(LibP2PCtx *ctx, PeersWaiter *w) {
39+
memset(w, 0, sizeof(*w));
40+
libp2p_ctx_peerstore_get_peers(ctx, on_peers, w);
41+
if (!wait_done(&w->done) || w->err_code != 0) {
42+
fprintf(stderr, "get_peers: %s\n", w->err[0] ? w->err : "unknown");
43+
return false;
44+
}
45+
return true;
46+
}
47+
48+
static bool holds(const PeersWaiter *w, const char *peerId) {
49+
for (size_t i = 0; i < w->n; i++)
50+
if (strcmp(w->peerIds[i], peerId) == 0)
51+
return true;
52+
return false;
53+
}
54+
55+
// get_peer_info replies with the full entry; we only report its counts here.
4156
typedef struct {
4257
atomic_int done;
4358
int err_code;
4459
char err[256];
45-
char addrs[MAX_ADDRS][256];
46-
size_t naddrs;
47-
char protocols[MAX_ADDRS][128];
48-
size_t nprotocols;
49-
} PeerEntryWaiter;
50-
51-
static void on_peer_entry(int ec, const PeerStoreEntryResponse *reply,
52-
const char *em, void *ud) {
53-
PeerEntryWaiter *w = (PeerEntryWaiter *)ud;
60+
size_t naddrs, nprotocols;
61+
} EntryWaiter;
62+
63+
static void on_entry(int ec, const PeerStoreEntryResponse *reply,
64+
const char *em, void *ud) {
65+
EntryWaiter *w = (EntryWaiter *)ud;
5466
w->err_code = ec;
5567
if (reply) {
56-
w->naddrs = reply->addrs.len < MAX_ADDRS ? reply->addrs.len : MAX_ADDRS;
57-
for (size_t i = 0; i < w->naddrs; i++)
58-
if (reply->addrs.data[i].data)
59-
snprintf(w->addrs[i], sizeof(w->addrs[i]), "%s",
60-
reply->addrs.data[i].data);
61-
w->nprotocols =
62-
reply->protocols.len < MAX_ADDRS ? reply->protocols.len : MAX_ADDRS;
63-
for (size_t i = 0; i < w->nprotocols; i++)
64-
if (reply->protocols.data[i].data)
65-
snprintf(w->protocols[i], sizeof(w->protocols[i]), "%s",
66-
reply->protocols.data[i].data);
68+
w->naddrs = reply->addrs.len;
69+
w->nprotocols = reply->protocols.len;
6770
}
6871
if (em)
6972
snprintf(w->err, sizeof(w->err), "%s", em);
7073
atomic_store(&w->done, 1);
7174
}
7275

73-
static bool get_entry(LibP2PCtx *ctx, const char *peerId, PeerEntryWaiter *w) {
74-
memset(w, 0, sizeof(*w));
75-
libp2p_ctx_peerstore_get_peer_info(ctx, nimffi_str(peerId), on_peer_entry, w);
76-
if (!wait_done(&w->done) || w->err_code != 0) {
77-
fprintf(stderr, "get_peer_info: %s\n", w->err[0] ? w->err : "unknown");
78-
return false;
79-
}
80-
return true;
81-
}
82-
83-
static bool has_protocol(const PeerEntryWaiter *w, const char *proto) {
84-
for (size_t i = 0; i < w->nprotocols; i++)
85-
if (strcmp(w->protocols[i], proto) == 0)
86-
return true;
87-
return false;
88-
}
89-
90-
static LibP2PCtx *createNode(const char *listenAddr, const char *label) {
91-
NimFfiStr addrSlot = nimffi_str(listenAddr);
76+
static LibP2PCtx *createNode(const char *addr, const char *label) {
77+
NimFfiStr slot = nimffi_str(addr);
9278
Libp2pConfig cfg;
9379
memset(&cfg, 0, sizeof(cfg));
94-
cfg.addrs.data = &addrSlot;
80+
cfg.addrs.data = &slot;
9581
cfg.addrs.len = 1;
9682
cfg.muxer = MuxerMplex;
9783
cfg.transport = TransportTcp;
@@ -102,8 +88,8 @@ int main(void) {
10288
int status = 1;
10389
BoolWaiter bw;
10490

105-
// The "local" node owns the peerstore we drive. The "other" node only exists
106-
// to hand us a real peer id and listen addresses to store.
91+
// `local` owns the peerstore we drive; `other` just hands us a real peer id
92+
// and listen addresses to store.
10793
LibP2PCtx *local = createNode("/ip4/127.0.0.1/tcp/5051", "local");
10894
LibP2PCtx *other = createNode("/ip4/127.0.0.1/tcp/5052", "other");
10995
if (!local || !other) {
@@ -115,96 +101,56 @@ int main(void) {
115101
// Start `other` so its listen addresses are bound and reported by peer_info.
116102
if (!AWAIT_BOOL(bw, libp2p_ctx_start(other, on_bool, &bw), "start other"))
117103
goto cleanup;
118-
119-
PeerInfoWaiter other_info;
120-
if (!await_peerinfo(other, &other_info, "other peerinfo"))
104+
PeerInfoWaiter oi;
105+
if (!await_peerinfo(other, &oi, "other peerinfo"))
121106
goto cleanup;
122-
printf("Peer to store: %s\n", other_info.peerId);
107+
printf("Peer to store: %s\n", oi.peerId);
123108

124-
// ── add_peer: merge addresses (and a protocol) into the address book ───────
109+
// add_peer: merge the peer's addresses and a protocol into the store.
125110
NimFfiStr addrs[MAX_ADDRS];
126-
for (size_t i = 0; i < other_info.naddrs; i++)
127-
addrs[i] = nimffi_str(other_info.addrs[i]);
128-
NimFfiStr protoSlot = nimffi_str(CustomProto);
129-
AddPeerRequest addReq = {nimffi_str(other_info.peerId),
130-
{addrs, other_info.naddrs},
131-
{&protoSlot, 1}};
111+
for (size_t i = 0; i < oi.naddrs; i++)
112+
addrs[i] = nimffi_str(oi.addrs[i]);
113+
NimFfiStr proto = nimffi_str(Proto);
114+
AddPeerRequest addReq = {
115+
nimffi_str(oi.peerId), {addrs, oi.naddrs}, {&proto, 1}};
132116
if (!AWAIT_BOOL(bw,
133117
libp2p_ctx_peerstore_add_peer(local, &addReq, on_bool, &bw),
134118
"add_peer"))
135119
goto cleanup;
136-
printf("Added %s with %zu address(es) and protocol %s\n", other_info.peerId,
137-
other_info.naddrs, CustomProto);
138120

139-
// ── get_peers: the stored peer should now be listed ───────────────────────
121+
// get_peers + get_peer_info: the peer is now listed and readable.
140122
PeersWaiter peers;
141-
memset(&peers, 0, sizeof(peers));
142-
libp2p_ctx_peerstore_get_peers(local, on_peers, &peers);
143-
if (!wait_done(&peers.done) || peers.err_code != 0) {
144-
fprintf(stderr, "get_peers: %s\n", peers.err[0] ? peers.err : "unknown");
123+
if (!get_peers(local, &peers))
145124
goto cleanup;
146-
}
147-
bool listed = false;
148-
printf("Peerstore holds %zu peer(s):\n", peers.n);
149-
for (size_t i = 0; i < peers.n; i++) {
150-
printf(" %s\n", peers.peerIds[i]);
151-
if (strcmp(peers.peerIds[i], other_info.peerId) == 0)
152-
listed = true;
153-
}
154-
if (!listed) {
155-
fprintf(stderr, "Error: stored peer not found in get_peers\n");
125+
EntryWaiter entry;
126+
memset(&entry, 0, sizeof(entry));
127+
libp2p_ctx_peerstore_get_peer_info(local, nimffi_str(oi.peerId), on_entry,
128+
&entry);
129+
if (!wait_done(&entry.done) || entry.err_code != 0) {
130+
fprintf(stderr, "get_peer_info: %s\n",
131+
entry.err[0] ? entry.err : "unknown");
156132
goto cleanup;
157133
}
158-
159-
// ── get_peer_info: read back the stored addresses and protocols ───────────
160-
PeerEntryWaiter entry;
161-
if (!get_entry(local, other_info.peerId, &entry))
162-
goto cleanup;
163-
printf("Stored entry: %zu address(es), %zu protocol(s)\n", entry.naddrs,
164-
entry.nprotocols);
165-
if (entry.naddrs == 0 || !has_protocol(&entry, CustomProto)) {
166-
fprintf(stderr, "Error: stored entry is missing its address or protocol\n");
167-
goto cleanup;
168-
}
169-
170-
// ── set_peer_protocols: replace the protocol set, then verify the change ──
171-
const char *NewProto = "/cbind/peerstore/2.0.0";
172-
NimFfiStr newProtoSlot = nimffi_str(NewProto);
173-
SetProtocolsRequest setReq = {nimffi_str(other_info.peerId),
174-
{&newProtoSlot, 1}};
175-
if (!AWAIT_BOOL(
176-
bw,
177-
libp2p_ctx_peerstore_set_peer_protocols(local, &setReq, on_bool, &bw),
178-
"set_peer_protocols"))
179-
goto cleanup;
180-
if (!get_entry(local, other_info.peerId, &entry))
181-
goto cleanup;
182-
if (has_protocol(&entry, CustomProto) || !has_protocol(&entry, NewProto)) {
183-
fprintf(stderr,
184-
"Error: set_peer_protocols did not replace the protocols\n");
134+
printf("Stored: %zu peer(s), entry has %zu address(es) and %zu protocol(s)\n",
135+
peers.n, entry.naddrs, entry.nprotocols);
136+
if (!holds(&peers, oi.peerId) || entry.naddrs == 0 || entry.nprotocols == 0) {
137+
fprintf(stderr, "Error: peer was not stored correctly\n");
185138
goto cleanup;
186139
}
187-
printf("Protocols replaced with %s\n", NewProto);
188140

189-
// ── delete_peer: the store should be empty of it afterwards ───────────────
141+
// delete_peer: the store no longer holds it.
190142
if (!AWAIT_BOOL(bw,
191-
libp2p_ctx_peerstore_delete_peer(
192-
local, nimffi_str(other_info.peerId), on_bool, &bw),
143+
libp2p_ctx_peerstore_delete_peer(local, nimffi_str(oi.peerId),
144+
on_bool, &bw),
193145
"delete_peer"))
194146
goto cleanup;
195-
memset(&peers, 0, sizeof(peers));
196-
libp2p_ctx_peerstore_get_peers(local, on_peers, &peers);
197-
if (!wait_done(&peers.done) || peers.err_code != 0) {
198-
fprintf(stderr, "get_peers: %s\n", peers.err[0] ? peers.err : "unknown");
147+
if (!get_peers(local, &peers))
148+
goto cleanup;
149+
if (holds(&peers, oi.peerId)) {
150+
fprintf(stderr, "Error: peer still present after delete_peer\n");
199151
goto cleanup;
200152
}
201-
for (size_t i = 0; i < peers.n; i++) {
202-
if (strcmp(peers.peerIds[i], other_info.peerId) == 0) {
203-
fprintf(stderr, "Error: peer still present after delete_peer\n");
204-
goto cleanup;
205-
}
206-
}
207-
printf("Deleted %s from the peerstore\n", other_info.peerId);
153+
printf("Deleted %s\n", oi.peerId);
208154
status = 0;
209155

210156
cleanup:

0 commit comments

Comments
 (0)