records.v

4.0 KB · raw

1//! What a save and an event look like on the remote.2//!3//! Records are JSON so a person can read the bucket, and the layout is the4//! same for every backend:5//!6//   <repo>/format          the remote layout, `koh-remote 1`7//   <repo>/objects/<hash>   the object's compressed bytes, as in the table8//   <repo>/saves/<id>       the full save record, including its file list9//   <repo>/events/<id>      one flag, clear or strip event10//   <repo>/head             the ID of the newest save on the line11//12// Only `head` is ever overwritten, and only with a matching version tag.1314module 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 string66	files         []FileRecord67}6869// save_record turns a local save into what travels. The file list is part of70// the record, which is why a save needs one round trip, not one per file.71pub fn save_record(store &storage.Store, save history.Save) !SaveRecord {72	files := history.files_of(store, save.id)!73	mut records := []FileRecord{}74	for file in files {75		records << FileRecord{76			path:       file.path77			hash:       file.hash78			executable: file.executable79		}80	}81	return SaveRecord{82		id:            save.id83		parent:        save.parent84		message:       save.message85		created_at:    save.created_at86		machine:       save.machine87		is_checkpoint: save.is_checkpoint88		size_bytes:    save.size_bytes89		agent:         save.agent90		session:       save.session91		restores:      save.restores92		replayed_from: save.replayed_from93		files:         records94	}95}9697pub fn encode_save(record SaveRecord) string {98	return json2.encode(record)99}100101pub fn decode_save(body []u8) !SaveRecord {102	return json2.decode[SaveRecord](body.bytestr())!103}104105pub fn to_save(record SaveRecord) history.Save {106	return history.Save{107		id:            record.id108		parent:        record.parent109		message:       record.message110		created_at:    record.created_at111		machine:       record.machine112		is_checkpoint: record.is_checkpoint113		size_bytes:    record.size_bytes114		agent:         record.agent115		session:       record.session116		restores:      record.restores117		replayed_from: record.replayed_from118	}119}120121pub fn to_files(record SaveRecord) []snapshot.FileEntry {122	mut files := []snapshot.FileEntry{}123	for file in record.files {124		files << snapshot.FileEntry{125			path:       file.path126			hash:       file.hash127			executable: file.executable128		}129	}130	return files131}132133pub struct EventRecord {134pub:135	id         string136	kind       string137	save_id    string138	path       string139	reason     string140	created_at i64141	machine    string142}143144pub fn event_record(event events.Event) EventRecord {145	return EventRecord{146		id:         event.id147		kind:       event.kind148		save_id:    event.save_id149		path:       event.path150		reason:     event.reason151		created_at: event.created_at152		machine:    event.machine153	}154}155156pub fn encode_event(event events.Event) string {157	return json2.encode(event_record(event))158}159160pub fn decode_event(body []u8) !events.Event {161	record := json2.decode[EventRecord](body.bytestr())!162	return events.Event{163		id:         record.id164		kind:       record.kind165		save_id:    record.save_id166		path:       record.path167		reason:     record.reason168		created_at: record.created_at169		machine:    record.machine170	}171}