2017-07-21 09:21:59 +00:00
|
|
|
use prelude::*;
|
2017-03-21 10:28:11 +00:00
|
|
|
|
2017-03-10 11:43:32 +00:00
|
|
|
use serde_yaml;
|
|
|
|
|
|
|
|
use std::fs::File;
|
|
|
|
use std::path::Path;
|
2017-03-16 08:42:30 +00:00
|
|
|
use std::io;
|
2017-03-10 11:43:32 +00:00
|
|
|
|
|
|
|
|
2017-03-16 08:42:30 +00:00
|
|
|
quick_error!{
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum ConfigError {
|
|
|
|
Io(err: io::Error) {
|
|
|
|
from()
|
|
|
|
cause(err)
|
|
|
|
}
|
|
|
|
Parse(reason: &'static str) {
|
|
|
|
from()
|
|
|
|
description("Failed to parse config")
|
|
|
|
display("Failed to parse config: {}", reason)
|
|
|
|
}
|
|
|
|
Yaml(err: serde_yaml::Error) {
|
|
|
|
from()
|
|
|
|
cause(err)
|
|
|
|
description("Yaml format error")
|
2017-03-18 16:22:11 +00:00
|
|
|
display("Yaml format error: {}", err)
|
2017-03-16 08:42:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-10 11:43:32 +00:00
|
|
|
impl HashMethod {
|
2018-02-19 21:30:59 +00:00
|
|
|
fn from_yaml(yaml: &str) -> Result<Self, ConfigError> {
|
|
|
|
HashMethod::from(yaml).map_err(ConfigError::Parse)
|
2017-03-10 11:43:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn to_yaml(&self) -> String {
|
|
|
|
self.name().to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct ChunkerYaml {
|
|
|
|
method: String,
|
|
|
|
avg_size: usize,
|
|
|
|
seed: u64
|
|
|
|
}
|
|
|
|
impl Default for ChunkerYaml {
|
|
|
|
fn default() -> Self {
|
|
|
|
ChunkerYaml {
|
|
|
|
method: "fastcdc".to_string(),
|
2017-07-21 09:21:59 +00:00
|
|
|
avg_size: 16 * 1024,
|
2017-03-10 11:43:32 +00:00
|
|
|
seed: 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
serde_impl!(ChunkerYaml(String) {
|
|
|
|
method: String => "method",
|
|
|
|
avg_size: usize => "avg_size",
|
|
|
|
seed: u64 => "seed"
|
|
|
|
});
|
|
|
|
|
|
|
|
impl ChunkerType {
|
2018-02-19 21:30:59 +00:00
|
|
|
fn from_yaml(yaml: &ChunkerYaml) -> Result<Self, ConfigError> {
|
2017-03-16 08:42:30 +00:00
|
|
|
ChunkerType::from(&yaml.method, yaml.avg_size, yaml.seed).map_err(ConfigError::Parse)
|
2017-03-10 11:43:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn to_yaml(&self) -> ChunkerYaml {
|
|
|
|
ChunkerYaml {
|
|
|
|
method: self.name().to_string(),
|
|
|
|
avg_size: self.avg_size(),
|
|
|
|
seed: self.seed()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Compression {
|
2017-03-14 15:07:52 +00:00
|
|
|
#[inline]
|
2018-02-19 21:30:59 +00:00
|
|
|
fn from_yaml(yaml: &str) -> Result<Self, ConfigError> {
|
|
|
|
Compression::from_string(yaml).map_err(|_| ConfigError::Parse("Invalid codec"))
|
2017-03-10 11:43:32 +00:00
|
|
|
}
|
|
|
|
|
2017-03-14 15:07:52 +00:00
|
|
|
#[inline]
|
|
|
|
fn to_yaml(&self) -> String {
|
|
|
|
self.to_string()
|
2017-03-10 11:43:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-03-18 16:22:11 +00:00
|
|
|
impl EncryptionMethod {
|
|
|
|
#[inline]
|
2018-02-19 21:30:59 +00:00
|
|
|
fn from_yaml(yaml: &str) -> Result<Self, ConfigError> {
|
|
|
|
EncryptionMethod::from_string(yaml).map_err(|_| ConfigError::Parse("Invalid codec"))
|
2017-03-18 16:22:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn to_yaml(&self) -> String {
|
|
|
|
self.to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct EncryptionYaml {
|
|
|
|
method: String,
|
|
|
|
key: String
|
|
|
|
}
|
|
|
|
impl Default for EncryptionYaml {
|
|
|
|
fn default() -> Self {
|
|
|
|
EncryptionYaml {
|
|
|
|
method: "sodium".to_string(),
|
|
|
|
key: "".to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
serde_impl!(EncryptionYaml(String) {
|
|
|
|
method: String => "method",
|
|
|
|
key: String => "key"
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2017-03-10 11:43:32 +00:00
|
|
|
|
|
|
|
struct ConfigYaml {
|
2017-03-14 15:07:52 +00:00
|
|
|
compression: Option<String>,
|
2017-03-18 16:22:11 +00:00
|
|
|
encryption: Option<EncryptionYaml>,
|
2017-03-10 11:43:32 +00:00
|
|
|
bundle_size: usize,
|
|
|
|
chunker: ChunkerYaml,
|
2017-07-21 09:21:59 +00:00
|
|
|
hash: String
|
2017-03-10 11:43:32 +00:00
|
|
|
}
|
|
|
|
impl Default for ConfigYaml {
|
|
|
|
fn default() -> Self {
|
|
|
|
ConfigYaml {
|
2017-03-14 15:07:52 +00:00
|
|
|
compression: Some("brotli/5".to_string()),
|
2017-03-18 16:22:11 +00:00
|
|
|
encryption: None,
|
2017-07-21 09:21:59 +00:00
|
|
|
bundle_size: 25 * 1024 * 1024,
|
2017-03-10 11:43:32 +00:00
|
|
|
chunker: ChunkerYaml::default(),
|
|
|
|
hash: "blake2".to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
serde_impl!(ConfigYaml(String) {
|
2017-03-14 15:07:52 +00:00
|
|
|
compression: Option<String> => "compression",
|
2017-03-18 16:22:11 +00:00
|
|
|
encryption: Option<EncryptionYaml> => "encryption",
|
2017-03-10 11:43:32 +00:00
|
|
|
bundle_size: usize => "bundle_size",
|
|
|
|
chunker: ChunkerYaml => "chunker",
|
|
|
|
hash: String => "hash"
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-04-02 16:55:53 +00:00
|
|
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
2017-03-10 11:43:32 +00:00
|
|
|
pub struct Config {
|
|
|
|
pub compression: Option<Compression>,
|
2017-03-18 16:22:11 +00:00
|
|
|
pub encryption: Option<Encryption>,
|
2017-03-10 11:43:32 +00:00
|
|
|
pub bundle_size: usize,
|
|
|
|
pub chunker: ChunkerType,
|
|
|
|
pub hash: HashMethod
|
|
|
|
}
|
2017-03-22 13:42:27 +00:00
|
|
|
impl Default for Config {
|
|
|
|
fn default() -> Self {
|
|
|
|
Config {
|
2017-04-07 09:05:28 +00:00
|
|
|
compression: Some(Compression::from_string("brotli/3").unwrap()),
|
2017-03-22 13:42:27 +00:00
|
|
|
encryption: None,
|
2017-07-21 09:21:59 +00:00
|
|
|
bundle_size: 25 * 1024 * 1024,
|
2017-03-22 13:42:27 +00:00
|
|
|
chunker: ChunkerType::from_string("fastcdc/16").unwrap(),
|
|
|
|
hash: HashMethod::Blake2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
serde_impl!(Config(u64) {
|
|
|
|
compression: Option<Compression> => 0,
|
|
|
|
encryption: Option<Encryption> => 1,
|
|
|
|
bundle_size: usize => 2,
|
|
|
|
chunker: ChunkerType => 3,
|
|
|
|
hash: HashMethod => 4
|
|
|
|
});
|
|
|
|
|
2017-03-10 11:43:32 +00:00
|
|
|
impl Config {
|
2017-03-16 08:42:30 +00:00
|
|
|
fn from_yaml(yaml: ConfigYaml) -> Result<Self, ConfigError> {
|
2017-03-10 11:43:32 +00:00
|
|
|
let compression = if let Some(c) = yaml.compression {
|
2018-02-19 21:30:59 +00:00
|
|
|
Some(try!(Compression::from_yaml(&c)))
|
2017-03-10 11:43:32 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2017-03-18 16:22:11 +00:00
|
|
|
let encryption = if let Some(e) = yaml.encryption {
|
2018-02-19 21:30:59 +00:00
|
|
|
let method = try!(EncryptionMethod::from_yaml(&e.method));
|
2017-07-21 09:21:59 +00:00
|
|
|
let key = try!(parse_hex(&e.key).map_err(|_| {
|
|
|
|
ConfigError::Parse("Invalid public key")
|
|
|
|
}));
|
2017-03-18 16:22:11 +00:00
|
|
|
Some((method, key.into()))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2017-07-21 09:21:59 +00:00
|
|
|
Ok(Config {
|
2017-03-10 11:43:32 +00:00
|
|
|
compression: compression,
|
2017-03-18 16:22:11 +00:00
|
|
|
encryption: encryption,
|
2017-03-10 11:43:32 +00:00
|
|
|
bundle_size: yaml.bundle_size,
|
2018-02-19 21:30:59 +00:00
|
|
|
chunker: try!(ChunkerType::from_yaml(&yaml.chunker)),
|
|
|
|
hash: try!(HashMethod::from_yaml(&yaml.hash))
|
2017-03-10 11:43:32 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_yaml(&self) -> ConfigYaml {
|
|
|
|
ConfigYaml {
|
|
|
|
compression: self.compression.as_ref().map(|c| c.to_yaml()),
|
2017-07-21 09:21:59 +00:00
|
|
|
encryption: self.encryption.as_ref().map(|e| {
|
|
|
|
EncryptionYaml {
|
|
|
|
method: e.0.to_yaml(),
|
|
|
|
key: to_hex(&e.1[..])
|
|
|
|
}
|
|
|
|
}),
|
2017-03-10 11:43:32 +00:00
|
|
|
bundle_size: self.bundle_size,
|
|
|
|
chunker: self.chunker.to_yaml(),
|
|
|
|
hash: self.hash.to_yaml()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-16 08:42:30 +00:00
|
|
|
pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, ConfigError> {
|
|
|
|
let f = try!(File::open(path));
|
|
|
|
let config = try!(serde_yaml::from_reader(f));
|
2017-03-10 11:43:32 +00:00
|
|
|
Config::from_yaml(config)
|
|
|
|
}
|
|
|
|
|
2017-03-16 08:42:30 +00:00
|
|
|
pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<(), ConfigError> {
|
|
|
|
let mut f = try!(File::create(path));
|
|
|
|
try!(serde_yaml::to_writer(&mut f, &self.to_yaml()));
|
2017-03-10 11:43:32 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|