Skip to content

Commit

Permalink
#1305 Restore warning when restoring invalid session
Browse files Browse the repository at this point in the history
  • Loading branch information
helgoboss committed Nov 4, 2024
1 parent fce4f9b commit 0097f46
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 55 deletions.
1 change: 0 additions & 1 deletion main/src/application/source_model.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::application::SourceProp::ButtonBackgroundImagePath;
use crate::application::{
Affected, Change, GetProcessingRelevance, MappingProp, ProcessingRelevance,
};
Expand Down
1 change: 0 additions & 1 deletion main/src/domain/stream_deck_device.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::domain::UnitId;
use base::hash_util::{NonCryptoHashMap, NonCryptoHashSet};
use derive_more::Display;
use hidapi::HidApi;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
Expand Down
70 changes: 43 additions & 27 deletions main/src/infrastructure/data/instance_data.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
use crate::infrastructure::data::{ClipMatrixRefData, UnitData};
use anyhow::{anyhow, bail, Context};

Check failure on line 2 in main/src/infrastructure/data/instance_data.rs

View workflow job for this annotation

GitHub Actions / Clippy

unused imports: `anyhow` and `bail`

Check warning on line 2 in main/src/infrastructure/data/instance_data.rs

View workflow job for this annotation

GitHub Actions / Check

unused imports: `anyhow` and `bail`

Check warning on line 2 in main/src/infrastructure/data/instance_data.rs

View workflow job for this annotation

GitHub Actions / Check

unused imports: `anyhow` and `bail`

Check warning on line 2 in main/src/infrastructure/data/instance_data.rs

View workflow job for this annotation

GitHub Actions / Test

unused imports: `anyhow` and `bail`

Check warning on line 2 in main/src/infrastructure/data/instance_data.rs

View workflow job for this annotation

GitHub Actions / Build

unused imports: `anyhow` and `bail`

Check warning on line 2 in main/src/infrastructure/data/instance_data.rs

View workflow job for this annotation

GitHub Actions / Build

unused imports: `anyhow` and `bail`

Check warning on line 2 in main/src/infrastructure/data/instance_data.rs

View workflow job for this annotation

GitHub Actions / Build

unused imports: `anyhow` and `bail`

Check warning on line 2 in main/src/infrastructure/data/instance_data.rs

View workflow job for this annotation

GitHub Actions / Test

unused imports: `anyhow` and `bail`

Check warning on line 2 in main/src/infrastructure/data/instance_data.rs

View workflow job for this annotation

GitHub Actions / Test

unused imports: `anyhow` and `bail`

Check warning on line 2 in main/src/infrastructure/data/instance_data.rs

View workflow job for this annotation

GitHub Actions / Check

