Skip to content

Commit

Permalink
save settings back to disk
Browse files Browse the repository at this point in the history
  • Loading branch information
mdonoughe committed Feb 18, 2019
1 parent 1119a21 commit 510b83c
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 26 deletions.
65 changes: 41 additions & 24 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,13 @@ fn handle_remove_action(state: &State, context: &str) {
state.contexts.remove(context);
}

fn handle_press(logger: &Logger, state: &State, context: &str, payload: &KeyPayload<Empty>) {
fn handle_press(
logger: &Logger,
state: &State,
context: &str,
payload: &KeyPayload<Empty>,
trigger_save: &mut mpsc::Sender<()>,
) {
let desired_state = payload
.user_desired_state
.unwrap_or_else(|| (payload.state + 1) % 2);
Expand All @@ -87,7 +93,6 @@ fn handle_press(logger: &Logger, state: &State, context: &str, payload: &KeyPayl

let mut state = state.lock().unwrap();
// save back current state
//TODO: save to disk
// Why update the state right before switching even if events are being
// monitored? Changes to the device state are not atomic, so if the user
// manually switches from headphones to speakers, we don't want to
Expand All @@ -109,7 +114,8 @@ fn handle_press(logger: &Logger, state: &State, context: &str, payload: &KeyPayl
// this should only happen with multiactions after implementing monitoring
return;
}
state.profiles[current_device_output] = current_device_profile;
state.settings.profiles[current_device_output] = current_device_profile;
let _ = trigger_save.try_send(());
}
Ok(None) => {
error!(
Expand All @@ -126,8 +132,8 @@ fn handle_press(logger: &Logger, state: &State, context: &str, payload: &KeyPayl
match sb::apply_profile(
logger,
output,
&state.profiles[output],
&state.selected_parameters,
&state.settings.profiles[output],
&state.settings.selected_parameters,
) {
Ok(_) => {
state.output = Some(output);
Expand Down Expand Up @@ -168,6 +174,7 @@ fn handle_message(
logger: &Logger,
message: &Message<Empty, Empty>,
state: &State,
trigger_save: &mut mpsc::Sender<()>,
) -> Result<(), ()> {
match &message {
Message::WillAppear {
Expand All @@ -186,7 +193,9 @@ fn handle_message(
context,
payload,
..
} if action == ACTION_SELECT_OUTPUT => handle_press(logger, state, context, payload),
} if action == ACTION_SELECT_OUTPUT => {
handle_press(logger, state, context, payload, trigger_save)
}
_ => {}
}
Ok(())
Expand Down Expand Up @@ -220,26 +229,16 @@ fn main() {
let (out_sink, out_stream) = mpsc::channel(1);
let mut state = RawState {
output: None,
selected_parameters: settings.selected_parameters,
contexts: BTreeSet::new(),
out: out_sink,
profiles: Profiles {
headphones: Profile {
volume: settings.profiles.headphones.volume,
parameters: settings.profiles.headphones.parameters,
},
speakers: Profile {
volume: settings.profiles.speakers.volume,
parameters: settings.profiles.speakers.parameters,
},
},
settings,
};

match sb::get_current_profile(&logger) {
Ok(Some((output, profile))) => {
info!(logger, "detected current output to be {:?}", output);
state.output = Some(output);
state.profiles[output] = profile;
state.settings.profiles[output] = profile;
}
Ok(None) => {
error!(
Expand All @@ -255,8 +254,22 @@ fn main() {

let state = Arc::new(Mutex::new(state));

let (mut trigger_save, save_trigger) = mpsc::channel(1);
let state_save = state.clone();
let save_log = logger.clone();
let save = save_trigger.for_each(move |_| {
debug!(save_log, "saving…");
let settings = { settings::prepare_for_save(&state_save.lock().unwrap().settings) };
match settings::save(&settings) {
Ok(_) => debug!(save_log, "settings saved"),
Err(error) => error!(save_log, "settings could not be saved: {:?}", error),
}
Ok(())
});

let state_events = state.clone();
let logger_events = logger.clone();
let mut trigger_save_events = trigger_save.clone();
let events = sb::watch(&logger).unwrap().for_each(move |evt| {
let evt = evt.unwrap();
debug!(logger_events, "saw change: {:?}", evt);
Expand Down Expand Up @@ -302,7 +315,7 @@ fn main() {
// before switching? If the user changes a setting and then
// manually switches outputs, we want to capture that setting for
// the next time the user switches back to the original output.
let feature = state.profiles[output]
let feature = state.settings.profiles[output]
.parameters
.entry(evt.feature)
.or_default();
Expand All @@ -311,10 +324,11 @@ fn main() {
}
ChangeEvent::Volume(volume) => {
if let Some(output) = state.output {
state.profiles[output].volume = Some(volume);
state.settings.profiles[output].volume = Some(volume);
}
}
}
let _ = trigger_save_events.try_send(());
Ok(())
});

Expand All @@ -337,12 +351,15 @@ fn main() {
.map_err(move |e| crit!(logger_e, "receive failed {:?}", e))
.for_each(move |message| {
debug!(logger, "received {:?}", message);
handle_message(&logger, &message, &state)
handle_message(&logger, &message, &state, &mut trigger_save)
})
});
tokio::run(
Future::select(events, test.map_err(|e| panic!("{:?}", e)))
.map(|_| ())
.map_err(|_| ()),
Future::select(
Future::select(save, events).map(|_| ()).map_err(|_| ()),
test.map(|_| ()).map_err(|e| panic!("{:?}", e)),
)
.map(|_| ())
.map_err(|_| ()),
);
}
72 changes: 72 additions & 0 deletions src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,75 @@ pub fn load() -> Result<CardSettings, serde_json::Error> {
},
})
}

fn convert_from_soundcore(
value: &IndexMap<String, IndexMap<String, SoundCoreParamValue>>,
) -> serde_json::Map<String, serde_json::Value> {
value
.into_iter()
.map(|(name, params)| {
(
name.to_string(),
serde_json::Value::Object(
params
.into_iter()
.filter_map(|(name, value)| match value {
SoundCoreParamValue::I32(n) => {
Some((name.to_string(), serde_json::Value::Number((*n).into())))
}
SoundCoreParamValue::U32(n) => {
Some((name.to_string(), serde_json::Value::Number((*n).into())))
}
SoundCoreParamValue::Float(n) => {
serde_json::Number::from_f64((*n).into())
.map(|v| (name.to_string(), serde_json::Value::Number(v)))
}
SoundCoreParamValue::Bool(b) => {
Some((name.to_string(), serde_json::Value::Bool(*b)))
}
_ => None,
})
.collect(),
),
)
})
.collect()
}

pub fn prepare_for_save(settings: &CardSettings) -> SerdeCardSettings {
SerdeCardSettings {
selected_parameters: settings
.selected_parameters
.iter()
.map(|(name, params)| {
(
name.to_string(),
serde_json::Value::Array(
params
.iter()
.map(|param| serde_json::Value::String(param.to_string()))
.collect(),
),
)
})
.collect(),
profiles: SerdeProfiles {
headphones: SerdeProfile {
volume: settings.profiles.headphones.volume,
parameters: convert_from_soundcore(&settings.profiles.headphones.parameters),
},
speakers: SerdeProfile {
volume: settings.profiles.speakers.volume,
parameters: convert_from_soundcore(&settings.profiles.speakers.parameters),
},
},
}
}

pub fn save(settings: &SerdeCardSettings) -> Result<(), serde_json::Error> {
let mut path = env::current_exe().unwrap_or_default();
path.pop();
path.push("sbzdeck.json");
let file = File::create(path).map_err(serde_json::Error::io)?;
serde_json::to_writer_pretty(file, settings)
}
3 changes: 1 addition & 2 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,9 @@ impl IndexMut<Output> for Profiles {

pub struct RawState {
pub output: Option<Output>,
pub selected_parameters: IndexMap<String, IndexSet<String>>,
pub contexts: BTreeSet<String>,
pub out: mpsc::Sender<MessageOut<Empty, Empty>>,
pub profiles: Profiles,
pub settings: CardSettings,
}

pub type State = Arc<Mutex<RawState>>;
Expand Down

0 comments on commit 510b83c

Please sign in to comment.