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