unused imports: `anyhow` and `bail`
use base::default_util::{deserialize_null_default, is_default};
use base::hash_util::NonCryptoHashMap;
use helgobox_api::persistence::InstanceSettings;
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum InstanceOrUnitData {
InstanceData(InstanceData),
/// For backward compatibility.
UnitData(UnitData),
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct InstanceData {
Expand Down Expand Up @@ -43,27 +36,50 @@ pub struct InstanceData {
pub custom_data: NonCryptoHashMap<String, serde_json::Value>,
}

impl Default for InstanceOrUnitData {
fn default() -> Self {
Self::InstanceData(InstanceData::default())
impl InstanceData {
pub fn parse(data: &[u8]) -> anyhow::Result<Self> {
let instance_data: Self = match serde_json::from_slice(data) {
Ok(d) => d,
Err(instance_data_error) => {
// Couldn't parse as instance data. Unhappy path. Let's make some inspections.
let json: serde_json::Value = serde_json::from_slice(data)
.with_context(|| create_parse_error_msg(data, "parsing as JSON"))?;
// Parsing was successful
if json.get("mainUnit").is_some() {
// It's really meant as InstanceData. Fail!
Err(instance_data_error).with_context(|| {
create_parse_error_msg(data, "interpreting JSON as instance data")
})?;
}
// Ah, this could be a preset for the pre-2.16 era, meant as data for a single unit.
let data: UnitData = serde_json::from_value(json).with_context(|| {
create_parse_error_msg(data, "interpreting JSON as unit data")
})?;
convert_old_unit_to_instance_data(data)
}
};
Ok(instance_data)
}
}

impl InstanceOrUnitData {
#[allow(deprecated)]
pub fn into_instance_data(self) -> InstanceData {
match self {
InstanceOrUnitData::InstanceData(d) => d,
InstanceOrUnitData::UnitData(mut d) => InstanceData {
// Migrate pot state from unit data
pot_state: d.pot_state.take().unwrap_or_default(),
// Migrate clip matrix state from unit data
clip_matrix: d.clip_matrix.take(),
main_unit: d,
additional_units: vec![],
settings: Default::default(),
custom_data: Default::default(),
},
}
fn create_parse_error_msg(data: &[u8], label: &str) -> String {
let data_as_str = std::str::from_utf8(data).unwrap_or("<UTF-8 decoding error>");
format!(
"Helgobox couldn't restore this instance while {label}. Please attach the following text if you want to report this: \n\n\
{data_as_str}\n\n"
)
}

#[allow(deprecated)]
fn convert_old_unit_to_instance_data(mut d: UnitData) -> InstanceData {
InstanceData {
// Migrate pot state from unit data
pot_state: d.pot_state.take().unwrap_or_default(),
// Migrate clip matrix state from unit data
clip_matrix: d.clip_matrix.take(),
main_unit: d,
additional_units: vec![],
settings: Default::default(),
custom_data: Default::default(),
}
}
6 changes: 2 additions & 4 deletions main/src/infrastructure/plugin/helgobox_plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use std::sync::{Arc, OnceLock};

use crate::infrastructure::plugin::backbone_shell::BackboneShell;

use crate::infrastructure::data::InstanceOrUnitData;
use crate::infrastructure::data::InstanceData;
use crate::infrastructure::plugin::helgobox_plugin_editor::HelgoboxPluginEditor;
use crate::infrastructure::plugin::instance_shell::InstanceShell;
use crate::infrastructure::ui::instance_panel::InstancePanel;
Expand Down Expand Up @@ -414,9 +414,7 @@ impl HelgoboxPlugin {
match param_name {
SET_STATE_PARAM_NAME => {
let c_str = unsafe { CStr::from_ptr(buffer) };
let rust_str = c_str.to_str().expect("not valid UTF-8");
let data: InstanceOrUnitData = serde_json::from_str(rust_str)
.context("couldn't deserialize instance or unit data")?;
let data = InstanceData::parse(c_str.to_bytes())?;
let lazy_data = self.lazy_data.get().context("lazy data not yet set")?;
lazy_data.instance_shell.clone().apply_data(data)?;
Ok(())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use reaper_low::firewall;
use std::sync;

use crate::domain::{ParameterManager, PluginParamIndex};
use crate::infrastructure::data::InstanceOrUnitData;
use crate::infrastructure::data::InstanceData;
use crate::infrastructure::plugin::instance_shell::InstanceShell;
use reaper_high::Reaper;
use std::sync::{Arc, OnceLock, RwLock};
Expand Down Expand Up @@ -175,7 +175,7 @@ impl PluginParameters for InstanceParameterContainer {
.instance_shell
.upgrade()
.expect("instance shell gone")
.apply_data(InstanceOrUnitData::default())
.apply_data(InstanceData::default())
.expect("couldn't load factory default");
}
return;
Expand Down
23 changes: 6 additions & 17 deletions main/src/infrastructure/plugin/instance_shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::domain::{
ControlEvent, IncomingMidiMessage, Instance, InstanceHandler, InstanceId, MidiEvent,
ProcessorContext, SharedInstance, SharedRealTimeInstance, UnitId,
};
use crate::infrastructure::data::{InstanceData, InstanceOrUnitData, UnitData};
use crate::infrastructure::data::{InstanceData, UnitData};
use crate::infrastructure::plugin::unit_shell::UnitShell;
use crate::infrastructure::plugin::{update_auto_units_async, BackboneShell};
use crate::infrastructure::ui::instance_panel::InstancePanel;
Expand Down Expand Up @@ -402,8 +402,7 @@ impl InstanceShell {
/// Must be called from the main thread.
pub fn save(&self) -> Vec<u8> {
let instance_data = self.create_data();
let data = InstanceOrUnitData::InstanceData(instance_data);
serde_json::to_vec(&data).expect("couldn't serialize instance data")
serde_json::to_vec(&instance_data).expect("couldn't serialize instance data")
}

fn remove_auto_unit_if_requirements_met(
Expand Down Expand Up @@ -487,32 +486,22 @@ impl InstanceShell {
// ReaLearn C++ saved some IPlug binary data in front of the actual JSON object. Find
// start of JSON data.
let data = &data[left_json_object_brace..];
let data: InstanceOrUnitData = match serde_json::from_slice(data) {
Ok(d) => d,
Err(e) => {
bail!(
"Helgobox couldn't restore this unit: {}\n\nPlease also attach the following text when reporting this: \n\n{}",
e,
std::str::from_utf8(data).unwrap_or("UTF-8 decoding error")
)
}
};
self.apply_data_internal(data)?;
let instance_data = InstanceData::parse(data)?;
self.apply_data_internal(instance_data)?;
Ok(())
}

pub fn apply_data(
self: SharedInstanceShell,
instance_data: InstanceOrUnitData,
instance_data: InstanceData,
) -> anyhow::Result<()> {
self.apply_data_internal(instance_data)
}

fn apply_data_internal(
self: SharedInstanceShell,
instance_data: InstanceOrUnitData,
instance_data: InstanceData,
) -> anyhow::Result<()> {
let instance_data = instance_data.into_instance_data();
let instance = self.instance();
// General properties
*self.settings.get().borrow_mut() = instance_data.settings;
Expand Down
6 changes: 3 additions & 3 deletions main/src/infrastructure/ui/header_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ use crate::domain::{
use crate::domain::{MidiControlInput, MidiDestination};
use crate::infrastructure::data::{
CommonCompartmentPresetManager, CommonPresetInfo, CompartmentModelData,
FileBasedMainPresetManager, InstanceOrUnitData, MappingModelData, OscDevice, PresetFileType,
PresetOrigin, UnitData,
FileBasedMainPresetManager, MappingModelData, OscDevice, PresetFileType, PresetOrigin,
UnitData,
};
use crate::infrastructure::plugin::{
update_auto_units_async, warn_about_failed_server_start, BackboneShell,
Expand Down Expand Up @@ -2047,7 +2047,7 @@ impl HeaderPanel {
let instance_panel = self.instance_panel();
instance_panel.show_unit(None);
let instance_shell = instance_panel.shell()?;
instance_shell.apply_data(InstanceOrUnitData::InstanceData(*d))?;
instance_shell.apply_data(*d)?;
}
}
Tagged(DataObject::Unit(Envelope { value: d, .. })) => {
Expand Down

0 comments on commit 0097f46

Please sign in to comment.