1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
use core::panic;
use std::{
  fmt,
  path::Path,
  collections::HashMap,
  fs::{
    File,
    read_to_string
  },
  io::{
    Result,
    Write
  },
};

use serde_json::Value as JSONValue;

pub type Value = JSONValue;
pub type JSON = HashMap<String, JSONValue>;

pub struct Storage {
  pub path: String,
  pub content: JSON
}

fn write_json_to_file(filepath: String, json: JSON) {
  let path = Path::new(&filepath);

  let data = match serde_json::to_string(&json) {
    Ok(data) => data,
    Err(err) => panic!("Couldn't serialize JSON: {}", err)
  };

  let mut file = match File::create(&filepath) {
    Ok(file) => file,
    Err(err) => panic!("Couldn't read file: ({}) {}", path.display(), err)
  };

  match file.write_all(data.as_bytes()) {
    Err(err) => panic!("Error writing file: ({}) {}", path.display(), err),
    Ok(_) => ()
  }
}

impl Storage {
  pub fn new(filename: &str) -> Storage {
    let path = Path::new(filename);

    if !path.exists() {
      File::create(path)
        .expect("An error is occurred while trying to open the configuration file.");

      write_json_to_file(filename.to_string(), JSON::new());
    }

    Storage {
      path: String::from(filename),
      content: JSON::new()
    }
  }

  pub fn update_file(&self) -> Result<()> {
    let path = Path::new(&self.path);

    let data = serde_json::to_string(&self.content)?;
    let mut file = File::create(&path)?;
    file.write_all(data.as_bytes())?;

    Ok(())
  }

  pub fn pull(&mut self) -> Result<()> {
    let string_content = read_to_string(Path::new(&self.path))?;
    let data : JSON = serde_json::from_str(&string_content)?;
    self.content = data;

    Ok(())
  }

  pub fn get(&self, key: String) -> std::result::Result<Value, KeyNotFoundError> {
    let data = &self.content;

    if !data.contains_key(&key) {
      return Err(KeyNotFoundError);
    }

    Ok(data[&key].clone())
  }

  pub fn put(&mut self, key: String, value: JSONValue) -> Result<()> {
    &self.content.insert(key, value);
    self.update_file()?;

    Ok(())
  }
}

// Error when a key cannot be found.
#[derive(Debug, Clone)]
pub struct KeyNotFoundError;

impl fmt::Display for KeyNotFoundError {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    write!(f, "Invalid key.")
  }
}