71 lines
2.1 KiB
Zig
71 lines
2.1 KiB
Zig
//! RFC-0120 S5.2: Peer Table
|
|
//! Manages a list of known nodes on the network and their health/trust metrics.
|
|
|
|
const std = @import("std");
|
|
const net = std.net;
|
|
|
|
pub const Peer = struct {
|
|
address: net.Address,
|
|
did_short: [8]u8, // Short hash of DID (RFC-0120 S4.1)
|
|
last_seen: i64,
|
|
trust_score: f32 = 1.0,
|
|
is_active: bool = true,
|
|
};
|
|
|
|
pub const PeerTable = struct {
|
|
allocator: std.mem.Allocator,
|
|
peers: std.AutoHashMap([8]u8, Peer),
|
|
mutex: std.Thread.Mutex,
|
|
|
|
pub fn init(allocator: std.mem.Allocator) PeerTable {
|
|
return PeerTable{
|
|
.allocator = allocator,
|
|
.peers = std.AutoHashMap([8]u8, Peer).init(allocator),
|
|
.mutex = .{},
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: *PeerTable) void {
|
|
self.peers.deinit();
|
|
}
|
|
|
|
/// Update or add a peer to the table
|
|
pub fn updatePeer(self: *PeerTable, did_short: [8]u8, address: net.Address) !void {
|
|
self.mutex.lock();
|
|
defer self.mutex.unlock();
|
|
|
|
const now = std.time.timestamp();
|
|
if (self.peers.getPtr(did_short)) |peer| {
|
|
peer.address = address;
|
|
peer.last_seen = now;
|
|
peer.is_active = true;
|
|
} else {
|
|
try self.peers.put(did_short, Peer{
|
|
.address = address,
|
|
.did_short = did_short,
|
|
.last_seen = now,
|
|
});
|
|
std.log.info("Discovered new peer: {x} at {f}", .{ did_short, address });
|
|
}
|
|
}
|
|
|
|
/// Mark peers as inactive if not seen for a while (Decay)
|
|
pub fn tick(self: *PeerTable) void {
|
|
self.mutex.lock();
|
|
defer self.mutex.unlock();
|
|
|
|
const now = std.time.timestamp();
|
|
const timeout = 300; // 5 minutes
|
|
|
|
var it = self.peers.iterator();
|
|
while (it.next()) |entry| {
|
|
if (now - entry.value_ptr.last_seen > timeout) {
|
|
if (entry.value_ptr.is_active) {
|
|
entry.value_ptr.is_active = false;
|
|
std.log.debug("Peer timed out: {x}", .{entry.key_ptr.*});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|