use super::*;
impl<'de> Deserialize<'de> for UpdateStatus {
fn deserialize<Reader>(reader: Reader) -> Result<Self, Reader::Error>
where
Reader: serde::Deserializer<'de>,
{
struct TagVisitor;
impl<'de> serde::de::Visitor<'de> for TagVisitor {
type Value = UpdateStatus;
fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
formatter.write_str(&format!(
"an `UpdateStatus` wire tag ({UPDATE_RESULT_SUCCESS:?} / {UPDATE_RESULT_FAILED:?})"
))
}
fn visit_str<Error>(self, value: &str) -> Result<Self::Value, Error>
where
Error: serde::de::Error,
{
if value == UPDATE_RESULT_SUCCESS {
Ok(UpdateStatus::Success)
} else if value == UPDATE_RESULT_FAILED {
Ok(UpdateStatus::Failed)
} else {
Err(Error::unknown_variant(
value,
&[UPDATE_RESULT_SUCCESS, UPDATE_RESULT_FAILED],
))
}
}
}
reader.deserialize_str(TagVisitor)
}
}
impl Display for UpdateStatus {
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
let tag: &'static str = match self {
UpdateStatus::Success => UPDATE_RESULT_SUCCESS,
UpdateStatus::Failed => UPDATE_RESULT_FAILED,
};
formatter.write_str(tag)
}
}
impl Default for BridgeConfig {
fn default() -> Self {
BridgeConfig::new(
BRIDGE_DEFAULT_GLOBAL_KEY,
BRIDGE_DEFAULT_CORE_KEY,
BRIDGE_DEFAULT_INVOKE_KEY,
)
}
}
impl UseEuvNativeBridge {
pub(crate) fn use_bridge_state() -> UseEuvNativeBridge {
UseEuvNativeBridge::new(
App::use_signal(|| false),
App::use_signal(|| true),
App::use_signal(String::new),
)
}
pub(crate) fn load_data(self, config: Option<BridgeConfig>) {
if !BridgeConfig::is_available(config.as_ref()) {
self.get_available().set(false);
self.get_loading().set(false);
return;
}
let permissions_state: UseEuvNativeBridge = self;
spawn_local(async move {
let args_obj: Object = Object::new();
Reflect::set(
&args_obj,
&JsValue::from_str(BRIDGE_GROUP_KEY),
&JsValue::from_str(BRIDGE_GROUP_ALL),
)
.unwrap_or_default();
let permissions_result: Result<JsValue, String> = match BridgeConfig::invoke(
INVOKE_RESOLVE_BRIDGE_GROUP_PERMISSIONS,
Some(&args_obj),
config.as_ref(),
) {
Ok(promise) => {
let future: JsFuture = JsFuture::from(promise);
match future.await {
Ok(value) => Ok(value),
Err(error) => Err(format!("{error:?}")),
}
}
Err(error) => Err(error),
};
match permissions_result {
Ok(value) => {
let permissions_array: Vec<String> = value
.dyn_into::<Array>()
.map(|array: Array| {
array
.iter()
.filter_map(|item: JsValue| item.as_string())
.collect::<Vec<String>>()
})
.unwrap_or_default();
permissions_state
.get_permissions()
.set(permissions_array.join(", "));
permissions_state.get_available().set(true);
}
Err(_) => {
permissions_state.get_available().set(false);
}
}
permissions_state.get_loading().set(false);
});
}
}
impl UseCacheUpdate {
pub(crate) fn use_cache_state() -> UseCacheUpdate {
UseCacheUpdate::new(
App::use_signal(|| false),
App::use_signal(String::new),
App::use_signal(|| false),
App::use_signal(String::new),
App::use_signal(String::new),
)
}
pub(crate) fn load<F, Fut>(self, updater: F)
where
F: FnOnce() -> Fut + 'static,
Fut: Future<Output = UpdateResult>,
{
spawn_local(async move {
let result: UpdateResult = updater().await;
self.get_doc_status().set(result.get_doc_status());
self.get_version().set(result.get_version().clone());
self.get_updating().set(result.get_updating());
self.get_data().set(result.get_data().clone());
self.get_message().set(result.get_message().clone());
});
}
}
impl BridgeConfig {
pub(crate) fn is_available(config: Option<&BridgeConfig>) -> bool {
let config: BridgeConfig = config.cloned().unwrap_or_default();
let Some(window_value): Option<Window> = window() else {
return false;
};
let bridge_key: JsValue = JsValue::from_str(config.get_global_key());
let bridge_obj: JsValue = match Reflect::get(&window_value, &bridge_key) {
Ok(value) => value,
Err(_) => return false,
};
if bridge_obj.is_undefined() || bridge_obj.is_null() {
return false;
}
let core_key: JsValue = JsValue::from_str(config.get_core_key());
let core_obj: JsValue = match Reflect::get(&bridge_obj, &core_key) {
Ok(value) => value,
Err(_) => return false,
};
!core_obj.is_undefined() && !core_obj.is_null()
}
pub(crate) fn invoke(
command: &str,
args: Option<&JsValue>,
config: Option<&BridgeConfig>,
) -> Result<Promise, String> {
let config: BridgeConfig = config.cloned().unwrap_or_default();
let Some(window_value): Option<Window> = window() else {
return Err("no global window exists".to_string());
};
let bridge_key: JsValue = JsValue::from_str(config.get_global_key());
let bridge_obj: JsValue = Reflect::get(&window_value, &bridge_key)
.map_err(|error: JsValue| format!("{error:?}"))?;
let core_key: JsValue = JsValue::from_str(config.get_core_key());
let core_obj: JsValue =
Reflect::get(&bridge_obj, &core_key).map_err(|error: JsValue| format!("{error:?}"))?;
let invoke_key: JsValue = JsValue::from_str(config.get_invoke_key());
let invoke_fn: JsValue =
Reflect::get(&core_obj, &invoke_key).map_err(|error: JsValue| format!("{error:?}"))?;
let invoke_function: Function = invoke_fn
.dyn_into::<Function>()
.map_err(|error: JsValue| format!("{error:?}"))?;
let command_value: JsValue = JsValue::from_str(command);
let result: JsValue = match args {
Some(arguments) => invoke_function
.call2(&core_obj, &command_value, arguments)
.map_err(|error: JsValue| format!("{error:?}"))?,
None => invoke_function
.call1(&core_obj, &command_value)
.map_err(|error: JsValue| format!("{error:?}"))?,
};
result
.dyn_into::<Promise>()
.map_err(|error: JsValue| format!("{error:?}"))
}
}