Queries now use AppHandle instead of Window (#189)

This commit is contained in:
Gregory Schier
2025-03-20 09:43:14 -07:00
committed by GitHub
parent cf8f8743bb
commit 4c4eaba7d2
19 changed files with 1063 additions and 740 deletions

View File

@@ -1,8 +1,7 @@
use tauri::{Manager, Runtime, WebviewWindow};
use tauri::{AppHandle, Runtime};
use yaak_models::queries::{
get_key_value_int, get_key_value_string,
set_key_value_int, set_key_value_string, UpdateSource,
get_key_value_int, get_key_value_string, set_key_value_int, set_key_value_string, UpdateSource,
};
const NAMESPACE: &str = "analytics";
@@ -16,14 +15,15 @@ pub struct LaunchEventInfo {
pub num_launches: i32,
}
pub async fn store_launch_history<R: Runtime>(w: &WebviewWindow<R>) -> LaunchEventInfo {
pub async fn store_launch_history<R: Runtime>(app_handle: &AppHandle<R>) -> LaunchEventInfo {
let last_tracked_version_key = "last_tracked_version";
let mut info = LaunchEventInfo::default();
info.num_launches = get_num_launches(w).await + 1;
info.previous_version = get_key_value_string(w, NAMESPACE, last_tracked_version_key, "").await;
info.current_version = w.package_info().version.to_string();
info.num_launches = get_num_launches(app_handle).await + 1;
info.previous_version =
get_key_value_string(app_handle, NAMESPACE, last_tracked_version_key, "").await;
info.current_version = app_handle.package_info().version.to_string();
if info.previous_version.is_empty() {
} else {
@@ -33,16 +33,22 @@ pub async fn store_launch_history<R: Runtime>(w: &WebviewWindow<R>) -> LaunchEve
// Update key values
set_key_value_string(
w,
app_handle,
NAMESPACE,
last_tracked_version_key,
info.current_version.as_str(),
&UpdateSource::Background,
)
.await;
set_key_value_int(w, NAMESPACE, NUM_LAUNCHES_KEY, info.num_launches, &UpdateSource::Background)
.await;
set_key_value_int(
app_handle,
NAMESPACE,
NUM_LAUNCHES_KEY,
info.num_launches,
&UpdateSource::Background,
)
.await;
info
}
@@ -59,6 +65,6 @@ pub fn get_os() -> &'static str {
}
}
pub async fn get_num_launches<R: Runtime>(w: &WebviewWindow<R>) -> i32 {
get_key_value_int(w, NAMESPACE, NUM_LAUNCHES_KEY, 0).await
pub async fn get_num_launches<R: Runtime>(app_handle: &AppHandle<R>) -> i32 {
get_key_value_int(app_handle, NAMESPACE, NUM_LAUNCHES_KEY, 0).await
}

View File

@@ -46,18 +46,22 @@ pub async fn send_http_request<R: Runtime>(
cookie_jar: Option<CookieJar>,
cancelled_rx: &mut Receiver<bool>,
) -> Result<HttpResponse> {
let plugin_manager = window.state::<PluginManager>();
let workspace = get_workspace(window, &unrendered_request.workspace_id).await?;
let base_environment = get_base_environment(window, &unrendered_request.workspace_id).await?;
let settings = get_or_create_settings(window).await;
let app_handle = window.app_handle().clone();
let plugin_manager = app_handle.state::<PluginManager>();
let workspace = get_workspace(&app_handle, &unrendered_request.workspace_id).await?;
let base_environment =
get_base_environment(&app_handle, &unrendered_request.workspace_id).await?;
let settings = get_or_create_settings(&app_handle).await;
let response_id = og_response.id.clone();
let response = Arc::new(Mutex::new(og_response.clone()));
let cb = PluginTemplateCallback::new(
window.app_handle(),
&WindowContext::from_window(window),
RenderPurpose::Send,
);
let response_id = og_response.id.clone();
let response = Arc::new(Mutex::new(og_response.clone()));
let update_source = UpdateSource::from_window(window);
let request = match render_http_request(
&unrendered_request,
@@ -68,7 +72,15 @@ pub async fn send_http_request<R: Runtime>(
.await
{
Ok(r) => r,
Err(e) => return Ok(response_err(&*response.lock().await, e.to_string(), window).await),
Err(e) => {
return Ok(response_err(
&app_handle,
&*response.lock().await,
e.to_string(),
&update_source,
)
.await)
}
};
let mut url_string = request.url;
@@ -178,9 +190,10 @@ pub async fn send_http_request<R: Runtime>(
Ok(u) => u,
Err(e) => {
return Ok(response_err(
&app_handle,
&*response.lock().await,
format!("Failed to parse URL \"{}\": {}", url_string, e.to_string()),
window,
&update_source,
)
.await);
}
@@ -190,9 +203,10 @@ pub async fn send_http_request<R: Runtime>(
Ok(u) => u,
Err(e) => {
return Ok(response_err(
&app_handle,
&*response.lock().await,
format!("Failed to parse URL \"{}\": {}", url_string, e.to_string()),
window,
&update_source,
)
.await);
}
@@ -296,7 +310,13 @@ pub async fn send_http_request<R: Runtime>(
request_builder = request_builder.body(f);
}
Err(e) => {
return Ok(response_err(&*response.lock().await, e, window).await);
return Ok(response_err(
&app_handle,
&*response.lock().await,
e,
&update_source,
)
.await);
}
}
} else if body_type == "multipart/form-data" && request_body.contains_key("form") {
@@ -323,9 +343,10 @@ pub async fn send_http_request<R: Runtime>(
Ok(f) => multipart::Part::bytes(f),
Err(e) => {
return Ok(response_err(
&app_handle,
&*response.lock().await,
e.to_string(),
window,
&update_source,
)
.await);
}
@@ -340,9 +361,10 @@ pub async fn send_http_request<R: Runtime>(
Ok(p) => p,
Err(e) => {
return Ok(response_err(
&app_handle,
&*response.lock().await,
format!("Invalid mime for multi-part entry {e:?}"),
window,
&update_source,
)
.await);
}
@@ -356,9 +378,10 @@ pub async fn send_http_request<R: Runtime>(
Ok(p) => p,
Err(e) => {
return Ok(response_err(
&app_handle,
&*response.lock().await,
format!("Invalid mime for multi-part entry {e:?}"),
window,
&update_source,
)
.await);
}
@@ -397,7 +420,13 @@ pub async fn send_http_request<R: Runtime>(
Ok(r) => r,
Err(e) => {
warn!("Failed to build request builder {e:?}");
return Ok(response_err(&*response.lock().await, e.to_string(), window).await);
return Ok(response_err(
&app_handle,
&*response.lock().await,
e.to_string(),
&update_source,
)
.await);
}
};
@@ -423,7 +452,13 @@ pub async fn send_http_request<R: Runtime>(
let plugin_result = match auth_result {
Ok(r) => r,
Err(e) => {
return Ok(response_err(&*response.lock().await, e.to_string(), window).await);
return Ok(response_err(
&app_handle,
&*response.lock().await,
e.to_string(),
&update_source,
)
.await);
}
};
@@ -449,21 +484,23 @@ pub async fn send_http_request<R: Runtime>(
Ok(r) = resp_rx => r,
_ = cancelled_rx.changed() => {
debug!("Request cancelled");
return Ok(response_err(&*response.lock().await, "Request was cancelled".to_string(), window).await);
return Ok(response_err(&app_handle, &*response.lock().await, "Request was cancelled".to_string(), &update_source).await);
}
};
{
let app_handle = app_handle.clone();
let window = window.clone();
let cancelled_rx = cancelled_rx.clone();
let response_id = response_id.clone();
let response = response.clone();
let update_source = update_source.clone();
tokio::spawn(async move {
match raw_response {
Ok(mut v) => {
let content_length = v.content_length();
let response_headers = v.headers().clone();
let dir = window.app_handle().path().app_data_dir().unwrap();
let dir = app_handle.path().app_data_dir().unwrap();
let base_dir = dir.join("responses");
create_dir_all(base_dir.clone()).await.expect("Failed to create responses dir");
let body_path = if response_id.is_empty() {
@@ -497,7 +534,7 @@ pub async fn send_http_request<R: Runtime>(
};
r.state = HttpResponseState::Connected;
update_response_if_id(&window, &r, &UpdateSource::Window)
update_response_if_id(&app_handle, &r, &update_source)
.await
.expect("Failed to update response after connected");
}
@@ -526,7 +563,7 @@ pub async fn send_http_request<R: Runtime>(
f.flush().await.expect("Failed to flush file");
written_bytes += bytes.len();
r.content_length = Some(written_bytes as i32);
update_response_if_id(&window, &r, &UpdateSource::Window)
update_response_if_id(&app_handle, &r, &update_source)
.await
.expect("Failed to update response");
}
@@ -534,7 +571,13 @@ pub async fn send_http_request<R: Runtime>(
break;
}
Err(e) => {
response_err(&*response.lock().await, e.to_string(), &window).await;
response_err(
&app_handle,
&*response.lock().await,
e.to_string(),
&update_source,
)
.await;
break;
}
}
@@ -548,7 +591,7 @@ pub async fn send_http_request<R: Runtime>(
None => Some(written_bytes as i32),
};
r.state = HttpResponseState::Closed;
update_response_if_id(&window, &r, &UpdateSource::Window)
update_response_if_id(&app_handle, &r, &UpdateSource::from_window(&window))
.await
.expect("Failed to update response");
};
@@ -574,8 +617,12 @@ pub async fn send_http_request<R: Runtime>(
})
.collect::<Vec<_>>();
cookie_jar.cookies = json_cookies;
if let Err(e) =
upsert_cookie_jar(&window, &cookie_jar, &UpdateSource::Window).await
if let Err(e) = upsert_cookie_jar(
&app_handle,
&cookie_jar,
&UpdateSource::from_window(&window),
)
.await
{
error!("Failed to update cookie jar: {}", e);
};
@@ -583,7 +630,13 @@ pub async fn send_http_request<R: Runtime>(
}
Err(e) => {
warn!("Failed to execute request {e}");
response_err(&*response.lock().await, format!("{e}{e:?}"), &window).await;
response_err(
&app_handle,
&*response.lock().await,
format!("{e}{e:?}"),
&update_source,
)
.await;
}
};
@@ -592,16 +645,17 @@ pub async fn send_http_request<R: Runtime>(
});
};
let app_handle = app_handle.clone();
Ok(tokio::select! {
Ok(r) = done_rx => r,
_ = cancelled_rx.changed() => {
match get_http_response(window, response_id.as_str()).await {
match get_http_response(&app_handle, response_id.as_str()).await {
Ok(mut r) => {
r.state = HttpResponseState::Closed;
update_response_if_id(&window, &r, &UpdateSource::Window).await.expect("Failed to update response")
update_response_if_id(&app_handle, &r, &UpdateSource::from_window(window)).await.expect("Failed to update response")
},
_ => {
response_err(&*response.lock().await, "Ephemeral request was cancelled".to_string(), &window).await
response_err(&app_handle, &*response.lock().await, "Ephemeral request was cancelled".to_string(), &update_source).await
}.clone(),
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ use log::debug;
use reqwest::Method;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use tauri::{Emitter, Manager, Runtime, WebviewWindow};
use tauri::{AppHandle, Emitter, Manager, Runtime, WebviewWindow};
use yaak_models::queries::{get_key_value_raw, set_key_value_raw, UpdateSource};
// Check for updates every hour
@@ -43,16 +43,18 @@ impl YaakNotifier {
}
}
pub async fn seen<R: Runtime>(&mut self, w: &WebviewWindow<R>, id: &str) -> Result<(), String> {
let mut seen = get_kv(w).await?;
pub async fn seen<R: Runtime>(&mut self, window: &WebviewWindow<R>, id: &str) -> Result<(), String> {
let app_handle = window.app_handle();
let mut seen = get_kv(app_handle).await?;
seen.push(id.to_string());
debug!("Marked notification as seen {}", id);
let seen_json = serde_json::to_string(&seen).map_err(|e| e.to_string())?;
set_key_value_raw(w, KV_NAMESPACE, KV_KEY, seen_json.as_str(), &UpdateSource::Window).await;
set_key_value_raw(app_handle, KV_NAMESPACE, KV_KEY, seen_json.as_str(), &UpdateSource::from_window(window)).await;
Ok(())
}
pub async fn check<R: Runtime>(&mut self, window: &WebviewWindow<R>) -> Result<(), String> {
let app_handle = window.app_handle();
let ignore_check = self.last_check.elapsed().unwrap().as_secs() < MAX_UPDATE_CHECK_SECONDS;
if ignore_check {
@@ -61,8 +63,8 @@ impl YaakNotifier {
self.last_check = SystemTime::now();
let num_launches = get_num_launches(window).await;
let info = window.app_handle().package_info().clone();
let num_launches = get_num_launches(app_handle).await;
let info = app_handle.package_info().clone();
let req = reqwest::Client::default()
.request(Method::GET, "https://notify.yaak.app/notifications")
.query(&[
@@ -90,14 +92,14 @@ impl YaakNotifier {
for notification in notifications {
let age = notification.timestamp.signed_duration_since(Utc::now());
let seen = get_kv(window).await?;
let seen = get_kv(app_handle).await?;
if seen.contains(&notification.id) || (age > Duration::days(2)) {
debug!("Already seen notification {}", notification.id);
continue;
}
debug!("Got notification {:?}", notification);
let _ = window.emit_to(window.label(), "notification", notification.clone());
let _ = app_handle.emit_to(window.label(), "notification", notification.clone());
break; // Only show one notification
}
@@ -105,8 +107,8 @@ impl YaakNotifier {
}
}
async fn get_kv<R: Runtime>(w: &WebviewWindow<R>) -> Result<Vec<String>, String> {
match get_key_value_raw(w, "notifications", "seen").await {
async fn get_kv<R: Runtime>(app_handle: &AppHandle<R>) -> Result<Vec<String>, String> {
match get_key_value_raw(app_handle, "notifications", "seen").await {
None => Ok(Vec::new()),
Some(v) => serde_json::from_str(&v.value).map_err(|e| e.to_string()),
}

View File

@@ -18,8 +18,8 @@ use yaak_models::queries::{
use yaak_plugins::events::{
Color, DeleteKeyValueResponse, EmptyPayload, FindHttpResponsesResponse,
GetHttpRequestByIdResponse, GetKeyValueResponse, Icon, InternalEvent, InternalEventPayload,
RenderHttpRequestResponse, SendHttpRequestResponse, SetKeyValueResponse, ShowToastRequest,
TemplateRenderResponse, WindowContext, WindowNavigateEvent,
RenderHttpRequestResponse, RenderPurpose, SendHttpRequestResponse, SetKeyValueResponse,
ShowToastRequest, TemplateRenderResponse, WindowContext, WindowNavigateEvent,
};
use yaak_plugins::manager::PluginManager;
use yaak_plugins::plugin_handle::PluginHandle;
@@ -80,7 +80,7 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
.await
.expect("Failed to get workspace_id from window URL");
let environment = environment_from_window(&window).await;
let base_environment = get_base_environment(&window, workspace.id.as_str())
let base_environment = get_base_environment(app_handle, workspace.id.as_str())
.await
.expect("Failed to get base environment");
let cb = PluginTemplateCallback::new(app_handle, &window_context, req.purpose);
@@ -104,7 +104,7 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
.await
.expect("Failed to get workspace_id from window URL");
let environment = environment_from_window(&window).await;
let base_environment = get_base_environment(&window, workspace.id.as_str())
let base_environment = get_base_environment(app_handle, workspace.id.as_str())
.await
.expect("Failed to get base environment");
let cb = PluginTemplateCallback::new(app_handle, &window_context, req.purpose);
@@ -145,7 +145,7 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
updated_at: Utc::now().naive_utc(), // TODO: Add reloaded_at field to use instead
..plugin
};
upsert_plugin(&window, new_plugin, &UpdateSource::Plugin).await.unwrap();
upsert_plugin(app_handle, new_plugin, &UpdateSource::Plugin).await.unwrap();
}
let toast_event = plugin_handle.build_event_to_send(
&WindowContext::from_window(&window),
@@ -177,7 +177,7 @@ pub(crate) async fn handle_plugin_event<R: Runtime>(
HttpResponse::new()
} else {
create_default_http_response(
&window,
app_handle,
http_request.id.as_str(),
&UpdateSource::Plugin,
)