Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic profile service #184

Merged
merged 1 commit into from
Mar 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/config_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ describe! config {

describe! config_service {
before_each {
let mut config = ConfigService::new(&config_file_name);
let config = ConfigService::new(&config_file_name);
}

it "should remember properties" {
Expand Down Expand Up @@ -261,7 +261,7 @@ describe! config {
it "ConfigService should remember things over restarts" {
// Block to make `config` go out of scope
{
let mut config = ConfigService::new(&config_file_name);
let config = ConfigService::new(&config_file_name);
config.set("foo", "bar", "baz");
}
// `config` should now be out of scope and dropped
Expand Down
13 changes: 11 additions & 2 deletions src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use http_server::HttpServer;
use iron::{Request, Response, IronResult};
use iron::headers::{ ContentType, AccessControlAllowOrigin };
use iron::status::Status;
use profile_service::ProfileService;
use self::collections::vec::IntoIter;
use service::{ Service, ServiceAdapter, ServiceProperties };
use std::collections::hash_map::HashMap;
Expand All @@ -35,6 +36,7 @@ pub struct FoxBox {
websockets: Arc<Mutex<HashMap<ws::util::Token, ws::Sender>>>,
pub config: Arc<ConfigService>,
upnp: Arc<UpnpManager>,
profile_service: Arc<ProfileService>
}

const DEFAULT_HOSTNAME: &'static str = "::"; // ipv6 default.
Expand All @@ -59,6 +61,7 @@ pub trait Controller : Send + Sync + Clone + Reflect + 'static {

fn get_config(&self) -> &ConfigService;
fn get_upnp_manager(&self) -> Arc<UpnpManager>;
fn get_profile(&self) -> &ProfileService;
}

impl FoxBox {
Expand All @@ -68,6 +71,7 @@ impl FoxBox {
http_port: u16,
ws_port: u16) -> Self {

let profile_service = ProfileService::new(None);
FoxBox {
services: Arc::new(Mutex::new(HashMap::new())),
websockets: Arc::new(Mutex::new(HashMap::new())),
Expand All @@ -77,8 +81,9 @@ impl FoxBox {
}),
http_port: http_port,
ws_port: ws_port,
config: Arc::new(ConfigService::new("foxbox.conf")),
upnp: Arc::new(UpnpManager::new())
config: Arc::new(ConfigService::new(&profile_service.path_for("foxbox.conf"))),
upnp: Arc::new(UpnpManager::new()),
profile_service: Arc::new(profile_service)
}
}
}
Expand Down Expand Up @@ -203,6 +208,10 @@ impl Controller for FoxBox {
&self.config
}

fn get_profile(&self) -> &ProfileService {
&self.profile_service
}

fn get_upnp_manager(&self) -> Arc<UpnpManager> {
self.upnp.clone()
}
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ mod config_store;
mod controller;
mod http_server;
mod managed_process;
mod profile_service;
mod registration;
mod service;
mod upnp;
Expand Down
93 changes: 93 additions & 0 deletions src/profile_service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/// Simple service that helps with managing files in a configurable
/// directory.

use std::env;
use std::fs;

pub struct ProfileService {
profile_dir: String
}

fn get_env_var(name: &str) -> Option<String> {
if let Some(value) = env::var_os(name) {
return match value.into_string() {
Ok(s) => Some(s),
Err(_) => None
};
}
None
}

impl ProfileService {
pub fn new(profile_dir: Option<String>) -> Self {
// If no explicit profile directory is set, follow the Freedesktop
// standard: If $XDG_DATA_HOME is either not set or empty, a default
// equal to $HOME/.local/share is used.
let dir = match profile_dir {
Some(path) => path,
None => {
if let Some(xdg) = get_env_var("XDG_DATA_HOME") {
format!("{}/foxbox", xdg)
} else {
if let Some(home) = get_env_var("HOME") {
format!("{}/.local/share/foxbox", home)
} else {
panic!("Unable to get $HOME value");
}
}
}
};

// Create the directory if needed. Panic if we can't or if there is an
// existing file with the same path.
match fs::metadata(dir.clone()) {
Ok(meta) => {
if !meta.is_dir() {
panic!("The path {} is a file, and can't be used as a profile.",
dir);
}
},
Err(_) => {
fs::create_dir_all(dir.clone()).unwrap_or_else(|err| {
panic!("Unable to create directory {} : {}", dir, err);
});
}
}

ProfileService {
profile_dir: dir
}
}

// Returns an absolute path for a file.
// This doesn't try to create the file.
pub fn path_for(&self, relative_path: &str) -> String {
format!("{}/{}", self.profile_dir, relative_path)
}
}

#[test]
#[should_panic]
fn test_bogus_path() {
let _ = ProfileService::new(Some("/cant_create/that/path".to_owned()));
}

#[test]
fn test_default_profile() {
use std::fs::File;
use std::io::Write;

let profile = ProfileService::new(None);
let path = profile.path_for("test.conf");
// We can't assert anything on the path value since it's environment
// dependant, but we should be able to create & delete the file.
// We let the test panic if something goes wrong.
let mut f = File::create(path.clone()).unwrap();
f.write_all(b"Hello, world!").unwrap();
fs::remove_file(path).unwrap();
assert!(true);
}