@@ -13,6 +13,7 @@ const PeerAction = peer_manager.PeerAction;
1313const GoodbyeReasonCode = peer_manager .GoodbyeReasonCode ;
1414const GossipScoreUpdate = peer_manager .GossipScoreUpdate ;
1515const RequestedSubnet = peer_manager .RequestedSubnet ;
16+ const parseExternalPeerActionName = peer_manager .parseExternalPeerActionName ;
1617
1718/// Allocator for internal allocations.
1819const allocator = std .heap .page_allocator ;
@@ -201,6 +202,34 @@ fn readPeerId(value: napi.Value) ![]const u8 {
201202 return try value .getValueStringUtf8 (& buf );
202203}
203204
205+ fn readOwnedPeerId (value : napi.Value ) ! []u8 {
206+ var buf : [128 ]u8 = undefined ;
207+ const peer_id = try value .getValueStringUtf8 (& buf );
208+ return allocator .dupe (u8 , peer_id );
209+ }
210+
211+ fn parsePeerActionName (action_name : []const u8 ) ? PeerAction {
212+ return parseExternalPeerActionName (action_name );
213+ }
214+
215+ fn parseOptionalU32Array (value : napi.Value ) ! ? []u32 {
216+ const value_type = try value .typeof ();
217+ if (value_type == .undefined or value_type == .null ) {
218+ return null ;
219+ }
220+
221+ const len = try value .getArrayLength ();
222+ const items = try allocator .alloc (u32 , len );
223+ errdefer allocator .free (items );
224+
225+ for (0.. len ) | i | {
226+ const elem = try value .getElement (@intCast (i ));
227+ items [i ] = try elem .getValueUint32 ();
228+ }
229+
230+ return items ;
231+ }
232+
204233// ── Lifecycle ────────────────────────────────────────────────────────
205234
206235pub fn PeerManager_init (env : napi.Env , cb : napi .CallbackInfo (1 )) ! napi.Value {
@@ -235,7 +264,8 @@ pub fn PeerManager_checkPingAndStatus(env: napi.Env, _: napi.CallbackInfo(0)) !n
235264
236265pub fn PeerManager_onConnectionOpen (env : napi.Env , cb : napi .CallbackInfo (2 )) ! napi.Value {
237266 const m = try getManager ();
238- const peer_id = try readPeerId (cb .arg (0 ));
267+ const peer_id = try readOwnedPeerId (cb .arg (0 ));
268+ defer allocator .free (peer_id );
239269 var dir_buf : [16 ]u8 = undefined ;
240270 const dir_str = try cb .arg (1 ).getValueStringUtf8 (& dir_buf );
241271 const direction = std .meta .stringToEnum (Direction , dir_str ) orelse
@@ -246,14 +276,16 @@ pub fn PeerManager_onConnectionOpen(env: napi.Env, cb: napi.CallbackInfo(2)) !na
246276
247277pub fn PeerManager_onConnectionClose (env : napi.Env , cb : napi .CallbackInfo (1 )) ! napi.Value {
248278 const m = try getManager ();
249- const peer_id = try readPeerId (cb .arg (0 ));
279+ const peer_id = try readOwnedPeerId (cb .arg (0 ));
280+ defer allocator .free (peer_id );
250281 const actions = try m .onConnectionClose (peer_id );
251282 return actionsToNapiArray (env , actions );
252283}
253284
254285pub fn PeerManager_onStatusReceived (env : napi.Env , cb : napi .CallbackInfo (4 )) ! napi.Value {
255286 const m = try getManager ();
256- const peer_id = try readPeerId (cb .arg (0 ));
287+ const peer_id = try readOwnedPeerId (cb .arg (0 ));
288+ defer allocator .free (peer_id );
257289 const remote_status = try statusFromObject (env , try cb .arg (1 ).coerceToObject ());
258290 const local_status = try statusFromObject (env , try cb .arg (2 ).coerceToObject ());
259291 const current_slot : u64 = @intCast (try cb .arg (3 ).getValueInt64 ());
@@ -263,7 +295,8 @@ pub fn PeerManager_onStatusReceived(env: napi.Env, cb: napi.CallbackInfo(4)) !na
263295
264296pub fn PeerManager_onMetadataReceived (env : napi.Env , cb : napi .CallbackInfo (2 )) ! napi.Value {
265297 const m = try getManager ();
266- const peer_id = try readPeerId (cb .arg (0 ));
298+ const peer_id = try readOwnedPeerId (cb .arg (0 ));
299+ defer allocator .free (peer_id );
267300 const md_obj = try cb .arg (1 ).coerceToObject ();
268301
269302 var metadata : Metadata = undefined ;
@@ -278,23 +311,27 @@ pub fn PeerManager_onMetadataReceived(env: napi.Env, cb: napi.CallbackInfo(2)) !
278311 @memcpy (& metadata .syncnets , syncnets_info .data [0.. 1]);
279312
280313 metadata .custody_group_count = @intCast (try (try md_obj .getNamedProperty ("custodyGroupCount" )).getValueInt64 ());
281- metadata .custody_groups = null ;
282- metadata .sampling_groups = null ;
314+ metadata .custody_groups = try parseOptionalU32Array (try md_obj .getNamedProperty ("custodyGroups" ));
315+ errdefer if (metadata .custody_groups ) | groups | allocator .free (groups );
316+ metadata .sampling_groups = try parseOptionalU32Array (try md_obj .getNamedProperty ("samplingGroups" ));
317+ errdefer if (metadata .sampling_groups ) | groups | allocator .free (groups );
283318
284319 m .onMetadataReceived (peer_id , metadata );
285320 return env .getUndefined ();
286321}
287322
288323pub fn PeerManager_onMessageReceived (env : napi.Env , cb : napi .CallbackInfo (1 )) ! napi.Value {
289324 const m = try getManager ();
290- const peer_id = try readPeerId (cb .arg (0 ));
325+ const peer_id = try readOwnedPeerId (cb .arg (0 ));
326+ defer allocator .free (peer_id );
291327 m .onMessageReceived (peer_id );
292328 return env .getUndefined ();
293329}
294330
295331pub fn PeerManager_onGoodbye (env : napi.Env , cb : napi .CallbackInfo (2 )) ! napi.Value {
296332 const m = try getManager ();
297- const peer_id = try readPeerId (cb .arg (0 ));
333+ const peer_id = try readOwnedPeerId (cb .arg (0 ));
334+ defer allocator .free (peer_id );
298335 const reason_raw : u64 = @intCast (try cb .arg (1 ).getValueInt64 ());
299336 const reason : GoodbyeReasonCode = @enumFromInt (reason_raw );
300337 const actions = try m .onGoodbye (peer_id , reason );
@@ -303,7 +340,8 @@ pub fn PeerManager_onGoodbye(env: napi.Env, cb: napi.CallbackInfo(2)) !napi.Valu
303340
304341pub fn PeerManager_onPing (env : napi.Env , cb : napi .CallbackInfo (2 )) ! napi.Value {
305342 const m = try getManager ();
306- const peer_id = try readPeerId (cb .arg (0 ));
343+ const peer_id = try readOwnedPeerId (cb .arg (0 ));
344+ defer allocator .free (peer_id );
307345 const seq_number : u64 = @intCast (try cb .arg (1 ).getValueInt64 ());
308346 const actions = try m .onPing (peer_id , seq_number );
309347 return actionsToNapiArray (env , actions );
@@ -313,10 +351,11 @@ pub fn PeerManager_onPing(env: napi.Env, cb: napi.CallbackInfo(2)) !napi.Value {
313351
314352pub fn PeerManager_reportPeer (env : napi.Env , cb : napi .CallbackInfo (2 )) ! napi.Value {
315353 const m = try getManager ();
316- const peer_id = try readPeerId (cb .arg (0 ));
354+ const peer_id = try readOwnedPeerId (cb .arg (0 ));
355+ defer allocator .free (peer_id );
317356 var action_buf : [32 ]u8 = undefined ;
318357 const action_str = try cb .arg (1 ).getValueStringUtf8 (& action_buf );
319- const action = std . meta . stringToEnum ( PeerAction , action_str ) orelse
358+ const action = parsePeerActionName ( action_str ) orelse
320359 return error .InvalidPeerAction ;
321360 m .reportPeer (peer_id , action );
322361 return env .getUndefined ();
@@ -328,17 +367,24 @@ pub fn PeerManager_updateGossipScores(env: napi.Env, cb: napi.CallbackInfo(1)) !
328367 const len = try arr .getArrayLength ();
329368 const scores = try allocator .alloc (GossipScoreUpdate , len );
330369 defer allocator .free (scores );
370+ const peer_ids = try allocator .alloc ([]u8 , len );
371+ defer allocator .free (peer_ids );
372+ var initialized : usize = 0 ;
373+ errdefer {
374+ for (peer_ids [0.. initialized ]) | pid | allocator .free (pid );
375+ }
331376
332377 for (0.. len ) | i | {
333378 const entry = try arr .getElement (@intCast (i ));
334- var pid_buf : [ 128 ] u8 = undefined ;
335- const pid = try ( try entry . getNamedProperty ( "peerId" )). getValueStringUtf8 ( & pid_buf ) ;
379+ peer_ids [ i ] = try readOwnedPeerId ( try entry . getNamedProperty ( "peerId" )) ;
380+ initialized += 1 ;
336381 scores [i ] = .{
337- .peer_id = pid ,
382+ .peer_id = peer_ids [ i ] ,
338383 .new_score = try (try entry .getNamedProperty ("score" )).getValueDouble (),
339384 };
340385 }
341386 m .updateGossipScores (scores );
387+ for (peer_ids ) | pid | allocator .free (pid );
342388 return env .getUndefined ();
343389}
344390
@@ -425,7 +471,8 @@ pub fn PeerManager_getConnectedPeers(env: napi.Env, _: napi.CallbackInfo(0)) !na
425471
426472pub fn PeerManager_getPeerData (env : napi.Env , cb : napi .CallbackInfo (1 )) ! napi.Value {
427473 const m = try getManager ();
428- const peer_id = try readPeerId (cb .arg (0 ));
474+ const peer_id = try readOwnedPeerId (cb .arg (0 ));
475+ defer allocator .free (peer_id );
429476 const peer = m .getPeerData (peer_id ) orelse return env .getNull ();
430477
431478 const obj = try env .createObject ();
@@ -459,28 +506,32 @@ pub fn PeerManager_getPeerData(env: napi.Env, cb: napi.CallbackInfo(1)) !napi.Va
459506
460507pub fn PeerManager_getEncodingPreference (env : napi.Env , cb : napi .CallbackInfo (1 )) ! napi.Value {
461508 const m = try getManager ();
462- const peer_id = try readPeerId (cb .arg (0 ));
509+ const peer_id = try readOwnedPeerId (cb .arg (0 ));
510+ defer allocator .free (peer_id );
463511 const encoding = m .getEncodingPreference (peer_id ) orelse return env .getNull ();
464512 return env .createStringUtf8 (@tagName (encoding ));
465513}
466514
467515pub fn PeerManager_getPeerKind (env : napi.Env , cb : napi .CallbackInfo (1 )) ! napi.Value {
468516 const m = try getManager ();
469- const peer_id = try readPeerId (cb .arg (0 ));
517+ const peer_id = try readOwnedPeerId (cb .arg (0 ));
518+ defer allocator .free (peer_id );
470519 const kind = m .getPeerKind (peer_id ) orelse return env .getNull ();
471520 return env .createStringUtf8 (@tagName (kind ));
472521}
473522
474523pub fn PeerManager_getAgentVersion (env : napi.Env , cb : napi .CallbackInfo (1 )) ! napi.Value {
475524 const m = try getManager ();
476- const peer_id = try readPeerId (cb .arg (0 ));
525+ const peer_id = try readOwnedPeerId (cb .arg (0 ));
526+ defer allocator .free (peer_id );
477527 const av = m .getAgentVersion (peer_id ) orelse return env .getNull ();
478528 return env .createStringUtf8 (av );
479529}
480530
481531pub fn PeerManager_getPeerScore (env : napi.Env , cb : napi .CallbackInfo (1 )) ! napi.Value {
482532 const m = try getManager ();
483- const peer_id = try readPeerId (cb .arg (0 ));
533+ const peer_id = try readOwnedPeerId (cb .arg (0 ));
534+ defer allocator .free (peer_id );
484535 return env .createDouble (m .getPeerScore (peer_id ));
485536}
486537
@@ -526,3 +577,16 @@ pub fn register(env: napi.Env, exports: napi.Value) !void {
526577
527578 try exports .setNamedProperty ("peerManager" , pm_obj );
528579}
580+
581+ test "parsePeerActionName accepts Lodestar JS action names" {
582+ try std .testing .expectEqual (PeerAction .mid_tolerance , parsePeerActionName ("MidToleranceError" ).? );
583+ try std .testing .expectEqual (PeerAction .low_tolerance , parsePeerActionName ("LowToleranceError" ).? );
584+ try std .testing .expectEqual (PeerAction .high_tolerance , parsePeerActionName ("HighToleranceError" ).? );
585+ try std .testing .expectEqual (PeerAction .fatal , parsePeerActionName ("Fatal" ).? );
586+ }
587+
588+ test "parsePeerActionName accepts Zig enum names" {
589+ try std .testing .expectEqual (PeerAction .mid_tolerance , parsePeerActionName ("mid_tolerance" ).? );
590+ try std .testing .expectEqual (PeerAction .fatal , parsePeerActionName ("fatal" ).? );
591+ try std .testing .expect (parsePeerActionName ("not-a-real-action" ) == null );
592+ }
0 commit comments