Skip to content

Commit

Permalink
Use TOML for the configuration file
Browse files Browse the repository at this point in the history
  • Loading branch information
baskerville committed Jun 23, 2018
1 parent 69a4d38 commit 2f9519e
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 62 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/archives
/resources
/libs
/settings.json
/Settings.toml
/user.css
/src/wrapper/*.so
/src/wrapper/*.dylib
Expand Down
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ unicode-normalization = "0.1.5"
glob = "0.2.11"
rand = "0.4.2"
crockford = "1.0.1"
toml = "0.4.6"

[dependencies.html-entities]
version = "0.1.0"
Expand Down
6 changes: 3 additions & 3 deletions doc/GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ Follow the instruction given on the *fmon* page on how to handle it.

## Configure

The default library path is `/mnt/onboard`. If your library lives somewhere else, you'll need to create a file named `settings.json` in the same directory as the program's binary with the following content:
```json
{ "libraryPath": "LIBRARY_PATH" }
The default library path is `/mnt/onboard`. If your library lives somewhere else, you'll need to create a file named `Settings.toml` in the same directory as the program's binary with the following content:
```toml
library-path = "LIBRARY_PATH"
```

If there's a `user.css` in same directory as the program's binary, it will be used for all the reflowable formats.
77 changes: 43 additions & 34 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use view::menu::{Menu, MenuKind};
use input::{DeviceEvent, ButtonCode, ButtonStatus};
use input::{raw_events, device_events, usb_events};
use gesture::{GestureEvent, gesture_events, BUTTON_HOLD_DELAY};
use helpers::{load_json, save_json};
use helpers::{load_json, save_json, load_toml, save_toml};
use metadata::{Metadata, METADATA_FILENAME, import};
use settings::{Settings, SETTINGS_PATH};
use frontlight::{Frontlight, NaturalFrontlight, StandardFrontlight};
Expand Down Expand Up @@ -65,10 +65,9 @@ impl Context {
}
}

pub fn run() -> Result<()> {
fn build_context() -> Result<Context> {
let path = Path::new(SETTINGS_PATH);

let settings = load_json::<Settings, _>(path);
let settings = load_toml::<Settings, _>(path);

if let Err(ref e) = settings {
if path.exists() {
Expand All @@ -85,8 +84,33 @@ pub fn run() -> Result<()> {
&vec![],
&settings.import.allowed_kinds))
.unwrap_or_default();
let fonts = Fonts::load().chain_err(|| "Can't load fonts.")?;

let battery = Box::new(KoboBattery::new().chain_err(|| "Can't create battery.")?) as Box<Battery>;

let lightsensor = if CURRENT_DEVICE.has_lightsensor() {
Box::new(KoboLightSensor::new().chain_err(|| "Can't create light sensor.")?) as Box<LightSensor>
} else {
Box::new(0u16) as Box<LightSensor>
};

let levels = settings.frontlight_levels;
let frontlight = if CURRENT_DEVICE.has_natural_light() {
Box::new(NaturalFrontlight::new(levels.intensity, levels.warmth)
.chain_err(|| "Can't create natural frontlight.")?) as Box<Frontlight>
} else {
Box::new(StandardFrontlight::new(levels.intensity)
.chain_err(|| "Can't create standard frontlight.")?) as Box<Frontlight>
};

Ok(Context::new(settings, metadata, PathBuf::from(METADATA_FILENAME),
fonts, battery, frontlight, lightsensor))
}

pub fn run() -> Result<()> {
let mut context = build_context().chain_err(|| "Can't build context.")?;
let mut fb = KoboFramebuffer::new("/dev/fb0").chain_err(|| "Can't create framebuffer.")?;

let paths = vec!["/dev/input/event0".to_string(),
"/dev/input/event1".to_string()];
let touch_screen = gesture_events(device_events(raw_events(paths), fb.dims()));
Expand Down Expand Up @@ -126,41 +150,21 @@ pub fn run() -> Result<()> {

let fb_rect = fb.rect();

let fonts = Fonts::load().chain_err(|| "Can't load fonts.")?;

if settings.wifi {
if context.settings.wifi {
Command::new("scripts/wifi-enable.sh").spawn().ok();
} else {
Command::new("scripts/wifi-disable.sh").spawn().ok();
}

let levels = settings.frontlight_levels;
let mut frontlight = if CURRENT_DEVICE.has_natural_light() {
Box::new(NaturalFrontlight::new(levels.intensity, levels.warmth)
.chain_err(|| "Can't create natural frontlight.")?) as Box<Frontlight>
} else {
Box::new(StandardFrontlight::new(levels.intensity)
.chain_err(|| "Can't create standard frontlight.")?) as Box<Frontlight>
};

if settings.frontlight {
frontlight.set_intensity(levels.intensity);
frontlight.set_warmth(levels.warmth);
if context.settings.frontlight {
let levels = context.settings.frontlight_levels;
context.frontlight.set_intensity(levels.intensity);
context.frontlight.set_warmth(levels.warmth);
} else {
frontlight.set_warmth(0.0);
frontlight.set_intensity(0.0);
context.frontlight.set_warmth(0.0);
context.frontlight.set_intensity(0.0);
}

let battery = Box::new(KoboBattery::new().chain_err(|| "Can't create battery.")?) as Box<Battery>;

let lightsensor = if CURRENT_DEVICE.has_lightsensor() {
Box::new(KoboLightSensor::new().chain_err(|| "Can't create light sensor.")?) as Box<LightSensor>
} else {
Box::new(0u16) as Box<LightSensor>
};

let mut context = Context::new(settings, metadata, PathBuf::from(METADATA_FILENAME),
fonts, battery, frontlight, lightsensor);
let mut history: Vec<Box<View>> = Vec::new();
let mut view: Box<View> = Box::new(Home::new(fb_rect, &tx, &mut context)?);

Expand All @@ -169,7 +173,7 @@ pub fn run() -> Result<()> {
println!("{} is running on a Kobo {}.", APP_NAME,
CURRENT_DEVICE.model);
println!("The framebuffer resolution is {} by {}.", fb_rect.width(),
fb_rect.height());
fb_rect.height());

let mut bus = VecDeque::with_capacity(4);

Expand Down Expand Up @@ -225,6 +229,11 @@ pub fn run() -> Result<()> {
if context.mounted {
Command::new("scripts/usb-disable.sh").status().ok();
context.mounted = false;
let path = Path::new(SETTINGS_PATH);
if let Ok(settings) = load_toml::<Settings, _>(path)
.map_err(|e| eprintln!("Can't load settings: {}", e)) {
context.settings = settings;
}
if context.settings.wifi {
Command::new("scripts/wifi-enable.sh")
.spawn()
Expand Down Expand Up @@ -273,7 +282,7 @@ pub fn run() -> Result<()> {
context.suspended = true;
updating.retain(|tok, _| fb.wait(*tok).is_err());
let path = Path::new(SETTINGS_PATH);
save_json(&context.settings, path).map_err(|e| eprintln!("Can't save settings: {}", e)).ok();
save_toml(&context.settings, path).map_err(|e| eprintln!("Can't save settings: {}", e)).ok();
let path = context.settings.library_path.join(&context.filename);
save_json(&context.metadata, path).map_err(|e| eprintln!("Can't save metadata: {}", e)).ok();
if context.settings.frontlight {
Expand Down Expand Up @@ -504,7 +513,7 @@ pub fn run() -> Result<()> {
save_json(&context.metadata, path).chain_err(|| "Can't save metadata.")?;

let path = Path::new(SETTINGS_PATH);
save_json(&context.settings, path).chain_err(|| "Can't save settings.")?;
save_toml(&context.settings, path).chain_err(|| "Can't save settings.")?;

Ok(())
}
15 changes: 8 additions & 7 deletions src/emulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;
#[macro_use]
extern crate lazy_static;
#[macro_use]
Expand Down Expand Up @@ -58,7 +59,7 @@ mod errors {
}

use std::thread;
use std::fs::File;
use std::fs::{self, File};
use std::sync::mpsc;
use std::collections::VecDeque;
use std::path::{Path, PathBuf};
Expand All @@ -83,12 +84,12 @@ use view::frontlight::FrontlightWindow;
use view::keyboard::Keyboard;
use view::menu::{Menu, MenuKind};
use view::common::{locate, locate_by_id, overlapping_rectangle};
use helpers::{load_json, save_json, load_toml, save_toml};
use metadata::{Metadata, METADATA_FILENAME};
use settings::{Settings, SETTINGS_PATH};
use geom::Rectangle;
use gesture::gesture_events;
use device::CURRENT_DEVICE;
use helpers::{load_json, save_json};
use metadata::{Metadata, METADATA_FILENAME};
use settings::{Settings, SETTINGS_PATH};
use battery::{Battery, FakeBattery};
use frontlight::{Frontlight, LightLevels};
use lightsensor::LightSensor;
Expand All @@ -101,7 +102,7 @@ pub const APP_NAME: &str = "Plato";
const CLOCK_REFRESH_INTERVAL: Duration = Duration::from_secs(60);

pub fn build_context() -> Result<Context> {
let settings = load_json::<Settings, _>(SETTINGS_PATH)?;
let settings = load_toml::<Settings, _>(SETTINGS_PATH)?;
let path = settings.library_path.join(METADATA_FILENAME);
let metadata = load_json::<Metadata, _>(path)?;
let battery = Box::new(FakeBattery::new()) as Box<Battery>;
Expand Down Expand Up @@ -248,7 +249,7 @@ pub fn run() -> Result<()> {
println!("{} is running on a Kobo {}.", APP_NAME,
CURRENT_DEVICE.model);
println!("The framebuffer resolution is {} by {}.", fb_rect.width(),
fb_rect.height());
fb_rect.height());

let mut bus = VecDeque::with_capacity(4);

Expand Down Expand Up @@ -424,7 +425,7 @@ pub fn run() -> Result<()> {
save_json(&context.metadata, path).chain_err(|| "Can't save metadata.")?;

let path = Path::new(SETTINGS_PATH);
save_json(&context.settings, path).chain_err(|| "Can't save settings.")?;
save_toml(&context.settings, path).chain_err(|| "Can't save settings.")?;

Ok(())
}
Expand Down
13 changes: 12 additions & 1 deletion src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
extern crate serde_json;
extern crate toml;

use std::path::Path;
use std::fs::File;
use std::fs::{self, File};
use std::cmp::Ordering;
use serde::{Serialize, Deserialize};
use errors::*;
Expand All @@ -16,6 +17,16 @@ pub fn save_json<T, P: AsRef<Path>>(data: &T, path: P) -> Result<()> where T: Se
serde_json::to_writer_pretty(file, data).chain_err(|| "Can't serialize data to file.")
}

pub fn load_toml<T, P: AsRef<Path>>(path: P) -> Result<T> where for<'a> T: Deserialize<'a> {
let s = fs::read_to_string(path).chain_err(|| "Can't read file.")?;
toml::from_str(&s).chain_err(|| "Can't parse file.")
}

pub fn save_toml<T, P: AsRef<Path>>(data: &T, path: P) -> Result<()> where T: Serialize {
let s = toml::to_string(data).chain_err(|| "Can't serialize data.")?;
fs::write(path, &s).chain_err(|| "Can't write to file.")
}

pub fn combine_sort_methods<'a, T, F1, F2>(mut f1: F1, mut f2: F2) -> Box<FnMut(&T, &T) -> Ordering + 'a>
where F1: FnMut(&T, &T) -> Ordering + 'a,
F2: FnMut(&T, &T) -> Ordering + 'a {
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate toml;
#[macro_use]
extern crate lazy_static;
#[macro_use]
Expand Down
28 changes: 14 additions & 14 deletions src/settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,38 @@ use frontlight::LightLevels;

pub use self::preset::{LightPreset, guess_frontlight};

pub const SETTINGS_PATH: &str = "settings.json";
pub const SETTINGS_PATH: &str = "Settings.toml";

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, rename_all = "camelCase")]
#[serde(default, rename_all = "kebab-case")]
pub struct Settings {
pub library_path: PathBuf,
pub refresh_every: Option<u8>,
pub summary_size: u8,
pub import: ImportSettings,
pub reader: ReaderSettings,
pub frontlight_levels: LightLevels,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub frontlight_presets: Vec<LightPreset>,
pub frontlight: bool,
pub wifi: bool,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub frontlight_presets: Vec<LightPreset>,
pub reader: ReaderSettings,
pub import: ImportSettings,
pub frontlight_levels: LightLevels,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, rename_all = "camelCase")]
#[serde(default, rename_all = "kebab-case")]
pub struct ImportSettings {
pub unmount_trigger: bool,
pub allowed_kinds: FnvHashSet<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, rename_all = "camelCase")]
#[serde(default, rename_all = "kebab-case")]
pub struct ReaderSettings {
pub refresh_every: Option<u8>,
pub finished: FinishedAction,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "kebab-case")]
pub enum FinishedAction {
Notify,
Close,
Expand All @@ -46,6 +46,7 @@ pub enum FinishedAction {
impl Default for ReaderSettings {
fn default() -> Self {
ReaderSettings {
refresh_every: Some(24),
finished: FinishedAction::Notify,
}
}
Expand All @@ -55,8 +56,8 @@ impl Default for ImportSettings {
fn default() -> Self {
ImportSettings {
unmount_trigger: true,
allowed_kinds: ["pdf", "djvu", "epub", "fb2", "html",
"cbz", "png", "jpg", "jpeg"].iter().map(|k| k.to_string()).collect(),
allowed_kinds: ["pdf", "djvu", "epub",
"fb2", "cbz"].iter().map(|k| k.to_string()).collect(),
}
}
}
Expand All @@ -65,7 +66,6 @@ impl Default for Settings {
fn default() -> Self {
Settings {
library_path: PathBuf::from("/mnt/onboard"),
refresh_every: Some(24),
summary_size: 1,
import: ImportSettings::default(),
reader: ReaderSettings::default(),
Expand Down
4 changes: 2 additions & 2 deletions src/view/reader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ impl Reader {
page_turns: 0,
finished: false,
ephemeral: false,
refresh_every: settings.refresh_every,
refresh_every: settings.reader.refresh_every,
search_direction: LinearDir::Forward,
frame,
scale,
Expand Down Expand Up @@ -197,7 +197,7 @@ impl Reader {
page_turns: 0,
finished: false,
ephemeral: true,
refresh_every: context.settings.refresh_every,
refresh_every: context.settings.reader.refresh_every,
search_direction: LinearDir::Forward,
frame,
scale,
Expand Down

0 comments on commit 2f9519e

Please sign in to comment.