╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Notify.zig ───────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯
31 32 const Self = @This(); 33 34 // the moment keys `evt.merge` reads and writes for this kind 35 pub const merge_policy: evt.MergePolicy = .target_wins; 36 pub const record_map_key = "event-id->notify"; 37 pub const all_id_set_key = "notify-id-set"; 38 39 // the id of the one record a user can hold on a thread 40 pub fn idOf(repo_id: *const [evt.event_id_size]u8, thread_id: *const [evt.event_id_size]u8) [evt.event_id_size]u8 { 41 var hasher = std.crypto.hash.sha2.Sha256.init(.{}); 42 // the kind name keeps derived ids of different kinds apart 43 hasher.update(@tagName(evt.EventKind.notify)); 44 hasher.update(repo_id); 45 hasher.update(thread_id); 46 var digest: [std.crypto.hash.sha2.Sha256.digest_length]u8 = undefined; 47 hasher.final(&digest); 48 return digest[0..evt.event_id_size].*; 49 } 50 51 // only what the event says about itself is checked. a record naming a missing 52 // repo or thread is inert. 53 fn validate(event_id: *const [evt.event_id_size]u8, record: Record) !void { 54 _ = try evt.parseEventId(&record.event.owner_id); 55 const repo_id = try evt.parseEventId(&record.event.repo_id); 56 const thread_id = try evt.parseEventId(&record.event.thread_id); 57 if (!std.mem.eql(u8, event_id, &idOf(&repo_id, &thread_id))) return error.InvalidNotifyId; 58 } 59 60 pub fn consume( 61 comptime DB: type, 62 comptime hash_kind: hash.HashKind, 63 haxy_moment: DB.HashMap(.read_write), 64 event_id: *const [evt.event_id_size]u8, 65 record_maybe: ?Record, 66 arena: *std.heap.ArenaAllocator, 67 _: ?[]const u8, 68 ) !void { 69 const notify_key = hash.hashInt(hash_kind, event_id); 70 const records = try DB.HashMap(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, record_map_key))); 71 72 var existing_maybe: ?Record = null; 73 const existing_cursor_maybe = try records.getCursor(notify_key); 74 if (existing_cursor_maybe) |cursor| { 75 existing_maybe = try evt.read(Record, DB, hash_kind, arena, try DB.HashMap(.read_only).init(cursor)); 76 } 77 78 var record = record_maybe orelse try evt.removedRecord(Record, DB, hash_kind, haxy_moment.readOnly(), existing_maybe); 79 80 if (!record.removed) try validate(event_id, record); 81 82 if (existing_maybe) |existing| { 83 // updates preserve the original creation metadata 84 record.created_order = existing.created_order; 85 } 86 87 const notify_cursor = try records.putCursor(notify_key); 88 try evt.upsert(Record, DB, hash_kind, try DB.HashMap(.read_write).init(notify_cursor), record); 89 try evt.indexEvent(DB, hash_kind, haxy_moment, event_id, .notify, existing_maybe, record); 90 91 // the id set retains removed records so merges can carry removals 92 if (existing_cursor_maybe == null) { 93 const ids = try DB.SortedSet(.read_write).init(try haxy_moment.putCursor(hash.hashInt(hash_kind, all_id_set_key))); 94 try ids.put(&evt.orderKeyDesc(record.created_order, event_id)); 95 } 96 } 97 98 // the user's mode for the thread, or null without a record 99 pub fn readMode( 100 comptime DB: type, 101 comptime hash_kind: hash.HashKind, 102 haxy_moment: DB.HashMap(.read_only), 103 arena: *std.heap.ArenaAllocator, 104 repo_id: *const [evt.event_id_size]u8, 105 thread_id: *const [evt.event_id_size]u8, 106 ) !?Mode { 107 const record = (try evt.readRecordSubset(Self, struct { removed: bool, event: struct { mode: Mode } }, DB, hash_kind, haxy_moment, arena, &idOf(repo_id, thread_id))) orelse return null; 108 return if (record.removed) null else record.event.mode; 109 } 110