1234567891011121314module exchange1516import json217import src.events18import src.history19import src.snapshot20import src.storage2122pub fn format_key(repo string) string {23 return '${repo}/format'24}2526pub fn object_key(repo string, hash string) string {27 return '${repo}/objects/${hash}'28}2930pub fn save_key(repo string, id string) string {31 return '${repo}/saves/${id}'32}3334pub fn event_key(repo string, id string) string {35 return '${repo}/events/${id}'36}3738pub fn head_key(repo string) string {39 return '${repo}/head'40}4142pub fn events_prefix(repo string) string {43 return '${repo}/events'44}4546pub struct FileRecord {47pub:48 path string49 hash string50 executable bool51}5253pub struct SaveRecord {54pub:55 id string56 parent string57 message string58 created_at i6459 machine string60 is_checkpoint bool61 size_bytes i6462 agent string63 session string64 restores string65 replayed_from string66pub mut:67 files []FileRecord68}69707172pub fn save_record(store &storage.Store, save history.Save) !SaveRecord {73 files := history.files_of(store, save.id)!74 mut records := []FileRecord{}75 for file in files {76 records << FileRecord{77 path: file.path78 hash: file.hash79 executable: file.executable80 }81 }82 return SaveRecord{83 id: save.id84 parent: save.parent85 message: save.message86 created_at: save.created_at87 machine: save.machine88 is_checkpoint: save.is_checkpoint89 size_bytes: save.size_bytes90 agent: save.agent91 session: save.session92 restores: save.restores93 replayed_from: save.replayed_from94 files: records95 }96}9798pub fn encode_save(record SaveRecord) string {99 return json2.encode(record)100}101102pub fn decode_save(body []u8) !SaveRecord {103 return json2.decode[SaveRecord](body.bytestr())!104}105106107pub fn drop_unsafe_paths(mut record SaveRecord) []string {108 mut kept := []FileRecord{}109 mut dropped := []string{}110 for file in record.files {111 if snapshot.legal_path(file.path) {112 kept << file113 } else {114 dropped << snapshot.escape_path(file.path)115 }116 }117 record.files = kept118 dropped.sort()119 return dropped120}121122pub fn to_save(record SaveRecord) history.Save {123 return history.Save{124 id: record.id125 parent: record.parent126 message: record.message127 created_at: record.created_at128 machine: record.machine129 is_checkpoint: record.is_checkpoint130 size_bytes: record.size_bytes131 agent: record.agent132 session: record.session133 restores: record.restores134 replayed_from: record.replayed_from135 }136}137138pub fn to_files(record SaveRecord) []snapshot.FileEntry {139 mut files := []snapshot.FileEntry{}140 for file in record.files {141 files << snapshot.FileEntry{142 path: file.path143 hash: file.hash144 executable: file.executable145 }146 }147 return files148}149150pub struct EventRecord {151pub:152 id string153 kind string154 save_id string155 path string156 reason string157 created_at i64158 machine string159}160161pub fn event_record(event events.Event) EventRecord {162 return EventRecord{163 id: event.id164 kind: event.kind165 save_id: event.save_id166 path: event.path167 reason: event.reason168 created_at: event.created_at169 machine: event.machine170 }171}172173pub fn encode_event(event events.Event) string {174 return json2.encode(event_record(event))175}176177pub fn decode_event(body []u8) !events.Event {178 record := json2.decode[EventRecord](body.bytestr())!179 return events.Event{180 id: record.id181 kind: record.kind182 save_id: record.save_id183 path: record.path184 reason: record.reason185 created_at: record.created_at186 machine: record.machine187 }188}