records.v

3.9 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>/objects/<hash>   the object's compressed bytes, as in the table7//!   <repo>/saves/<id>       the full save record, including its file list8//!   <repo>/events/<id>      one flag, clear or strip event9//!   <repo>/head             the ID of the newest save on the line10//!11//! Only `head` is ever overwritten, and only with a matching version tag.1213module exchange1415import json216import src.events17import src.history18import src.snapshot19import src.storage2021pub fn object_key(repo string, hash string) string {22	return '${repo}/objects/${hash}'23}2425pub fn save_key(repo string, id string) string {26	return '${repo}/saves/${id}'27}2829pub fn event_key(repo string, id string) string {30	return '${repo}/events/${id}'31}3233pub fn head_key(repo string) string {34	return '${repo}/head'35}3637pub fn events_prefix(repo string) string {38	return '${repo}/events'39}4041pub struct FileRecord {42pub:43	path       string44	hash       string45	executable bool46}4748pub struct SaveRecord {49pub:50	id            string51	parent        string52	message       string53	created_at    i6454	machine       string55	is_checkpoint bool56	size_bytes    i6457	agent         string58	session       string59	restores      string60	replayed_from string61	files         []FileRecord62}6364// save_record turns a local save into what travels. The file list is part of65// the record, which is why a save needs one round trip, not one per file.66pub fn save_record(store &storage.Store, save history.Save) !SaveRecord {67	files := history.files_of(store, save.id)!68	mut records := []FileRecord{}69	for file in files {70		records << FileRecord{71			path:       file.path72			hash:       file.hash73			executable: file.executable74		}75	}76	return SaveRecord{77		id:            save.id78		parent:        save.parent79		message:       save.message80		created_at:    save.created_at81		machine:       save.machine82		is_checkpoint: save.is_checkpoint83		size_bytes:    save.size_bytes84		agent:         save.agent85		session:       save.session86		restores:      save.restores87		replayed_from: save.replayed_from88		files:         records89	}90}9192pub fn encode_save(record SaveRecord) string {93	return json2.encode(record)94}9596pub fn decode_save(body []u8) !SaveRecord {97	return json2.decode[SaveRecord](body.bytestr())!98}99100pub fn to_save(record SaveRecord) history.Save {101	return history.Save{102		id:            record.id103		parent:        record.parent104		message:       record.message105		created_at:    record.created_at106		machine:       record.machine107		is_checkpoint: record.is_checkpoint108		size_bytes:    record.size_bytes109		agent:         record.agent110		session:       record.session111		restores:      record.restores112		replayed_from: record.replayed_from113	}114}115116pub fn to_files(record SaveRecord) []snapshot.FileEntry {117	mut files := []snapshot.FileEntry{}118	for file in record.files {119		files << snapshot.FileEntry{120			path:       file.path121			hash:       file.hash122			executable: file.executable123		}124	}125	return files126}127128pub struct EventRecord {129pub:130	id         string131	kind       string132	save_id    string133	path       string134	reason     string135	created_at i64136	machine    string137}138139pub fn event_record(event events.Event) EventRecord {140	return EventRecord{141		id:         event.id142		kind:       event.kind143		save_id:    event.save_id144		path:       event.path145		reason:     event.reason146		created_at: event.created_at147		machine:    event.machine148	}149}150151pub fn encode_event(event events.Event) string {152	return json2.encode(event_record(event))153}154155pub fn decode_event(body []u8) !events.Event {156	record := json2.decode[EventRecord](body.bytestr())!157	return events.Event{158		id:         record.id159		kind:       record.kind160		save_id:    record.save_id161		path:       record.path162		reason:     record.reason163		created_at: record.created_at164		machine:    record.machine165	}166}