microsoft/openvmm

Public

mirrored fromhttps://github.com/microsoft/openvmmAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
copilot/apply-async-process-wait-functionality

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

flowey/flowey_cli/src/var_db/single_json_file.rs

87lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! A dead simple runtime variable db, backed by a single JSON file.
5
6use anyhow::Context;
7use fs_err::File;
8use serde::Deserialize;
9use serde::Serialize;
10use serde_json::value::RawValue;
11use std::borrow::Cow;
12use std::collections::BTreeMap;
13use std::io::Seek;
14use std::io::Write;
15use std::path::Path;
16
17/// On-disk format for the var db
18#[derive(Serialize, Deserialize)]
19#[serde(transparent)]
20struct VarDb<'a> {
21 vars: BTreeMap<String, (bool, Cow<'a, RawValue>)>,
22}
23
24/// Implements [`flowey_core::node::RuntimeVarDb`] backed by a JSON file.
25pub struct SingleJsonFileVarDb {
26 file: File,
27}
28
29impl SingleJsonFileVarDb {
30 pub fn new(backing_file: impl AsRef<Path>) -> anyhow::Result<Self> {
31 let backing_file = backing_file.as_ref();
32 let exists = backing_file.exists();
33 let mut file = fs_err::OpenOptions::new()
34 .read(true)
35 .write(true)
36 .create(true)
37 .open(backing_file)
38 .context("failed to open/create database file")?;
39
40 // seed the database file with an empty json map
41 if !exists {
42 eprintln!(
43 "seeding new empty database file: {}",
44 backing_file.display()
45 );
46 file.write_all(b"{}")?;
47 }
48
49 Ok(Self { file })
50 }
51
52 fn load_db(&mut self) -> VarDb<'static> {
53 self.file.rewind().unwrap();
54 serde_json::from_reader(&self.file).expect("corrupt runtime variable db")
55 }
56}
57
58impl flowey_core::node::RuntimeVarDb for SingleJsonFileVarDb {
59 fn try_get_var(&mut self, var_name: &str) -> Option<(Vec<u8>, bool)> {
60 let db = self.load_db();
61 let (is_secret, ref val) = *db.vars.get(var_name)?;
62 if is_secret {
63 log::debug!("[db] read var: {} = <secret>", var_name);
64 } else {
65 log::debug!("[db] read var: {} = {}", var_name, val);
66 }
67 Some((val.get().into(), is_secret))
68 }
69
70 fn set_var(&mut self, var_name: &str, is_secret: bool, value: Vec<u8>) {
71 let value: &RawValue = serde_json::from_slice(&value)
72 .unwrap_or_else(|err| panic!("invalid JSON for var {}: {}", var_name, err));
73 if is_secret {
74 log::debug!("[db] set var: {} = <secret>", var_name)
75 } else {
76 log::debug!("[db] set var: {} = {}", var_name, value)
77 };
78 let mut db = self.load_db();
79 let existing = db
80 .vars
81 .insert(var_name.into(), (is_secret, Cow::Borrowed(value)));
82 assert!(existing.is_none()); // all vars are one-time-write
83 self.file.set_len(0).unwrap();
84 self.file.rewind().unwrap();
85 serde_json::to_writer(&self.file, &db).expect("failed to write to db JSON");
86 }
87}
88