use crate::DaemonError;
use file_lock::{FileLock, FileOptions};
use serde_json::{from_reader, json, Value};
use std::{fs::File, io::Seek};
#[derive(Debug)]
pub struct JsonLockedState {
lock: FileLock,
json: Value,
path: String,
}
impl JsonLockedState {
pub fn new(path: &str) -> Self {
let options = FileOptions::new()
.create(true)
.read(true)
.write(true)
.truncate(false);
let lock: FileLock = FileLock::lock(path, false, options)
.unwrap_or_else(|_| panic!("Was not able to receive {path} state lock"));
let json: Value = if lock.file.metadata().unwrap().len().eq(&0) {
json!({})
} else {
let json: Value = from_reader(&lock.file).unwrap();
patch_state_if_old(json)
};
let filename = path.to_owned();
JsonLockedState {
lock,
json,
path: filename,
}
}
pub fn prepare(&mut self, chain_id: &str, deploy_id: &str) {
let json = &mut self.json;
if json.get(chain_id).is_none() {
json[chain_id] = json!({
deploy_id: {},
"code_ids": {}
});
}
}
pub fn state(&self) -> Value {
self.json.clone()
}
pub fn get(&self, chain_id: &str) -> &Value {
&self.json[chain_id]
}
pub fn get_mut(&mut self, chain_id: &str) -> &mut Value {
self.json.get_mut(chain_id).unwrap()
}
pub fn force_write(&mut self) {
self.lock.file.set_len(0).unwrap();
self.lock.file.rewind().unwrap();
serde_json::to_writer_pretty(&self.lock.file, &self.json).unwrap();
}
pub fn path(&self) -> &str {
&self.path
}
}
impl Drop for JsonLockedState {
fn drop(&mut self) {
self.force_write()
}
}
pub fn read(filename: &String) -> Result<Value, DaemonError> {
let file = File::open(filename)
.map_err(|err| DaemonError::OpenFile(filename.to_string(), err.to_string()))?;
let json: serde_json::Value = from_reader(file)?;
Ok(json)
}
pub(crate) fn patch_state_if_old(maybe_old: Value) -> Value {
let expect_object = |v: Value| -> serde_json::Map<String, Value> {
let Value::Object(map) = v else {
panic!("Unexpected daemon state format");
};
map
};
let maybe_old_map = expect_object(maybe_old);
let mut maybe_old_iter = maybe_old_map.iter();
let Some((_maybe_chain_name, maybe_chain_id_object)) = maybe_old_iter.next() else {
return Value::Object(maybe_old_map);
};
let Value::Object(maybe_chain_map) = maybe_chain_id_object else {
panic!("Unexpected daemon state format");
};
if maybe_chain_map.iter().any(|(key, _val)| key == "code_ids") {
return Value::Object(maybe_old_map);
}
let new_state = maybe_old_map.into_iter().fold(
serde_json::Map::new(),
|mut acc, (_chain_name, chain_value)| {
let chain_map = expect_object(chain_value);
acc.extend(chain_map);
acc
},
);
Value::Object(new_state)
}
#[cfg(test)]
mod test_old_patch {
use super::*;
#[test]
fn old_to_new() {
let old_map = json!({
"chain-name": {
"chain-id": {
"abracadabra": {
"open": "sesame"
},
"code_ids": {
"foo": 123
}
}
}
});
let patched = patch_state_if_old(old_map);
let expected = json!({
"chain-id": {
"abracadabra": {
"open": "sesame"
},
"code_ids": {
"foo": 123
}
}
});
assert_eq!(patched, expected);
let not_patched = patch_state_if_old(patched);
assert_eq!(not_patched, expected);
}
#[test]
fn big_test() {
let old_starship_state = json!({
"juno": {
"juno-1": {
"code_ids": {
"abstract:account-factory": 22,
"abstract:ans-host": 20,
"abstract:ibc-client": 26,
"abstract:ibc-host": 27,
"abstract:manager": 24,
"abstract:module-factory": 23,
"abstract:proxy": 25,
"abstract:version-control": 21,
"polytone:note": 9,
"polytone:proxy": 11,
"polytone:voice": 10
},
"default": {
"abstract:account-factory": "juno1j6scewlz8mrsk3dl3a578rmdps8svlz8jltwpa5ee2qsj8va8ats2ksmgn",
"abstract:ans-host": "juno1vmsr7jrfsaveqeqpua2cpfz6wtsrh7ym2wlk82ghpltjqcg9psrs76yzld",
"abstract:ibc-client": "juno13nh52udymffggkjaq4vqa8ds0hm4uv0eedzvyq43szpwkwjqu07qdhknsf",
"abstract:ibc-host": "juno1cznnmdqxg86ysplcese8z5t504gyhxzndhfuktns6chejk0wvh8sfttefv",
"abstract:manager-local-0": "juno1xthk3jr7ful9xmxqqsup7pkx9ngkycq7hfa7t75gcv47ajpyjvgsdxtlqs",
"abstract:manager-local-1": "juno1ha8kxcqcclt8a03fryt0xrpps2jzhyfdv6aaltu5e6wn7l4v0rjs9khssu",
"abstract:manager-local-2": "juno1k8e4pg220xyy8xltptxvt4w2rkajjfr05u0007c5j0ad2ntxmslqhlntp0",
"abstract:module-factory": "juno19gqaw2laku723sz32aq75pc6rw9q9fy9ruq6l0jqg272utkp4jdsmev49q",
"abstract:proxy-local-0": "juno1a0gu37sj27hpndjjsse9mdx3n5j46qz8mwqghwtsv98gztumr8jsa3u7w3",
"abstract:proxy-local-1": "juno1dwsvlcpjvdwyrka0smftpu8mln4q8dadv2xz3xxl92ngfxvuf5ss82crwn",
"abstract:proxy-local-2": "juno17x2jjjafl4mlqvtd22tv2sptjlw3hnwgxj85wqasfd0temhxzpfsgn8guv",
"abstract:version-control": "juno10u2skqwln29qrw2ggg5xhkw8t0xct6jz4674urcdx5qj0uyl08eq6jq0qa",
"polytone:note": null,
"polytone:note | junotwo-1": "juno1plr28ztj64a47a32lw7tdae8vluzm2lm7nqk364r4ws50rgwyzgs6y8ewu"
}
},
"junofour-1": {
"code_ids": {},
"default": {}
},
"junothree-1": {
"code_ids": {},
"default": {}
}
},
"osmosis": {
"junotwo-1": {
"code_ids": {
"abstract:account-factory": 24,
"abstract:ans-host": 22,
"abstract:ibc-client": 28,
"abstract:ibc-host": 29,
"abstract:manager": 26,
"abstract:module-factory": 25,
"abstract:proxy": 27,
"abstract:version-control": 23,
"counter_contract": 30,
"polytone:note": 9,
"polytone:proxy": 11,
"polytone:voice": 10
},
"default": {
"abstract:account-factory": "osmo1nv772ju2szazve72a5nycsscam770gq5ranufcmsj9n8mkm86yjqwvm4ft",
"abstract:ans-host": "osmo1ud7zhcceh4hwjhuhs58nxnh9he0n7sgx90wqq7uslr67k8vuj2pq6fynqv",
"abstract:ibc-client": "osmo1sun3clwczfm2p0xtyhesnpchdqcj55d2wzxjjgd0hqtxejczdypshlwrzy",
"abstract:ibc-host": "osmo149fzg5j97794hu3f09w8eh54v26xnwym8s0decq6ll9zfgn80g5smpypkg",
"abstract:manager-juno-2": "osmo1ng8jq8a0chlx73shyu998ytvlz5384h45u8xh6gc5gh63p2sv3aqdzhtep",
"abstract:manager-local-0": "osmo1wf0rljs9zselxp3kyg6vwtsg5k9nd2c5s38kuzde8vgzk46r9qssgtkjdy",
"abstract:module-factory": "osmo1ekc95e6p7277t77ahxn2dhl5qz76r6egdlrdp2ehvewdraa97m7qmyt5vn",
"abstract:proxy-juno-2": "osmo1d2h356rtl4yex2cnl7au7nrq262mvxqvtclde3lrzqg0kesrcrhqah9xgp",
"abstract:proxy-local-0": "osmo1nncn9p7xafk7zfnt4c4jy8mqh3m25t2tfw0scsghvmc485uxnzxqrtpd30",
"abstract:version-control": "osmo1wqchrjh07e3kxaee59yrpzckwr94j03zchmdslypvkv6ps0684msrzv484",
"counter_contract": "osmo1t4a34yj7r7h7fffuls3gvj6ept6vqyuujm4v2a4lnrnm8yckwmuqnkd0a9",
"polytone:voice": null,
"polytone:voice | juno-1": "osmo1hzz0s0ucrhdp6tue2lxk3c03nj6f60qy463we7lgx0wudd72ctms64096d"
}
}
}
}
);
let expected = json!({
"juno-1": {
"code_ids": {
"abstract:account-factory": 22,
"abstract:ans-host": 20,
"abstract:ibc-client": 26,
"abstract:ibc-host": 27,
"abstract:manager": 24,
"abstract:module-factory": 23,
"abstract:proxy": 25,
"abstract:version-control": 21,
"polytone:note": 9,
"polytone:proxy": 11,
"polytone:voice": 10
},
"default": {
"abstract:account-factory": "juno1j6scewlz8mrsk3dl3a578rmdps8svlz8jltwpa5ee2qsj8va8ats2ksmgn",
"abstract:ans-host": "juno1vmsr7jrfsaveqeqpua2cpfz6wtsrh7ym2wlk82ghpltjqcg9psrs76yzld",
"abstract:ibc-client": "juno13nh52udymffggkjaq4vqa8ds0hm4uv0eedzvyq43szpwkwjqu07qdhknsf",
"abstract:ibc-host": "juno1cznnmdqxg86ysplcese8z5t504gyhxzndhfuktns6chejk0wvh8sfttefv",
"abstract:manager-local-0": "juno1xthk3jr7ful9xmxqqsup7pkx9ngkycq7hfa7t75gcv47ajpyjvgsdxtlqs",
"abstract:manager-local-1": "juno1ha8kxcqcclt8a03fryt0xrpps2jzhyfdv6aaltu5e6wn7l4v0rjs9khssu",
"abstract:manager-local-2": "juno1k8e4pg220xyy8xltptxvt4w2rkajjfr05u0007c5j0ad2ntxmslqhlntp0",
"abstract:module-factory": "juno19gqaw2laku723sz32aq75pc6rw9q9fy9ruq6l0jqg272utkp4jdsmev49q",
"abstract:proxy-local-0": "juno1a0gu37sj27hpndjjsse9mdx3n5j46qz8mwqghwtsv98gztumr8jsa3u7w3",
"abstract:proxy-local-1": "juno1dwsvlcpjvdwyrka0smftpu8mln4q8dadv2xz3xxl92ngfxvuf5ss82crwn",
"abstract:proxy-local-2": "juno17x2jjjafl4mlqvtd22tv2sptjlw3hnwgxj85wqasfd0temhxzpfsgn8guv",
"abstract:version-control": "juno10u2skqwln29qrw2ggg5xhkw8t0xct6jz4674urcdx5qj0uyl08eq6jq0qa",
"polytone:note": null,
"polytone:note | junotwo-1": "juno1plr28ztj64a47a32lw7tdae8vluzm2lm7nqk364r4ws50rgwyzgs6y8ewu"
}
},
"junofour-1": {
"code_ids": {},
"default": {}
},
"junothree-1": {
"code_ids": {},
"default": {}
},
"junotwo-1": {
"code_ids": {
"abstract:account-factory": 24,
"abstract:ans-host": 22,
"abstract:ibc-client": 28,
"abstract:ibc-host": 29,
"abstract:manager": 26,
"abstract:module-factory": 25,
"abstract:proxy": 27,
"abstract:version-control": 23,
"counter_contract": 30,
"polytone:note": 9,
"polytone:proxy": 11,
"polytone:voice": 10
},
"default": {
"abstract:account-factory": "osmo1nv772ju2szazve72a5nycsscam770gq5ranufcmsj9n8mkm86yjqwvm4ft",
"abstract:ans-host": "osmo1ud7zhcceh4hwjhuhs58nxnh9he0n7sgx90wqq7uslr67k8vuj2pq6fynqv",
"abstract:ibc-client": "osmo1sun3clwczfm2p0xtyhesnpchdqcj55d2wzxjjgd0hqtxejczdypshlwrzy",
"abstract:ibc-host": "osmo149fzg5j97794hu3f09w8eh54v26xnwym8s0decq6ll9zfgn80g5smpypkg",
"abstract:manager-juno-2": "osmo1ng8jq8a0chlx73shyu998ytvlz5384h45u8xh6gc5gh63p2sv3aqdzhtep",
"abstract:manager-local-0": "osmo1wf0rljs9zselxp3kyg6vwtsg5k9nd2c5s38kuzde8vgzk46r9qssgtkjdy",
"abstract:module-factory": "osmo1ekc95e6p7277t77ahxn2dhl5qz76r6egdlrdp2ehvewdraa97m7qmyt5vn",
"abstract:proxy-juno-2": "osmo1d2h356rtl4yex2cnl7au7nrq262mvxqvtclde3lrzqg0kesrcrhqah9xgp",
"abstract:proxy-local-0": "osmo1nncn9p7xafk7zfnt4c4jy8mqh3m25t2tfw0scsghvmc485uxnzxqrtpd30",
"abstract:version-control": "osmo1wqchrjh07e3kxaee59yrpzckwr94j03zchmdslypvkv6ps0684msrzv484",
"counter_contract": "osmo1t4a34yj7r7h7fffuls3gvj6ept6vqyuujm4v2a4lnrnm8yckwmuqnkd0a9",
"polytone:voice": null,
"polytone:voice | juno-1": "osmo1hzz0s0ucrhdp6tue2lxk3c03nj6f60qy463we7lgx0wudd72ctms64096d"
}
}
});
let patched = patch_state_if_old(old_starship_state);
assert_eq!(patched, expected);
let not_patched = patch_state_if_old(patched);
assert_eq!(not_patched, expected);
}
}