Skip to content

Commit

Permalink
Merge branch 'main' into 2025-02-20-error-handling
Browse files Browse the repository at this point in the history
  • Loading branch information
hardyjosh authored Feb 20, 2025
2 parents 9466c5f + 9edbf36 commit 7d0a239
Show file tree
Hide file tree
Showing 25 changed files with 271 additions and 180 deletions.
1 change: 1 addition & 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 crates/js_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ base64 = "0.22.1"
bincode = "1.3.3"
sha2 = "0.10.8"
web-sys = { version = "0.3.69", features = ["console"] }
strict-yaml-rust = { workspace = true }
8 changes: 6 additions & 2 deletions crates/js_api/src/gui/deposits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl DotrainOrderGui {
let gui_deposit = self.get_gui_deposit(&token)?;

if amount.is_empty() {
self.remove_deposit(token);
self.remove_deposit(token)?;
return Ok(());
}

Expand All @@ -85,12 +85,16 @@ impl DotrainOrderGui {
};

self.deposits.insert(token, value);

self.execute_state_update_callback()?;
Ok(())
}

#[wasm_bindgen(js_name = "removeDeposit")]
pub fn remove_deposit(&mut self, token: String) {
pub fn remove_deposit(&mut self, token: String) -> Result<(), GuiError> {
self.deposits.remove(&token);
self.execute_state_update_callback()?;
Ok(())
}

#[wasm_bindgen(js_name = "getDepositPresets")]
Expand Down
6 changes: 5 additions & 1 deletion crates/js_api/src/gui/field_values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ impl DotrainOrderGui {
}
}
self.field_values.insert(binding, value);

self.execute_state_update_callback()?;
Ok(())
}

Expand All @@ -54,8 +56,10 @@ impl DotrainOrderGui {
}

