Something went wrong. Try again.
atproto relay in zig zlay.waow.tech
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128const std = @import("std");const zat = @import("zat");
pub const Source = struct { frame: []const u8, host: []const u8 };pub const Capture = struct { pub const max_samples = 16; pub const max_frame_bytes = 2 * 1024 * 1024; dir: ?std.Io.Dir = null, mutex: std.Io.Mutex = .init, next_slot: usize = 0, fingerprints: [max_samples]u64 = undefined, fingerprint_count: usize = 0,
pub fn open(self: *Capture, io: std.Io, path: []const u8) !void { self.dir = try std.Io.Dir.cwd().createDirPathOpen(io, path, .{ .permissions = .fromMode(0o700) }); }
pub fn deinit(self: *Capture, io: std.Io) void { if (self.dir) |d| d.close(io); }
pub fn record(self: *Capture, io: std.Io, allocator: std.mem.Allocator, source: Source, did: []const u8, err: anyerror, key: []const u8, curve: []const u8) void { const dir = self.dir orelse return; if (source.frame.len > max_frame_bytes or source.host.len > 256 or did.len > 2048 or key.len > 65) return; if (!self.mutex.tryLock()) return; defer self.mutex.unlock(io); if (self.next_slot == max_samples or self.fingerprint_count == max_samples) return; var hash = std.hash.Wyhash.init(0); hash.update(did); hash.update(@errorName(err)); const fingerprint = hash.final(); for (self.fingerprints[0..self.fingerprint_count]) |seen| if (seen == fingerprint) return; self.fingerprints[self.fingerprint_count] = fingerprint; self.fingerprint_count += 1; var arena = std.heap.ArenaAllocator.init(allocator); defer arena.deinit(); const packet = zat.cbor.encodeAlloc(arena.allocator(), .{ .map = &.{ .{ .key = "frame", .value = .{ .bytes = source.frame } }, .{ .key = "host", .value = .{ .text = source.host } }, .{ .key = "error", .value = .{ .text = @errorName(err) } }, .{ .key = "key", .value = .{ .bytes = key } }, .{ .key = "curve", .value = .{ .text = curve } }, } }) catch { self.next_slot = max_samples; return; }; while (self.next_slot < max_samples) { const slot = self.next_slot; self.next_slot += 1; var name_buf: [32]u8 = undefined; const name = std.fmt.bufPrint(&name_buf, "proof-{d}.cbor", .{slot}) catch unreachable; const file = dir.createFile(io, name, .{ .exclusive = true, .permissions = .fromMode(0o600) }) catch |e| { if (e == error.PathAlreadyExists) continue; std.log.warn("proof capture unavailable: {s}", .{@errorName(e)}); self.next_slot = max_samples; return; }; defer file.close(io); file.writeStreamingAll(io, packet) catch |e| { std.log.warn("proof capture write failed: {s}", .{@errorName(e)}); self.next_slot = max_samples; return; }; std.log.warn("proof capture file={s} host={s} did={s} error={s} bytes={d}", .{ name, source.host, did, @errorName(err), source.frame.len }); return; } }};
test "capture is bounded, deduplicated, and preserves original bytes across reopening" { const io = std.testing.io; var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var capture: Capture = .{ .dir = tmp.dir }; const source: Source = .{ .frame = "original frame", .host = "test.invalid" }; capture.record(io, std.testing.allocator, source, "did:plc:first", error.PartialTree, "key", "p256"); capture.record(io, std.testing.allocator, source, "did:plc:first", error.PartialTree, "key", "p256"); for (0..32) |i| { var buf: [32]u8 = undefined; const did = try std.fmt.bufPrint(&buf, "did:plc:{d}", .{i}); capture.record(io, std.testing.allocator, source, did, error.PartialTree, "key", "p256"); } try std.testing.expectEqual(@as(usize, 16), capture.next_slot); const file = try tmp.dir.openFile(io, "proof-0.cbor", .{}); defer file.close(io); var buffer: [2048]u8 = undefined; var reader = file.readerStreaming(io, &buffer); const bytes = try reader.interface.allocRemaining(std.testing.allocator, .limited(2048)); defer std.testing.allocator.free(bytes); var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); const packet = try zat.cbor.decodeAll(arena.allocator(), bytes); try std.testing.expectEqualStrings(source.frame, packet.getBytes("frame").?); try std.testing.expectEqualStrings("PartialTree", packet.getString("error").?); var reopened: Capture = .{ .dir = tmp.dir }; reopened.record(io, std.testing.allocator, source, "did:plc:new", error.PartialTree, "key", "p256"); try std.testing.expectEqual(@as(usize, 16), reopened.next_slot); try std.testing.expectError(error.FileNotFound, tmp.dir.openFile(io, "proof-16.cbor", .{}));}
test "oversized samples and contention do not consume capture slots" { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var capture: Capture = .{ .dir = tmp.dir }; const frame = try std.testing.allocator.alloc(u8, Capture.max_frame_bytes + 1); defer std.testing.allocator.free(frame); capture.record(std.testing.io, std.testing.allocator, .{ .frame = frame, .host = "test.invalid" }, "did:plc:large", error.PartialTree, "key", "p256"); try std.testing.expect(capture.mutex.tryLock()); capture.record(std.testing.io, std.testing.allocator, .{ .frame = "frame", .host = "test.invalid" }, "did:plc:busy", error.PartialTree, "key", "p256"); capture.mutex.unlock(std.testing.io); try std.testing.expectEqual(@as(usize, 0), capture.next_slot);}
test "allocation failure disables capture without accumulating fingerprints" { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var capture: Capture = .{ .dir = tmp.dir }; var failing = std.testing.FailingAllocator.init(std.testing.allocator, .{ .fail_index = 0 }); for (0..32) |i| { var buf: [32]u8 = undefined; const did = try std.fmt.bufPrint(&buf, "did:plc:{d}", .{i}); capture.record(std.testing.io, failing.allocator(), .{ .frame = "frame", .host = "test.invalid" }, did, error.PartialTree, "key", "p256"); } try std.testing.expectEqual(@as(usize, Capture.max_samples), capture.next_slot); try std.testing.expectEqual(@as(usize, 1), capture.fingerprint_count); try std.testing.expectError(error.FileNotFound, tmp.dir.openFile(std.testing.io, "proof-0.cbor", .{}));}