#[wasm_bindgen(js_name = "removeFieldValue")]
pub fn remove_field_value(&mut self, binding: String) {
pub fn remove_field_value(&mut self, binding: String) -> Result<(), GuiError> {
self.field_values.remove(&binding);
self.execute_state_update_callback()?;
Ok(())
}

#[wasm_bindgen(js_name = "getFieldValue")]
Expand Down
6 changes: 6 additions & 0 deletions crates/js_api/src/gui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ pub struct DotrainOrderGui {
selected_deployment: String,
field_values: BTreeMap<String, field_values::PairValue>,
deposits: BTreeMap<String, field_values::PairValue>,
#[serde(skip)]
state_update_callback: Option<js_sys::Function>,
}
#[wasm_bindgen]
impl DotrainOrderGui {
Expand All @@ -67,6 +69,7 @@ impl DotrainOrderGui {
pub async fn choose_deployment(
dotrain: String,
deployment_name: String,
state_update_callback: Option<js_sys::Function>,
) -> Result<DotrainOrderGui, GuiError> {
let dotrain_order = DotrainOrder::new(dotrain, None).await?;

Expand All @@ -80,6 +83,7 @@ impl DotrainOrderGui {
selected_deployment: deployment_name.clone(),
field_values: BTreeMap::new(),
deposits: BTreeMap::new(),
state_update_callback,
})
}

Expand Down Expand Up @@ -235,6 +239,8 @@ pub enum GuiError {
BindingHasNoPresets(String),
#[error("Token not in select tokens: {0}")]
TokenNotInSelectTokens(String),
#[error("JavaScript error: {0}")]
JsError(String),
#[error(transparent)]
DotrainOrderError(#[from] DotrainOrderError),
#[error(transparent)]
Expand Down
2 changes: 2 additions & 0 deletions crates/js_api/src/gui/order_operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,8 @@ impl DotrainOrderGui {
.dotrain_yaml()
.get_order(&deployment.deployment.order.key)?
.update_vault_id(is_input, index, vault_id)?;

self.execute_state_update_callback()?;
Ok(())
}

Expand Down
4 changes: 4 additions & 0 deletions crates/js_api/src/gui/select_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ impl DotrainOrderGui {
Some(&token_info.name),
Some(&token_info.symbol),
)?;

self.execute_state_update_callback()?;
Ok(())
}

Expand All @@ -122,6 +124,8 @@ impl DotrainOrderGui {
}

Token::remove_record_from_yaml(self.dotrain_order.orderbook_yaml().documents, &key)?;

self.execute_state_update_callback()?;
Ok(())
}

Expand Down
147 changes: 82 additions & 65 deletions crates/js_api/src/gui/state_management.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use super::*;
use rain_orderbook_app_settings::token::Token;
use sha2::{Digest, Sha256};
use std::sync::{Arc, RwLock};
use strict_yaml_rust::StrictYaml;

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
struct SerializedGuiState {
Expand All @@ -20,6 +22,54 @@ impl DotrainOrderGui {
Ok(URL_SAFE.encode(hash))
}

fn create_preset(value: &field_values::PairValue, default_value: String) -> GuiPreset {
if value.is_preset {
GuiPreset {
id: value.value.clone(),
name: None,
value: default_value,
}
} else {
GuiPreset {
id: "".to_string(),
name: None,
value: value.value.clone(),
}
}
}

fn preset_to_pair_value(preset: GuiPreset) -> field_values::PairValue {
if preset.id != "" {
field_values::PairValue {
is_preset: true,
value: preset.id,
}
} else {
field_values::PairValue {
is_preset: false,
value: preset.value,
}
}
}

fn parse_vault_ids_for_order(
documents: Vec<Arc<RwLock<StrictYaml>>>,
order_key: &str,
is_input: bool,
) -> Result<BTreeMap<(bool, u8), Option<String>>, GuiError> {
let mut vault_ids = BTreeMap::new();
for (i, vault_id) in Order::parse_vault_ids(documents, order_key, is_input)?
.iter()
.enumerate()
{
vault_ids.insert(
(is_input, i as u8),
vault_id.as_ref().map(|v| v.to_string()),
);
}
Ok(vault_ids)
}

#[wasm_bindgen(js_name = "serializeState")]
pub fn serialize_state(&self) -> Result<String, GuiError> {
let mut field_values = BTreeMap::new();
Expand All @@ -37,30 +87,14 @@ impl DotrainOrderGui {
.ok_or(GuiError::InvalidPreset)?
.clone()
} else {
GuiPreset {
id: "".to_string(),
name: None,
value: v.value.clone(),
}
Self::create_preset(v, String::default())
};
field_values.insert(k.clone(), preset);
}

let mut deposits = BTreeMap::new();
for (k, v) in self.deposits.iter() {
let preset = if v.is_preset {
GuiPreset {
id: v.value.clone(),
name: None,
value: String::default(),
}
} else {
GuiPreset {
id: "".to_string(),
name: None,
value: v.value.clone(),
}
};
let preset = Self::create_preset(v, String::default());
deposits.insert(k.clone(), preset);
}

Expand All @@ -81,30 +115,20 @@ impl DotrainOrderGui {
}

let order_key = Deployment::parse_order_key(
self.dotrain_order.dotrain_yaml().documents,
self.dotrain_order.dotrain_yaml().documents.clone(),
&self.selected_deployment,
)?;
let mut vault_ids = BTreeMap::new();
for (i, vault_id) in Order::parse_vault_ids(
vault_ids.extend(Self::parse_vault_ids_for_order(
self.dotrain_order.dotrain_yaml().documents.clone(),
&order_key,
true,
)?
.iter()
.enumerate()
{
vault_ids.insert((true, i as u8), vault_id.as_ref().map(|v| v.to_string()));
}
for (i, vault_id) in Order::parse_vault_ids(
)?);
vault_ids.extend(Self::parse_vault_ids_for_order(
self.dotrain_order.dotrain_yaml().documents.clone(),
&order_key,
false,
)?
.iter()
.enumerate()
{
vault_ids.insert((false, i as u8), vault_id.as_ref().map(|v| v.to_string()));
}
)?);

let state = SerializedGuiState {
field_values: field_values.clone(),
Expand All @@ -127,6 +151,7 @@ impl DotrainOrderGui {
pub async fn deserialize_state(
dotrain: String,
serialized: String,
state_update_callback: Option<js_sys::Function>,
) -> Result<DotrainOrderGui, GuiError> {
let compressed = URL_SAFE.decode(serialized)?;

Expand All @@ -145,46 +170,21 @@ impl DotrainOrderGui {
let field_values = state
.field_values
.into_iter()
.map(|(k, v)| {
let pair_value = if v.id != "" {
field_values::PairValue {
is_preset: true,
value: v.id,
}
} else {
field_values::PairValue {
is_preset: false,
value: v.value,
}
};
(k, pair_value)
})
.map(|(k, v)| (k, Self::preset_to_pair_value(v)))
.collect::<BTreeMap<_, _>>();

let deposits = state
.deposits
.into_iter()
.map(|(k, v)| {
let pair_value = if v.id != "" {
field_values::PairValue {
is_preset: true,
value: v.id,
}
} else {
field_values::PairValue {
is_preset: false,
value: v.value,
}
};
(k, pair_value)
})
.map(|(k, v)| (k, Self::preset_to_pair_value(v)))
.collect::<BTreeMap<_, _>>();

let dotrain_order_gui = DotrainOrderGui {
dotrain_order,
field_values,
deposits,
selected_deployment: state.selected_deployment.clone(),
state_update_callback,
};

let deployment_select_tokens = Gui::parse_select_tokens(
Expand Down Expand Up @@ -236,15 +236,32 @@ impl DotrainOrderGui {
self.deposits.clear();
}

fn is_preset<K: AsRef<str>>(
&self,
key: K,
map: &BTreeMap<String, field_values::PairValue>,
) -> Option<bool> {
map.get(key.as_ref()).map(|v| v.is_preset)
}

#[wasm_bindgen(js_name = "isFieldPreset")]
pub fn is_field_preset(&self, binding: String) -> Option<bool> {
let value = self.field_values.get(&binding);
value.map(|v| v.is_preset)
self.is_preset(binding, &self.field_values)
}

#[wasm_bindgen(js_name = "isDepositPreset")]
pub fn is_deposit_preset(&self, token: String) -> Option<bool> {
let value = self.deposits.get(&token);
value.map(|v| v.is_preset)
self.is_preset(token, &self.deposits)
}

#[wasm_bindgen(js_name = "executeStateUpdateCallback")]
pub fn execute_state_update_callback(&self) -> Result<(), GuiError> {
if let Some(callback) = &self.state_update_callback {
let state = to_value(&self.serialize_state()?)?;
callback.call1(&JsValue::UNDEFINED, &state).map_err(|e| {
GuiError::JsError(format!("Failed to execute state update callback: {:?}", e))
})?;
}
Ok(())
}
}
Loading

0 comments on commit 7d0a239

Please sign in to comment.