mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-26 03:11:28 +01:00
Start on plugin ctx API (#64)
This commit is contained in:
66
src-tauri/Cargo.lock
generated
66
src-tauri/Cargo.lock
generated
@@ -2052,30 +2052,6 @@ dependencies = [
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "grpc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dunce",
|
||||
"hyper 0.14.30",
|
||||
"hyper-rustls 0.24.2",
|
||||
"log",
|
||||
"md5",
|
||||
"prost 0.12.6",
|
||||
"prost-reflect",
|
||||
"prost-types 0.12.6",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-plugin-shell",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tonic 0.10.2",
|
||||
"tonic-reflection",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gtk"
|
||||
version = "0.18.1"
|
||||
@@ -6125,13 +6101,6 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "templates"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tendril"
|
||||
version = "0.4.3"
|
||||
@@ -7573,7 +7542,6 @@ dependencies = [
|
||||
"chrono",
|
||||
"cocoa",
|
||||
"datetime",
|
||||
"grpc",
|
||||
"hex_color",
|
||||
"http 1.1.0",
|
||||
"log",
|
||||
@@ -7597,13 +7565,38 @@ dependencies = [
|
||||
"tauri-plugin-shell",
|
||||
"tauri-plugin-updater",
|
||||
"tauri-plugin-window-state",
|
||||
"templates",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"uuid",
|
||||
"yaak_grpc",
|
||||
"yaak_models",
|
||||
"yaak_plugin_runtime",
|
||||
"yaak_templates",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaak_grpc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dunce",
|
||||
"hyper 0.14.30",
|
||||
"hyper-rustls 0.24.2",
|
||||
"log",
|
||||
"md5",
|
||||
"prost 0.12.6",
|
||||
"prost-reflect",
|
||||
"prost-types 0.12.6",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-plugin-shell",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tonic 0.10.2",
|
||||
"tonic-reflection",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7651,6 +7644,13 @@ dependencies = [
|
||||
"yaak_models",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaak_templates"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus"
|
||||
version = "4.0.1"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[workspace]
|
||||
members = ["grpc", "templates", "yaak_plugin_runtime", "yaak_models"]
|
||||
members = ["yaak_grpc", "yaak_templates", "yaak_plugin_runtime", "yaak_models"]
|
||||
|
||||
|
||||
[package]
|
||||
@@ -26,8 +26,8 @@ cocoa = "0.25.0"
|
||||
openssl-sys = { version = "0.9", features = ["vendored"] } # For Ubuntu installation to work
|
||||
|
||||
[dependencies]
|
||||
grpc = { path = "./grpc" }
|
||||
templates = { path = "./templates" }
|
||||
yaak_grpc = { path = "yaak_grpc" }
|
||||
yaak_templates = { path = "yaak_templates" }
|
||||
yaak_plugin_runtime = { path = "yaak_plugin_runtime" }
|
||||
anyhow = "1.0.86"
|
||||
base64 = "0.22.0"
|
||||
@@ -43,7 +43,7 @@ reqwest_cookie_store = "0.8.0"
|
||||
serde = { version = "1.0.198", features = ["derive"] }
|
||||
serde_json = { version = "1.0.116", features = ["raw_value"] }
|
||||
serde_yaml = "0.9.34"
|
||||
tauri = { workspace = true }
|
||||
tauri = { workspace = true, features = ["unstable"] }
|
||||
tauri-plugin-shell = { workspace = true }
|
||||
tauri-plugin-clipboard-manager = "2.0.0-rc.0"
|
||||
tauri-plugin-dialog = "2.0.0-rc.0"
|
||||
|
||||
2
src-tauri/migrations/20240814013812_fix-env-model.sql
Normal file
2
src-tauri/migrations/20240814013812_fix-env-model.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE environments DROP COLUMN model;
|
||||
ALTER TABLE environments ADD COLUMN model TEXT DEFAULT 'environment';
|
||||
@@ -3,9 +3,11 @@ use std::fmt::Display;
|
||||
use log::{debug, info};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, Value};
|
||||
use tauri::{AppHandle, Manager};
|
||||
use tauri::{Manager, Runtime, WebviewWindow};
|
||||
|
||||
use yaak_models::queries::{generate_id, get_key_value_int, get_key_value_string, set_key_value_int, set_key_value_string};
|
||||
use yaak_models::queries::{
|
||||
generate_id, get_key_value_int, get_key_value_string, set_key_value_int, set_key_value_string,
|
||||
};
|
||||
|
||||
use crate::is_dev;
|
||||
|
||||
@@ -36,7 +38,7 @@ pub enum AnalyticsResource {
|
||||
|
||||
impl AnalyticsResource {
|
||||
pub fn from_str(s: &str) -> serde_json::Result<AnalyticsResource> {
|
||||
return serde_json::from_str(format!("\"{s}\"").as_str());
|
||||
serde_json::from_str(format!("\"{s}\"").as_str())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +76,7 @@ pub enum AnalyticsAction {
|
||||
|
||||
impl AnalyticsAction {
|
||||
pub fn from_str(s: &str) -> serde_json::Result<AnalyticsAction> {
|
||||
return serde_json::from_str(format!("\"{s}\"").as_str());
|
||||
serde_json::from_str(format!("\"{s}\"").as_str())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,19 +98,18 @@ pub struct LaunchEventInfo {
|
||||
pub num_launches: i32,
|
||||
}
|
||||
|
||||
pub async fn track_launch_event(app: &AppHandle) -> LaunchEventInfo {
|
||||
pub async fn track_launch_event<R: Runtime>(w: &WebviewWindow<R>) -> LaunchEventInfo {
|
||||
let last_tracked_version_key = "last_tracked_version";
|
||||
|
||||
let mut info = LaunchEventInfo::default();
|
||||
|
||||
info.num_launches = get_num_launches(app).await + 1;
|
||||
info.previous_version =
|
||||
get_key_value_string(app, NAMESPACE, last_tracked_version_key, "").await;
|
||||
info.current_version = app.package_info().version.to_string();
|
||||
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();
|
||||
|
||||
if info.previous_version.is_empty() {
|
||||
track_event(
|
||||
app,
|
||||
w,
|
||||
AnalyticsResource::App,
|
||||
AnalyticsAction::LaunchFirst,
|
||||
None,
|
||||
@@ -118,7 +119,7 @@ pub async fn track_launch_event(app: &AppHandle) -> LaunchEventInfo {
|
||||
info.launched_after_update = info.current_version != info.previous_version;
|
||||
if info.launched_after_update {
|
||||
track_event(
|
||||
app,
|
||||
w,
|
||||
AnalyticsResource::App,
|
||||
AnalyticsAction::LaunchUpdate,
|
||||
Some(json!({ NUM_LAUNCHES_KEY: info.num_launches })),
|
||||
@@ -129,7 +130,7 @@ pub async fn track_launch_event(app: &AppHandle) -> LaunchEventInfo {
|
||||
|
||||
// Track a launch event in all cases
|
||||
track_event(
|
||||
app,
|
||||
w,
|
||||
AnalyticsResource::App,
|
||||
AnalyticsAction::Launch,
|
||||
Some(json!({ NUM_LAUNCHES_KEY: info.num_launches })),
|
||||
@@ -139,27 +140,27 @@ pub async fn track_launch_event(app: &AppHandle) -> LaunchEventInfo {
|
||||
// Update key values
|
||||
|
||||
set_key_value_string(
|
||||
app,
|
||||
w,
|
||||
NAMESPACE,
|
||||
last_tracked_version_key,
|
||||
info.current_version.as_str(),
|
||||
)
|
||||
.await;
|
||||
set_key_value_int(app, NAMESPACE, NUM_LAUNCHES_KEY, info.num_launches).await;
|
||||
set_key_value_int(w, NAMESPACE, NUM_LAUNCHES_KEY, info.num_launches).await;
|
||||
|
||||
info
|
||||
}
|
||||
|
||||
pub async fn track_event(
|
||||
app_handle: &AppHandle,
|
||||
pub async fn track_event<R: Runtime>(
|
||||
w: &WebviewWindow<R>,
|
||||
resource: AnalyticsResource,
|
||||
action: AnalyticsAction,
|
||||
attributes: Option<Value>,
|
||||
) {
|
||||
let id = get_id(app_handle).await;
|
||||
let id = get_id(w).await;
|
||||
let event = format!("{}.{}", resource, action);
|
||||
let attributes_json = attributes.unwrap_or("{}".to_string().into()).to_string();
|
||||
let info = app_handle.package_info();
|
||||
let info = w.app_handle().package_info();
|
||||
let tz = datetime::sys_timezone().unwrap_or("unknown".to_string());
|
||||
let site = match is_dev() {
|
||||
true => "site_TkHWjoXwZPq3HfhERb",
|
||||
@@ -177,7 +178,7 @@ pub async fn track_event(
|
||||
("v", info.version.clone().to_string()),
|
||||
("os", get_os().to_string()),
|
||||
("tz", tz),
|
||||
("xy", get_window_size(app_handle)),
|
||||
("xy", get_window_size(w)),
|
||||
];
|
||||
let req = reqwest::Client::builder()
|
||||
.build()
|
||||
@@ -208,13 +209,8 @@ fn get_os() -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_window_size(app_handle: &AppHandle) -> String {
|
||||
let window = match app_handle.webview_windows().into_values().next() {
|
||||
Some(w) => w,
|
||||
None => return "unknown".to_string(),
|
||||
};
|
||||
|
||||
let current_monitor = match window.current_monitor() {
|
||||
fn get_window_size<R: Runtime>(w: &WebviewWindow<R>) -> String {
|
||||
let current_monitor = match w.current_monitor() {
|
||||
Ok(Some(m)) => m,
|
||||
_ => return "unknown".to_string(),
|
||||
};
|
||||
@@ -231,17 +227,17 @@ fn get_window_size(app_handle: &AppHandle) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
async fn get_id(app_handle: &AppHandle) -> String {
|
||||
let id = get_key_value_string(app_handle, "analytics", "id", "").await;
|
||||
async fn get_id<R: Runtime>(w: &WebviewWindow<R>) -> String {
|
||||
let id = get_key_value_string(w, "analytics", "id", "").await;
|
||||
if id.is_empty() {
|
||||
let new_id = generate_id();
|
||||
set_key_value_string(app_handle, "analytics", "id", new_id.as_str()).await;
|
||||
set_key_value_string(w, "analytics", "id", new_id.as_str()).await;
|
||||
new_id
|
||||
} else {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_num_launches(app: &AppHandle) -> i32 {
|
||||
get_key_value_int(app, NAMESPACE, NUM_LAUNCHES_KEY, 0).await
|
||||
pub async fn get_num_launches<R: Runtime>(w: &WebviewWindow<R>) -> i32 {
|
||||
get_key_value_int(w, NAMESPACE, NUM_LAUNCHES_KEY, 0).await
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||
|
||||
use KeyAndValueRef::{Ascii, Binary};
|
||||
|
||||
use grpc::{KeyAndValueRef, MetadataMap};
|
||||
use yaak_grpc::{KeyAndValueRef, MetadataMap};
|
||||
|
||||
pub fn metadata_to_map(metadata: MetadataMap) -> HashMap<String, String> {
|
||||
let mut entries = HashMap::new();
|
||||
|
||||
@@ -11,24 +11,25 @@ use crate::{render, response_err};
|
||||
use base64::Engine;
|
||||
use http::header::{ACCEPT, USER_AGENT};
|
||||
use http::{HeaderMap, HeaderName, HeaderValue};
|
||||
use log::{error, info, warn};
|
||||
use log::{error, warn};
|
||||
use mime_guess::Mime;
|
||||
use reqwest::redirect::Policy;
|
||||
use reqwest::Method;
|
||||
use reqwest::{multipart, Url};
|
||||
use tauri::{Manager, WebviewWindow};
|
||||
use tauri::{Manager, Runtime, WebviewWindow};
|
||||
use tokio::sync::oneshot;
|
||||
use tokio::sync::watch::Receiver;
|
||||
use yaak_models::models::{Cookie, CookieJar, Environment, HttpRequest, HttpResponse, HttpResponseHeader};
|
||||
use yaak_models::models::{
|
||||
Cookie, CookieJar, Environment, HttpRequest, HttpResponse, HttpResponseHeader,
|
||||
};
|
||||
use yaak_models::queries::{get_workspace, update_response_if_id, upsert_cookie_jar};
|
||||
|
||||
pub async fn send_http_request(
|
||||
window: &WebviewWindow,
|
||||
pub async fn send_http_request<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
request: HttpRequest,
|
||||
response: &HttpResponse,
|
||||
environment: Option<Environment>,
|
||||
cookie_jar: Option<CookieJar>,
|
||||
download_path: Option<PathBuf>,
|
||||
cancel_rx: &mut Receiver<bool>,
|
||||
) -> Result<HttpResponse, String> {
|
||||
let environment_ref = environment.as_ref();
|
||||
@@ -442,16 +443,6 @@ pub async fn send_http_request(
|
||||
.await
|
||||
.expect("Failed to update response");
|
||||
|
||||
// Copy response to the download path, if specified
|
||||
match (download_path, response.body_path.clone()) {
|
||||
(Some(dl_path), Some(body_path)) => {
|
||||
info!("Downloading response body to {}", dl_path.display());
|
||||
fs::copy(body_path, dl_path)
|
||||
.expect("Failed to copy file for response download");
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
// Add cookie store if specified
|
||||
if let Some((cookie_store, mut cookie_jar)) = maybe_cookie_manager {
|
||||
// let cookies = response_headers.get_all(SET_COOKIE).iter().map(|h| {
|
||||
@@ -466,7 +457,8 @@ pub async fn send_http_request(
|
||||
.unwrap()
|
||||
.iter_any()
|
||||
.map(|c| {
|
||||
let json_cookie = serde_json::to_value(&c).expect("Failed to serialize cookie");
|
||||
let json_cookie =
|
||||
serde_json::to_value(&c).expect("Failed to serialize cookie");
|
||||
serde_json::from_value(json_cookie).expect("Failed to deserialize cookie")
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -16,17 +16,17 @@ use fern::colors::ColoredLevelConfig;
|
||||
use log::{debug, error, info, warn};
|
||||
use rand::random;
|
||||
use serde_json::{json, Value};
|
||||
use tauri::Listener;
|
||||
#[cfg(target_os = "macos")]
|
||||
use tauri::TitleBarStyle;
|
||||
use tauri::{AppHandle, Emitter, LogicalSize, RunEvent, State, WebviewUrl, WebviewWindow};
|
||||
use tauri::{Listener, Runtime};
|
||||
use tauri::{Manager, WindowEvent};
|
||||
use tauri_plugin_log::{fern, Target, TargetKind};
|
||||
use tauri_plugin_shell::ShellExt;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::sync::{watch, Mutex};
|
||||
|
||||
use ::grpc::manager::{DynamicMessage, GrpcHandle};
|
||||
use ::grpc::{deserialize_message, serialize_message, Code, ServiceDefinition};
|
||||
use yaak_grpc::manager::{DynamicMessage, GrpcHandle};
|
||||
use yaak_grpc::{deserialize_message, serialize_message, Code, ServiceDefinition};
|
||||
use yaak_plugin_runtime::manager::PluginManager;
|
||||
|
||||
use crate::analytics::{AnalyticsAction, AnalyticsResource};
|
||||
@@ -42,7 +42,7 @@ use yaak_models::models::{
|
||||
GrpcRequest, HttpRequest, HttpResponse, KeyValue, ModelType, Settings, Workspace,
|
||||
};
|
||||
use yaak_models::queries::{
|
||||
cancel_pending_grpc_connections, cancel_pending_responses, create_http_response,
|
||||
cancel_pending_grpc_connections, cancel_pending_responses, create_default_http_response,
|
||||
delete_all_grpc_connections, delete_all_http_responses, delete_cookie_jar, delete_environment,
|
||||
delete_folder, delete_grpc_connection, delete_grpc_request, delete_http_request,
|
||||
delete_http_response, delete_workspace, duplicate_grpc_request, duplicate_http_request,
|
||||
@@ -54,7 +54,10 @@ use yaak_models::queries::{
|
||||
upsert_cookie_jar, upsert_environment, upsert_folder, upsert_grpc_connection,
|
||||
upsert_grpc_event, upsert_grpc_request, upsert_http_request, upsert_workspace,
|
||||
};
|
||||
use yaak_plugin_runtime::events::FilterResponse;
|
||||
use yaak_plugin_runtime::events::{
|
||||
FilterResponse, GetHttpRequestByIdResponse, InternalEvent, InternalEventPayload,
|
||||
SendHttpRequestResponse,
|
||||
};
|
||||
|
||||
mod analytics;
|
||||
mod export_resources;
|
||||
@@ -96,11 +99,15 @@ async fn cmd_metadata(app_handle: AppHandle) -> Result<AppMetaData, ()> {
|
||||
|
||||
#[tauri::command]
|
||||
async fn cmd_dismiss_notification(
|
||||
app: AppHandle,
|
||||
window: WebviewWindow,
|
||||
notification_id: &str,
|
||||
yaak_notifier: State<'_, Mutex<YaakNotifier>>,
|
||||
) -> Result<(), String> {
|
||||
yaak_notifier.lock().await.seen(&app, notification_id).await
|
||||
yaak_notifier
|
||||
.lock()
|
||||
.await
|
||||
.seen(&window, notification_id)
|
||||
.await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -135,17 +142,21 @@ async fn cmd_grpc_go(
|
||||
request_id: &str,
|
||||
environment_id: Option<&str>,
|
||||
proto_files: Vec<String>,
|
||||
w: WebviewWindow,
|
||||
window: WebviewWindow,
|
||||
grpc_handle: State<'_, Mutex<GrpcHandle>>,
|
||||
) -> Result<String, String> {
|
||||
let req = get_grpc_request(&w, request_id)
|
||||
let req = get_grpc_request(&window, request_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let environment = match environment_id {
|
||||
Some(id) => Some(get_environment(&w, id).await.map_err(|e| e.to_string())?),
|
||||
Some(id) => Some(
|
||||
get_environment(&window, id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?,
|
||||
),
|
||||
None => None,
|
||||
};
|
||||
let workspace = get_workspace(&w, &req.workspace_id)
|
||||
let workspace = get_workspace(&window, &req.workspace_id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let mut metadata = HashMap::new();
|
||||
@@ -199,7 +210,7 @@ async fn cmd_grpc_go(
|
||||
let conn = {
|
||||
let req = req.clone();
|
||||
upsert_grpc_connection(
|
||||
&w,
|
||||
&window,
|
||||
&GrpcConnection {
|
||||
workspace_id: req.workspace_id,
|
||||
request_id: req.id,
|
||||
@@ -256,7 +267,7 @@ async fn cmd_grpc_go(
|
||||
Ok(c) => c,
|
||||
Err(err) => {
|
||||
upsert_grpc_connection(
|
||||
&w,
|
||||
&window,
|
||||
&GrpcConnection {
|
||||
elapsed: start.elapsed().as_millis() as i32,
|
||||
error: Some(err.clone()),
|
||||
@@ -282,7 +293,7 @@ async fn cmd_grpc_go(
|
||||
|
||||
let cb = {
|
||||
let cancelled_rx = cancelled_rx.clone();
|
||||
let w = w.clone();
|
||||
let w = window.clone();
|
||||
let base_msg = base_msg.clone();
|
||||
let method_desc = method_desc.clone();
|
||||
let vars = vars.clone();
|
||||
@@ -355,10 +366,10 @@ async fn cmd_grpc_go(
|
||||
}
|
||||
}
|
||||
};
|
||||
let event_handler = w.listen_any(format!("grpc_client_msg_{}", conn.id).as_str(), cb);
|
||||
let event_handler = window.listen_any(format!("grpc_client_msg_{}", conn.id).as_str(), cb);
|
||||
|
||||
let grpc_listen = {
|
||||
let w = w.clone();
|
||||
let w = window.clone();
|
||||
let base_event = base_msg.clone();
|
||||
let req = req.clone();
|
||||
let vars = vars.clone();
|
||||
@@ -603,7 +614,7 @@ async fn cmd_grpc_go(
|
||||
{
|
||||
let conn_id = conn_id.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let w = w.clone();
|
||||
let w = window.clone();
|
||||
tokio::select! {
|
||||
_ = grpc_listen => {
|
||||
let events = list_grpc_events(&w, &conn_id)
|
||||
@@ -691,7 +702,6 @@ async fn cmd_send_ephemeral_request(
|
||||
&response,
|
||||
environment,
|
||||
cookie_jar,
|
||||
None,
|
||||
&mut cancel_rx,
|
||||
)
|
||||
.await
|
||||
@@ -701,7 +711,7 @@ async fn cmd_send_ephemeral_request(
|
||||
async fn cmd_filter_response(
|
||||
w: WebviewWindow,
|
||||
response_id: &str,
|
||||
plugin_manager: State<'_, Mutex<PluginManager>>,
|
||||
plugin_manager: State<'_, PluginManager>,
|
||||
filter: &str,
|
||||
) -> Result<FilterResponse, String> {
|
||||
let response = get_http_response(&w, response_id)
|
||||
@@ -724,8 +734,6 @@ async fn cmd_filter_response(
|
||||
|
||||
// TODO: Have plugins register their own content type (regex?)
|
||||
plugin_manager
|
||||
.lock()
|
||||
.await
|
||||
.run_filter(filter, &body, &content_type)
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
@@ -734,15 +742,13 @@ async fn cmd_filter_response(
|
||||
#[tauri::command]
|
||||
async fn cmd_import_data(
|
||||
w: WebviewWindow,
|
||||
plugin_manager: State<'_, Mutex<PluginManager>>,
|
||||
plugin_manager: State<'_, PluginManager>,
|
||||
file_path: &str,
|
||||
) -> Result<WorkspaceExportResources, String> {
|
||||
let file =
|
||||
read_to_string(file_path).unwrap_or_else(|_| panic!("Unable to read file {}", file_path));
|
||||
let file_contents = file.as_str();
|
||||
let (import_result, plugin_name) = plugin_manager
|
||||
.lock()
|
||||
.await
|
||||
.run_import(file_contents)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
@@ -853,7 +859,7 @@ async fn cmd_import_data(
|
||||
);
|
||||
|
||||
analytics::track_event(
|
||||
&w.app_handle(),
|
||||
&w,
|
||||
AnalyticsResource::App,
|
||||
AnalyticsAction::Import,
|
||||
Some(json!({ "plugin": plugin_name })),
|
||||
@@ -867,7 +873,7 @@ async fn cmd_import_data(
|
||||
async fn cmd_request_to_curl(
|
||||
app: AppHandle,
|
||||
request_id: &str,
|
||||
plugin_manager: State<'_, Mutex<PluginManager>>,
|
||||
plugin_manager: State<'_, PluginManager>,
|
||||
environment_id: Option<&str>,
|
||||
) -> Result<String, String> {
|
||||
let request = get_http_request(&app, request_id)
|
||||
@@ -883,8 +889,6 @@ async fn cmd_request_to_curl(
|
||||
let rendered = render_request(&request, &workspace, environment.as_ref());
|
||||
|
||||
let import_response = plugin_manager
|
||||
.lock()
|
||||
.await
|
||||
.run_export_curl(&rendered)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
@@ -894,19 +898,19 @@ async fn cmd_request_to_curl(
|
||||
#[tauri::command]
|
||||
async fn cmd_curl_to_request(
|
||||
command: &str,
|
||||
plugin_manager: State<'_, Mutex<PluginManager>>,
|
||||
plugin_manager: State<'_, PluginManager>,
|
||||
workspace_id: &str,
|
||||
w: WebviewWindow,
|
||||
) -> Result<HttpRequest, String> {
|
||||
let (import_result, plugin_name) = plugin_manager
|
||||
.lock()
|
||||
.await
|
||||
.run_import(command)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let (import_result, plugin_name) = {
|
||||
plugin_manager
|
||||
.run_import(command)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
};
|
||||
|
||||
analytics::track_event(
|
||||
&w.app_handle(),
|
||||
&w,
|
||||
AnalyticsResource::App,
|
||||
AnalyticsAction::Import,
|
||||
Some(json!({ "plugin": plugin_name })),
|
||||
@@ -947,7 +951,7 @@ async fn cmd_export_data(
|
||||
f.sync_all().expect("Failed to sync");
|
||||
|
||||
analytics::track_event(
|
||||
&window.app_handle(),
|
||||
&window,
|
||||
AnalyticsResource::App,
|
||||
AnalyticsAction::Export,
|
||||
None,
|
||||
@@ -984,7 +988,6 @@ async fn cmd_send_http_request(
|
||||
window: WebviewWindow,
|
||||
environment_id: Option<&str>,
|
||||
cookie_jar_id: Option<&str>,
|
||||
download_dir: Option<&str>,
|
||||
// NOTE: We receive the entire request because to account for the race
|
||||
// condition where the user may have just edited a field before sending
|
||||
// that has not yet been saved in the DB.
|
||||
@@ -1010,28 +1013,9 @@ async fn cmd_send_http_request(
|
||||
None => None,
|
||||
};
|
||||
|
||||
let response = create_http_response(
|
||||
&window,
|
||||
&request.id,
|
||||
0,
|
||||
0,
|
||||
"",
|
||||
0,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
vec![],
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create response");
|
||||
|
||||
let download_path = if let Some(p) = download_dir {
|
||||
Some(std::path::Path::new(p).to_path_buf())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let response = create_default_http_response(&window, &request.id)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let (cancel_tx, mut cancel_rx) = tokio::sync::watch::channel(false);
|
||||
window.listen_any(
|
||||
@@ -1047,16 +1031,15 @@ async fn cmd_send_http_request(
|
||||
&response,
|
||||
environment,
|
||||
cookie_jar,
|
||||
download_path,
|
||||
&mut cancel_rx,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn response_err(
|
||||
async fn response_err<R: Runtime>(
|
||||
response: &HttpResponse,
|
||||
error: String,
|
||||
w: &WebviewWindow,
|
||||
w: &WebviewWindow<R>,
|
||||
) -> Result<HttpResponse, String> {
|
||||
warn!("Failed to send request: {}", error);
|
||||
let mut response = response.clone();
|
||||
@@ -1080,7 +1063,7 @@ async fn cmd_track_event(
|
||||
AnalyticsAction::from_str(action),
|
||||
) {
|
||||
(Ok(resource), Ok(action)) => {
|
||||
analytics::track_event(&window.app_handle(), resource, action, attributes).await;
|
||||
analytics::track_event(&window, resource, action, attributes).await;
|
||||
}
|
||||
(r, a) => {
|
||||
error!(
|
||||
@@ -1635,9 +1618,8 @@ pub fn run() {
|
||||
let grpc_handle = GrpcHandle::new(&app.app_handle());
|
||||
app.manage(Mutex::new(grpc_handle));
|
||||
|
||||
// Add plugin manager
|
||||
let grpc_handle = GrpcHandle::new(&app.app_handle());
|
||||
app.manage(Mutex::new(grpc_handle));
|
||||
let app_handle = app.app_handle().clone();
|
||||
monitor_plugin_events(&app_handle);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
@@ -1715,10 +1697,9 @@ pub fn run() {
|
||||
.run(|app_handle, event| {
|
||||
match event {
|
||||
RunEvent::Ready => {
|
||||
create_window(app_handle, "/");
|
||||
let h = app_handle.clone();
|
||||
let w = create_window(app_handle, "/");
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let info = analytics::track_launch_event(&h).await;
|
||||
let info = analytics::track_launch_event(&w).await;
|
||||
debug!("Launched Yaak {:?}", info);
|
||||
});
|
||||
|
||||
@@ -1743,10 +1724,12 @@ pub fn run() {
|
||||
|
||||
let h = app_handle.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let windows = h.webview_windows();
|
||||
let w = windows.values().next().unwrap();
|
||||
tokio::time::sleep(Duration::from_millis(4000)).await;
|
||||
let val: State<'_, Mutex<YaakNotifier>> = h.state();
|
||||
let val: State<'_, Mutex<YaakNotifier>> = w.state();
|
||||
let mut n = val.lock().await;
|
||||
if let Err(e) = n.check(&h).await {
|
||||
if let Err(e) = n.check(&w).await {
|
||||
warn!("Failed to check for notifications {}", e)
|
||||
}
|
||||
});
|
||||
@@ -1905,3 +1888,86 @@ fn safe_uri(endpoint: &str) -> String {
|
||||
format!("http://{}", endpoint)
|
||||
}
|
||||
}
|
||||
|
||||
fn monitor_plugin_events<R: Runtime>(app_handle: &AppHandle<R>) {
|
||||
let app_handle = app_handle.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let plugin_manager: State<'_, PluginManager> = app_handle.state();
|
||||
let (_rx_id, mut rx) = plugin_manager.subscribe().await;
|
||||
|
||||
let app_handle = app_handle.clone();
|
||||
while let Some(event) = rx.recv().await {
|
||||
let payload = match handle_plugin_event(&app_handle, &event).await {
|
||||
Some(e) => e,
|
||||
None => continue,
|
||||
};
|
||||
if let Err(e) = plugin_manager.reply(&event, &payload).await {
|
||||
warn!("Failed to reply to plugin manager: {}", e)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn handle_plugin_event<R: Runtime>(
|
||||
app_handle: &AppHandle<R>,
|
||||
event: &InternalEvent,
|
||||
) -> Option<InternalEventPayload> {
|
||||
let event = match event.clone().payload {
|
||||
InternalEventPayload::GetHttpRequestByIdRequest(req) => {
|
||||
let http_request = get_http_request(app_handle, req.id.as_str()).await.ok();
|
||||
InternalEventPayload::GetHttpRequestByIdResponse(GetHttpRequestByIdResponse {
|
||||
http_request,
|
||||
})
|
||||
}
|
||||
InternalEventPayload::SendHttpRequestRequest(req) => {
|
||||
let webview_windows = app_handle.get_focused_window()?.webview_windows();
|
||||
let w = match webview_windows.iter().next() {
|
||||
None => return None,
|
||||
Some((_, w)) => w,
|
||||
};
|
||||
|
||||
let url = w.url().unwrap();
|
||||
let mut query_pairs = url.query_pairs();
|
||||
|
||||
let cookie_jar_id = query_pairs
|
||||
.find(|(k, _v)| k == "cookie_jar_id")
|
||||
.map(|(_k, v)| v.to_string());
|
||||
let cookie_jar = match cookie_jar_id {
|
||||
None => None,
|
||||
Some(id) => get_cookie_jar(w, id.as_str()).await.ok(),
|
||||
};
|
||||
|
||||
let environment_id = query_pairs
|
||||
.find(|(k, _v)| k == "environment_id")
|
||||
.map(|(_k, v)| v.to_string());
|
||||
let environment = match environment_id {
|
||||
None => None,
|
||||
Some(id) => get_environment(w, id.as_str()).await.ok(),
|
||||
};
|
||||
|
||||
let resp = create_default_http_response(w, req.http_request.id.as_str())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let result = send_http_request(
|
||||
&w,
|
||||
req.http_request,
|
||||
&resp,
|
||||
environment,
|
||||
cookie_jar,
|
||||
&mut watch::channel(false).1, // No-op cancel channel
|
||||
)
|
||||
.await;
|
||||
|
||||
let http_response = match result {
|
||||
Ok(r) => r,
|
||||
Err(_e) => return None,
|
||||
};
|
||||
|
||||
InternalEventPayload::SendHttpRequestResponse(SendHttpRequestResponse { http_response })
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(event)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use chrono::{DateTime, Duration, Utc};
|
||||
use log::debug;
|
||||
use reqwest::Method;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::{AppHandle, Emitter};
|
||||
use tauri::{Emitter, Manager, Runtime, WebviewWindow};
|
||||
use yaak_models::queries::{get_key_value_raw, set_key_value_raw};
|
||||
|
||||
// Check for updates every hour
|
||||
@@ -42,16 +42,16 @@ impl YaakNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn seen(&mut self, app: &AppHandle, id: &str) -> Result<(), String> {
|
||||
let mut seen = get_kv(app).await?;
|
||||
pub async fn seen<R: Runtime>(&mut self, w: &WebviewWindow<R>, id: &str) -> Result<(), String> {
|
||||
let mut seen = get_kv(w).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(app, KV_NAMESPACE, KV_KEY, seen_json.as_str()).await;
|
||||
set_key_value_raw(w, KV_NAMESPACE, KV_KEY, seen_json.as_str()).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn check(&mut self, app: &AppHandle) -> Result<(), String> {
|
||||
pub async fn check<R: Runtime>(&mut self, w: &WebviewWindow<R>) -> Result<(), String> {
|
||||
let ignore_check = self.last_check.elapsed().unwrap().as_secs() < MAX_UPDATE_CHECK_SECONDS;
|
||||
|
||||
if ignore_check {
|
||||
@@ -60,8 +60,8 @@ impl YaakNotifier {
|
||||
|
||||
self.last_check = SystemTime::now();
|
||||
|
||||
let num_launches = get_num_launches(app).await;
|
||||
let info = app.package_info().clone();
|
||||
let num_launches = get_num_launches(w).await;
|
||||
let info = w.app_handle().package_info().clone();
|
||||
let req = reqwest::Client::default()
|
||||
.request(Method::GET, "https://notify.yaak.app/notifications")
|
||||
.query(&[
|
||||
@@ -80,21 +80,21 @@ impl YaakNotifier {
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let age = notification.timestamp.signed_duration_since(Utc::now());
|
||||
let seen = get_kv(app).await?;
|
||||
let seen = get_kv(w).await?;
|
||||
if seen.contains(¬ification.id) || (age > Duration::days(2)) {
|
||||
debug!("Already seen notification {}", notification.id);
|
||||
return Ok(());
|
||||
}
|
||||
debug!("Got notification {:?}", notification);
|
||||
|
||||
let _ = app.emit("notification", notification.clone());
|
||||
let _ = w.emit("notification", notification.clone());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_kv(app: &AppHandle) -> Result<Vec<String>, String> {
|
||||
match get_key_value_raw(app, "notifications", "seen").await {
|
||||
async fn get_kv<R: Runtime>(w: &WebviewWindow<R>) -> Result<Vec<String>, String> {
|
||||
match get_key_value_raw(w, "notifications", "seen").await {
|
||||
None => Ok(Vec::new()),
|
||||
Some(v) => serde_json::from_str(&v.value).map_err(|e| e.to_string()),
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
use serde_json::Value;
|
||||
use crate::template_fns::timestamp;
|
||||
use templates::parse_and_render;
|
||||
use yaak_templates::parse_and_render;
|
||||
use yaak_models::models::{
|
||||
Environment, EnvironmentVariable, HttpRequest, HttpRequestHeader, HttpUrlParameter, Workspace,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "grpc"
|
||||
name = "yaak_grpc"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
@@ -15,10 +15,10 @@ use sea_query::Keyword::CurrentTimestamp;
|
||||
use sea_query::{Cond, Expr, OnConflict, Order, Query, SqliteQueryBuilder};
|
||||
use sea_query_rusqlite::RusqliteBinder;
|
||||
use serde::Serialize;
|
||||
use tauri::{AppHandle, Emitter, Manager, WebviewWindow, Wry};
|
||||
use tauri::{AppHandle, Emitter, Manager, Runtime, WebviewWindow};
|
||||
|
||||
pub async fn set_key_value_string(
|
||||
mgr: &impl Manager<Wry>,
|
||||
pub async fn set_key_value_string<R: Runtime>(
|
||||
mgr: &WebviewWindow<R>,
|
||||
namespace: &str,
|
||||
key: &str,
|
||||
value: &str,
|
||||
@@ -27,8 +27,8 @@ pub async fn set_key_value_string(
|
||||
set_key_value_raw(mgr, namespace, key, &encoded.unwrap()).await
|
||||
}
|
||||
|
||||
pub async fn set_key_value_int(
|
||||
mgr: &impl Manager<Wry>,
|
||||
pub async fn set_key_value_int<R: Runtime>(
|
||||
mgr: &WebviewWindow<R>,
|
||||
namespace: &str,
|
||||
key: &str,
|
||||
value: i32,
|
||||
@@ -37,8 +37,8 @@ pub async fn set_key_value_int(
|
||||
set_key_value_raw(mgr, namespace, key, &encoded.unwrap()).await
|
||||
}
|
||||
|
||||
pub async fn get_key_value_string(
|
||||
mgr: &impl Manager<Wry>,
|
||||
pub async fn get_key_value_string<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
namespace: &str,
|
||||
key: &str,
|
||||
default: &str,
|
||||
@@ -58,8 +58,8 @@ pub async fn get_key_value_string(
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_key_value_int(
|
||||
mgr: &impl Manager<Wry>,
|
||||
pub async fn get_key_value_int<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
namespace: &str,
|
||||
key: &str,
|
||||
default: i32,
|
||||
@@ -79,15 +79,15 @@ pub async fn get_key_value_int(
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_key_value_raw(
|
||||
mgr: &impl Manager<Wry>,
|
||||
pub async fn set_key_value_raw<R: Runtime>(
|
||||
w: &WebviewWindow<R>,
|
||||
namespace: &str,
|
||||
key: &str,
|
||||
value: &str,
|
||||
) -> (KeyValue, bool) {
|
||||
let existing = get_key_value_raw(mgr, namespace, key).await;
|
||||
let existing = get_key_value_raw(w, namespace, key).await;
|
||||
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let dbm = &*w.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
let (sql, params) = Query::insert()
|
||||
.into_table(KeyValueIden::Table)
|
||||
@@ -119,11 +119,11 @@ pub async fn set_key_value_raw(
|
||||
let kv = stmt
|
||||
.query_row(&*params.as_params(), |row| row.try_into())
|
||||
.expect("Failed to upsert KeyValue");
|
||||
(kv, existing.is_none())
|
||||
(emit_upserted_model(w, kv), existing.is_none())
|
||||
}
|
||||
|
||||
pub async fn get_key_value_raw(
|
||||
mgr: &impl Manager<Wry>,
|
||||
pub async fn get_key_value_raw<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
namespace: &str,
|
||||
key: &str,
|
||||
) -> Option<KeyValue> {
|
||||
@@ -143,7 +143,7 @@ pub async fn get_key_value_raw(
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub async fn list_workspaces(mgr: &impl Manager<Wry>) -> Result<Vec<Workspace>> {
|
||||
pub async fn list_workspaces<R: Runtime>(mgr: &impl Manager<R>) -> Result<Vec<Workspace>> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
let (sql, params) = Query::select()
|
||||
@@ -155,7 +155,7 @@ pub async fn list_workspaces(mgr: &impl Manager<Wry>) -> Result<Vec<Workspace>>
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
}
|
||||
|
||||
pub async fn get_workspace(mgr: &impl Manager<Wry>, id: &str) -> Result<Workspace> {
|
||||
pub async fn get_workspace<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<Workspace> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
let (sql, params) = Query::select()
|
||||
@@ -167,7 +167,10 @@ pub async fn get_workspace(mgr: &impl Manager<Wry>, id: &str) -> Result<Workspac
|
||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||
}
|
||||
|
||||
pub async fn upsert_workspace(window: &WebviewWindow, workspace: Workspace) -> Result<Workspace> {
|
||||
pub async fn upsert_workspace<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
workspace: Workspace,
|
||||
) -> Result<Workspace> {
|
||||
let id = match workspace.id.as_str() {
|
||||
"" => generate_model_id(ModelType::TypeWorkspace),
|
||||
_ => workspace.id.to_string(),
|
||||
@@ -222,7 +225,10 @@ pub async fn upsert_workspace(window: &WebviewWindow, workspace: Workspace) -> R
|
||||
Ok(emit_upserted_model(window, m))
|
||||
}
|
||||
|
||||
pub async fn delete_workspace(window: &WebviewWindow, id: &str) -> Result<Workspace> {
|
||||
pub async fn delete_workspace<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
id: &str,
|
||||
) -> Result<Workspace> {
|
||||
let workspace = get_workspace(window, id).await?;
|
||||
|
||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||
@@ -241,7 +247,7 @@ pub async fn delete_workspace(window: &WebviewWindow, id: &str) -> Result<Worksp
|
||||
emit_deleted_model(window, workspace)
|
||||
}
|
||||
|
||||
pub async fn get_cookie_jar(mgr: &impl Manager<Wry>, id: &str) -> Result<CookieJar> {
|
||||
pub async fn get_cookie_jar<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<CookieJar> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
|
||||
@@ -254,8 +260,8 @@ pub async fn get_cookie_jar(mgr: &impl Manager<Wry>, id: &str) -> Result<CookieJ
|
||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||
}
|
||||
|
||||
pub async fn list_cookie_jars(
|
||||
mgr: &impl Manager<Wry>,
|
||||
pub async fn list_cookie_jars<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<CookieJar>> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
@@ -270,7 +276,10 @@ pub async fn list_cookie_jars(
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
}
|
||||
|
||||
pub async fn delete_cookie_jar(window: &WebviewWindow, id: &str) -> Result<CookieJar> {
|
||||
pub async fn delete_cookie_jar<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
id: &str,
|
||||
) -> Result<CookieJar> {
|
||||
let cookie_jar = get_cookie_jar(window, id).await?;
|
||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
@@ -284,13 +293,19 @@ pub async fn delete_cookie_jar(window: &WebviewWindow, id: &str) -> Result<Cooki
|
||||
emit_deleted_model(window, cookie_jar)
|
||||
}
|
||||
|
||||
pub async fn duplicate_grpc_request(window: &WebviewWindow, id: &str) -> Result<GrpcRequest> {
|
||||
pub async fn duplicate_grpc_request<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
id: &str,
|
||||
) -> Result<GrpcRequest> {
|
||||
let mut request = get_grpc_request(window, id).await?.clone();
|
||||
request.id = "".to_string();
|
||||
upsert_grpc_request(window, &request).await
|
||||
}
|
||||
|
||||
pub async fn delete_grpc_request(window: &WebviewWindow, id: &str) -> Result<GrpcRequest> {
|
||||
pub async fn delete_grpc_request<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
id: &str,
|
||||
) -> Result<GrpcRequest> {
|
||||
let req = get_grpc_request(window, id).await?;
|
||||
|
||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||
@@ -304,8 +319,8 @@ pub async fn delete_grpc_request(window: &WebviewWindow, id: &str) -> Result<Grp
|
||||
emit_deleted_model(window, req)
|
||||
}
|
||||
|
||||
pub async fn upsert_grpc_request(
|
||||
window: &WebviewWindow,
|
||||
pub async fn upsert_grpc_request<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
request: &GrpcRequest,
|
||||
) -> Result<GrpcRequest> {
|
||||
let id = match request.id.as_str() {
|
||||
@@ -346,7 +361,11 @@ pub async fn upsert_grpc_request(
|
||||
request.service.as_ref().map(|s| s.as_str()).into(),
|
||||
request.method.as_ref().map(|s| s.as_str()).into(),
|
||||
request.message.as_str().into(),
|
||||
request .authentication_type .as_ref() .map(|s| s.as_str()) .into(),
|
||||
request
|
||||
.authentication_type
|
||||
.as_ref()
|
||||
.map(|s| s.as_str())
|
||||
.into(),
|
||||
serde_json::to_string(&request.authentication)?.into(),
|
||||
serde_json::to_string(&request.metadata)?.into(),
|
||||
])
|
||||
@@ -376,7 +395,7 @@ pub async fn upsert_grpc_request(
|
||||
Ok(emit_upserted_model(window, m))
|
||||
}
|
||||
|
||||
pub async fn get_grpc_request(mgr: &impl Manager<Wry>, id: &str) -> Result<GrpcRequest> {
|
||||
pub async fn get_grpc_request<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<GrpcRequest> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
|
||||
@@ -389,8 +408,8 @@ pub async fn get_grpc_request(mgr: &impl Manager<Wry>, id: &str) -> Result<GrpcR
|
||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||
}
|
||||
|
||||
pub async fn list_grpc_requests(
|
||||
mgr: &impl Manager<Wry>,
|
||||
pub async fn list_grpc_requests<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<GrpcRequest>> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
@@ -405,8 +424,8 @@ pub async fn list_grpc_requests(
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
}
|
||||
|
||||
pub async fn upsert_grpc_connection(
|
||||
window: &WebviewWindow,
|
||||
pub async fn upsert_grpc_connection<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
connection: &GrpcConnection,
|
||||
) -> Result<GrpcConnection> {
|
||||
let id = match connection.id.as_str() {
|
||||
@@ -467,7 +486,10 @@ pub async fn upsert_grpc_connection(
|
||||
Ok(emit_upserted_model(window, m))
|
||||
}
|
||||
|
||||
pub async fn get_grpc_connection(mgr: &impl Manager<Wry>, id: &str) -> Result<GrpcConnection> {
|
||||
pub async fn get_grpc_connection<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
id: &str,
|
||||
) -> Result<GrpcConnection> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
let (sql, params) = Query::select()
|
||||
@@ -479,8 +501,8 @@ pub async fn get_grpc_connection(mgr: &impl Manager<Wry>, id: &str) -> Result<Gr
|
||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||
}
|
||||
|
||||
pub async fn list_grpc_connections(
|
||||
mgr: &impl Manager<Wry>,
|
||||
pub async fn list_grpc_connections<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
request_id: &str,
|
||||
) -> Result<Vec<GrpcConnection>> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
@@ -497,7 +519,10 @@ pub async fn list_grpc_connections(
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
}
|
||||
|
||||
pub async fn delete_grpc_connection(window: &WebviewWindow, id: &str) -> Result<GrpcConnection> {
|
||||
pub async fn delete_grpc_connection<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
id: &str,
|
||||
) -> Result<GrpcConnection> {
|
||||
let resp = get_grpc_connection(window, id).await?;
|
||||
|
||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||
@@ -512,14 +537,20 @@ pub async fn delete_grpc_connection(window: &WebviewWindow, id: &str) -> Result<
|
||||
emit_deleted_model(window, resp)
|
||||
}
|
||||
|
||||
pub async fn delete_all_grpc_connections(window: &WebviewWindow, request_id: &str) -> Result<()> {
|
||||
pub async fn delete_all_grpc_connections<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
request_id: &str,
|
||||
) -> Result<()> {
|
||||
for r in list_grpc_connections(window, request_id).await? {
|
||||
delete_grpc_connection(window, &r.id).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn upsert_grpc_event(window: &WebviewWindow, event: &GrpcEvent) -> Result<GrpcEvent> {
|
||||
pub async fn upsert_grpc_event<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
event: &GrpcEvent,
|
||||
) -> Result<GrpcEvent> {
|
||||
let id = match event.id.as_str() {
|
||||
"" => generate_model_id(ModelType::TypeGrpcEvent),
|
||||
_ => event.id.to_string(),
|
||||
@@ -575,7 +606,7 @@ pub async fn upsert_grpc_event(window: &WebviewWindow, event: &GrpcEvent) -> Res
|
||||
Ok(emit_upserted_model(window, m))
|
||||
}
|
||||
|
||||
pub async fn get_grpc_event(mgr: &impl Manager<Wry>, id: &str) -> Result<GrpcEvent> {
|
||||
pub async fn get_grpc_event<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<GrpcEvent> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
let (sql, params) = Query::select()
|
||||
@@ -587,8 +618,8 @@ pub async fn get_grpc_event(mgr: &impl Manager<Wry>, id: &str) -> Result<GrpcEve
|
||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||
}
|
||||
|
||||
pub async fn list_grpc_events(
|
||||
mgr: &impl Manager<Wry>,
|
||||
pub async fn list_grpc_events<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
connection_id: &str,
|
||||
) -> Result<Vec<GrpcEvent>> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
@@ -605,8 +636,8 @@ pub async fn list_grpc_events(
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
}
|
||||
|
||||
pub async fn upsert_cookie_jar(
|
||||
window: &WebviewWindow,
|
||||
pub async fn upsert_cookie_jar<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
cookie_jar: &CookieJar,
|
||||
) -> Result<CookieJar> {
|
||||
let id = match cookie_jar.id.as_str() {
|
||||
@@ -653,8 +684,8 @@ pub async fn upsert_cookie_jar(
|
||||
Ok(emit_upserted_model(window, m))
|
||||
}
|
||||
|
||||
pub async fn list_environments(
|
||||
mgr: &impl Manager<Wry>,
|
||||
pub async fn list_environments<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<Environment>> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
@@ -671,7 +702,10 @@ pub async fn list_environments(
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
}
|
||||
|
||||
pub async fn delete_environment(window: &WebviewWindow, id: &str) -> Result<Environment> {
|
||||
pub async fn delete_environment<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
id: &str,
|
||||
) -> Result<Environment> {
|
||||
let env = get_environment(window, id).await?;
|
||||
|
||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||
@@ -686,7 +720,7 @@ pub async fn delete_environment(window: &WebviewWindow, id: &str) -> Result<Envi
|
||||
emit_deleted_model(window, env)
|
||||
}
|
||||
|
||||
async fn get_settings(mgr: &impl Manager<Wry>) -> Result<Settings> {
|
||||
async fn get_settings<R: Runtime>(mgr: &impl Manager<R>) -> Result<Settings> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
|
||||
@@ -699,7 +733,7 @@ async fn get_settings(mgr: &impl Manager<Wry>) -> Result<Settings> {
|
||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||
}
|
||||
|
||||
pub async fn get_or_create_settings(mgr: &impl Manager<Wry>) -> Settings {
|
||||
pub async fn get_or_create_settings<R: Runtime>(mgr: &impl Manager<R>) -> Settings {
|
||||
if let Ok(settings) = get_settings(mgr).await {
|
||||
return settings;
|
||||
}
|
||||
@@ -721,7 +755,10 @@ pub async fn get_or_create_settings(mgr: &impl Manager<Wry>) -> Settings {
|
||||
.expect("Failed to insert Settings")
|
||||
}
|
||||
|
||||
pub async fn update_settings(window: &WebviewWindow, settings: Settings) -> Result<Settings> {
|
||||
pub async fn update_settings<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
settings: Settings,
|
||||
) -> Result<Settings> {
|
||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
|
||||
@@ -773,8 +810,8 @@ pub async fn update_settings(window: &WebviewWindow, settings: Settings) -> Resu
|
||||
Ok(emit_upserted_model(window, m))
|
||||
}
|
||||
|
||||
pub async fn upsert_environment(
|
||||
window: &WebviewWindow,
|
||||
pub async fn upsert_environment<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
environment: Environment,
|
||||
) -> Result<Environment> {
|
||||
let id = match environment.id.as_str() {
|
||||
@@ -821,7 +858,7 @@ pub async fn upsert_environment(
|
||||
Ok(emit_upserted_model(window, m))
|
||||
}
|
||||
|
||||
pub async fn get_environment(mgr: &impl Manager<Wry>, id: &str) -> Result<Environment> {
|
||||
pub async fn get_environment<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<Environment> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
|
||||
@@ -834,7 +871,7 @@ pub async fn get_environment(mgr: &impl Manager<Wry>, id: &str) -> Result<Enviro
|
||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||
}
|
||||
|
||||
pub async fn get_folder(mgr: &impl Manager<Wry>, id: &str) -> Result<Folder> {
|
||||
pub async fn get_folder<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<Folder> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
|
||||
@@ -847,7 +884,10 @@ pub async fn get_folder(mgr: &impl Manager<Wry>, id: &str) -> Result<Folder> {
|
||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||
}
|
||||
|
||||
pub async fn list_folders(mgr: &impl Manager<Wry>, workspace_id: &str) -> Result<Vec<Folder>> {
|
||||
pub async fn list_folders<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<Folder>> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
|
||||
@@ -862,7 +902,7 @@ pub async fn list_folders(mgr: &impl Manager<Wry>, workspace_id: &str) -> Result
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
}
|
||||
|
||||
pub async fn delete_folder(window: &WebviewWindow, id: &str) -> Result<Folder> {
|
||||
pub async fn delete_folder<R: Runtime>(window: &WebviewWindow<R>, id: &str) -> Result<Folder> {
|
||||
let folder = get_folder(window, id).await?;
|
||||
|
||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||
@@ -877,7 +917,7 @@ pub async fn delete_folder(window: &WebviewWindow, id: &str) -> Result<Folder> {
|
||||
emit_deleted_model(window, folder)
|
||||
}
|
||||
|
||||
pub async fn upsert_folder(window: &WebviewWindow, r: Folder) -> Result<Folder> {
|
||||
pub async fn upsert_folder<R: Runtime>(window: &WebviewWindow<R>, r: Folder) -> Result<Folder> {
|
||||
let id = match r.id.as_str() {
|
||||
"" => generate_model_id(ModelType::TypeFolder),
|
||||
_ => r.id.to_string(),
|
||||
@@ -925,13 +965,19 @@ pub async fn upsert_folder(window: &WebviewWindow, r: Folder) -> Result<Folder>
|
||||
Ok(emit_upserted_model(window, m))
|
||||
}
|
||||
|
||||
pub async fn duplicate_http_request(window: &WebviewWindow, id: &str) -> Result<HttpRequest> {
|
||||
pub async fn duplicate_http_request<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
id: &str,
|
||||
) -> Result<HttpRequest> {
|
||||
let mut request = get_http_request(window, id).await?.clone();
|
||||
request.id = "".to_string();
|
||||
upsert_http_request(window, request).await
|
||||
}
|
||||
|
||||
pub async fn upsert_http_request(window: &WebviewWindow, r: HttpRequest) -> Result<HttpRequest> {
|
||||
pub async fn upsert_http_request<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
r: HttpRequest,
|
||||
) -> Result<HttpRequest> {
|
||||
let id = match r.id.as_str() {
|
||||
"" => generate_model_id(ModelType::TypeHttpRequest),
|
||||
_ => r.id.to_string(),
|
||||
@@ -1004,8 +1050,8 @@ pub async fn upsert_http_request(window: &WebviewWindow, r: HttpRequest) -> Resu
|
||||
Ok(emit_upserted_model(window, m))
|
||||
}
|
||||
|
||||
pub async fn list_http_requests(
|
||||
mgr: &impl Manager<Wry>,
|
||||
pub async fn list_http_requests<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<HttpRequest>> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
@@ -1021,7 +1067,7 @@ pub async fn list_http_requests(
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
}
|
||||
|
||||
pub async fn get_http_request(mgr: &impl Manager<Wry>, id: &str) -> Result<HttpRequest> {
|
||||
pub async fn get_http_request<R: Runtime>(mgr: &impl Manager<R>, id: &str) -> Result<HttpRequest> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
|
||||
@@ -1034,7 +1080,10 @@ pub async fn get_http_request(mgr: &impl Manager<Wry>, id: &str) -> Result<HttpR
|
||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||
}
|
||||
|
||||
pub async fn delete_http_request(window: &WebviewWindow, id: &str) -> Result<HttpRequest> {
|
||||
pub async fn delete_http_request<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
id: &str,
|
||||
) -> Result<HttpRequest> {
|
||||
let req = get_http_request(window, id).await?;
|
||||
|
||||
// DB deletes will cascade but this will delete the files
|
||||
@@ -1051,9 +1100,30 @@ pub async fn delete_http_request(window: &WebviewWindow, id: &str) -> Result<Htt
|
||||
emit_deleted_model(window, req)
|
||||
}
|
||||
|
||||
pub async fn create_default_http_response<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
request_id: &str,
|
||||
) -> Result<HttpResponse> {
|
||||
create_http_response(
|
||||
&window,
|
||||
request_id,
|
||||
0,
|
||||
0,
|
||||
"",
|
||||
0,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
vec![],
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn create_http_response(
|
||||
window: &WebviewWindow,
|
||||
pub async fn create_http_response<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
request_id: &str,
|
||||
elapsed: i64,
|
||||
elapsed_headers: i64,
|
||||
@@ -1146,8 +1216,8 @@ pub async fn cancel_pending_responses(app: &AppHandle) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_response_if_id(
|
||||
window: &WebviewWindow,
|
||||
pub async fn update_response_if_id<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
response: &HttpResponse,
|
||||
) -> Result<HttpResponse> {
|
||||
if response.id.is_empty() {
|
||||
@@ -1157,8 +1227,8 @@ pub async fn update_response_if_id(
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn update_response(
|
||||
window: &WebviewWindow,
|
||||
pub async fn update_response<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
response: &HttpResponse,
|
||||
) -> Result<HttpResponse> {
|
||||
let dbm = &*window.app_handle().state::<SqliteConnection>();
|
||||
@@ -1211,7 +1281,10 @@ pub async fn update_response(
|
||||
Ok(emit_upserted_model(window, m))
|
||||
}
|
||||
|
||||
pub async fn get_http_response(mgr: &impl Manager<Wry>, id: &str) -> Result<HttpResponse> {
|
||||
pub async fn get_http_response<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
id: &str,
|
||||
) -> Result<HttpResponse> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await.get().unwrap();
|
||||
let (sql, params) = Query::select()
|
||||
@@ -1223,7 +1296,10 @@ pub async fn get_http_response(mgr: &impl Manager<Wry>, id: &str) -> Result<Http
|
||||
Ok(stmt.query_row(&*params.as_params(), |row| row.try_into())?)
|
||||
}
|
||||
|
||||
pub async fn delete_http_response(window: &WebviewWindow, id: &str) -> Result<HttpResponse> {
|
||||
pub async fn delete_http_response<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
id: &str,
|
||||
) -> Result<HttpResponse> {
|
||||
let resp = get_http_response(window, id).await?;
|
||||
|
||||
// Delete the body file if it exists
|
||||
@@ -1244,15 +1320,18 @@ pub async fn delete_http_response(window: &WebviewWindow, id: &str) -> Result<Ht
|
||||
emit_deleted_model(window, resp)
|
||||
}
|
||||
|
||||
pub async fn delete_all_http_responses(window: &WebviewWindow, request_id: &str) -> Result<()> {
|
||||
pub async fn delete_all_http_responses<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
request_id: &str,
|
||||
) -> Result<()> {
|
||||
for r in list_responses(window, request_id, None).await? {
|
||||
delete_http_response(window, &r.id).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn list_responses(
|
||||
mgr: &impl Manager<Wry>,
|
||||
pub async fn list_responses<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
request_id: &str,
|
||||
limit: Option<i64>,
|
||||
) -> Result<Vec<HttpResponse>> {
|
||||
@@ -1271,8 +1350,8 @@ pub async fn list_responses(
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
}
|
||||
|
||||
pub async fn list_responses_by_workspace_id(
|
||||
mgr: &impl Manager<Wry>,
|
||||
pub async fn list_responses_by_workspace_id<R: Runtime>(
|
||||
mgr: &impl Manager<R>,
|
||||
workspace_id: &str,
|
||||
) -> Result<Vec<HttpResponse>> {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
@@ -1288,7 +1367,7 @@ pub async fn list_responses_by_workspace_id(
|
||||
Ok(items.map(|v| v.unwrap()).collect())
|
||||
}
|
||||
|
||||
pub async fn debug_pool(mgr: &impl Manager<Wry>) {
|
||||
pub async fn debug_pool<R: Runtime>(mgr: &impl Manager<R>) {
|
||||
let dbm = &*mgr.state::<SqliteConnection>();
|
||||
let db = dbm.0.lock().await;
|
||||
debug!("Debug database state: {:?}", db.state());
|
||||
@@ -1310,7 +1389,7 @@ struct ModelPayload<M: Serialize + Clone> {
|
||||
pub window_label: String,
|
||||
}
|
||||
|
||||
fn emit_upserted_model<M: Serialize + Clone>(window: &WebviewWindow, model: M) -> M {
|
||||
fn emit_upserted_model<M: Serialize + Clone, R: Runtime>(window: &WebviewWindow<R>, model: M) -> M {
|
||||
let payload = ModelPayload {
|
||||
model: model.clone(),
|
||||
window_label: window.label().to_string(),
|
||||
@@ -1320,7 +1399,10 @@ fn emit_upserted_model<M: Serialize + Clone>(window: &WebviewWindow, model: M) -
|
||||
model
|
||||
}
|
||||
|
||||
fn emit_deleted_model<M: Serialize + Clone>(window: &WebviewWindow, model: M) -> Result<M> {
|
||||
fn emit_deleted_model<M: Serialize + Clone, R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
model: M,
|
||||
) -> Result<M> {
|
||||
let payload = ModelPayload {
|
||||
model: model.clone(),
|
||||
window_label: window.label().to_string(),
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
use yaak_models::models::{CookieJar, Environment, Folder, GrpcConnection, GrpcEvent, GrpcRequest, HttpRequest, HttpResponse, KeyValue, Settings, Workspace};
|
||||
use yaak_models::models::{
|
||||
CookieJar, Environment, Folder, GrpcConnection, GrpcEvent, GrpcRequest, HttpRequest,
|
||||
HttpResponse, KeyValue, Settings, Workspace,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -20,12 +23,22 @@ pub struct InternalEvent {
|
||||
pub enum InternalEventPayload {
|
||||
BootRequest(BootRequest),
|
||||
BootResponse(BootResponse),
|
||||
|
||||
ImportRequest(ImportRequest),
|
||||
ImportResponse(ImportResponse),
|
||||
|
||||
FilterRequest(FilterRequest),
|
||||
FilterResponse(FilterResponse),
|
||||
|
||||
ExportHttpRequestRequest(ExportHttpRequestRequest),
|
||||
ExportHttpRequestResponse(ExportHttpRequestResponse),
|
||||
|
||||
SendHttpRequestRequest(SendHttpRequestRequest),
|
||||
SendHttpRequestResponse(SendHttpRequestResponse),
|
||||
|
||||
GetHttpRequestByIdRequest(GetHttpRequestByIdRequest),
|
||||
GetHttpRequestByIdResponse(GetHttpRequestByIdResponse),
|
||||
|
||||
/// Returned when a plugin doesn't get run, just so the server
|
||||
/// has something to listen for
|
||||
EmptyResponse(EmptyResponse),
|
||||
@@ -95,17 +108,33 @@ pub struct ExportHttpRequestResponse {
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
// TODO: Migrate plugins to return this type
|
||||
// #[derive(Debug, Clone, Serialize, Deserialize, TS)]
|
||||
// #[serde(rename_all = "camelCase", untagged)]
|
||||
// #[ts(export)]
|
||||
// pub enum ExportableModel {
|
||||
// Workspace(Workspace),
|
||||
// Environment(Environment),
|
||||
// Folder(Folder),
|
||||
// HttpRequest(HttpRequest),
|
||||
// GrpcRequest(GrpcRequest),
|
||||
// }
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct SendHttpRequestRequest {
|
||||
pub http_request: HttpRequest,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct SendHttpRequestResponse {
|
||||
pub http_response: HttpResponse,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct GetHttpRequestByIdRequest {
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct GetHttpRequestByIdResponse {
|
||||
pub http_request: Option<HttpRequest>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
|
||||
#[serde(default, rename_all = "camelCase")]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::error::Result;
|
||||
use crate::events::{
|
||||
ExportHttpRequestRequest, ExportHttpRequestResponse, FilterRequest, FilterResponse,
|
||||
ImportRequest, ImportResponse, InternalEventPayload,
|
||||
ExportHttpRequestRequest, ExportHttpRequestResponse, FilterRequest, FilterResponse
|
||||
, ImportRequest, ImportResponse, InternalEvent, InternalEventPayload,
|
||||
};
|
||||
|
||||
use crate::error::Error::PluginErr;
|
||||
@@ -10,6 +10,7 @@ use crate::plugin::start_server;
|
||||
use crate::server::PluginRuntimeGrpcServer;
|
||||
use std::time::Duration;
|
||||
use tauri::{AppHandle, Runtime};
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::sync::watch::Sender;
|
||||
use yaak_models::models::HttpRequest;
|
||||
|
||||
@@ -35,14 +36,33 @@ impl PluginManager {
|
||||
PluginManager { kill_tx, server }
|
||||
}
|
||||
|
||||
pub async fn cleanup(&mut self) {
|
||||
pub async fn subscribe(&self) -> (String, mpsc::Receiver<InternalEvent>) {
|
||||
self.server.subscribe().await
|
||||
}
|
||||
|
||||
pub async fn unsubscribe(&self, rx_id: &str) {
|
||||
self.server.unsubscribe(rx_id).await
|
||||
}
|
||||
|
||||
pub async fn cleanup(&self) {
|
||||
self.kill_tx.send_replace(true);
|
||||
|
||||
// Give it a bit of time to kill
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
}
|
||||
|
||||
pub async fn run_import(&mut self, content: &str) -> Result<(ImportResponse, String)> {
|
||||
pub async fn reply(
|
||||
&self,
|
||||
source_event: &InternalEvent,
|
||||
payload: &InternalEventPayload,
|
||||
) -> Result<()> {
|
||||
let reply_id = Some(source_event.clone().id);
|
||||
self.server
|
||||
.send(&payload, source_event.plugin_ref_id.as_str(), reply_id)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn run_import(&self, content: &str) -> Result<(ImportResponse, String)> {
|
||||
let reply_events = self
|
||||
.server
|
||||
.send_and_wait(&InternalEventPayload::ImportRequest(ImportRequest {
|
||||
@@ -67,7 +87,7 @@ impl PluginManager {
|
||||
}
|
||||
|
||||
pub async fn run_export_curl(
|
||||
&mut self,
|
||||
&self,
|
||||
request: &HttpRequest,
|
||||
) -> Result<ExportHttpRequestResponse> {
|
||||
let event = self
|
||||
@@ -90,7 +110,7 @@ impl PluginManager {
|
||||
}
|
||||
|
||||
pub async fn run_filter(
|
||||
&mut self,
|
||||
&self,
|
||||
filter: &str,
|
||||
content: &str,
|
||||
content_type: &str,
|
||||
|
||||
@@ -13,7 +13,6 @@ use tauri::plugin::{Builder, TauriPlugin};
|
||||
use tauri::{Manager, RunEvent, Runtime, State};
|
||||
use tokio::fs::read_dir;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::sync::Mutex;
|
||||
use tonic::codegen::tokio_stream;
|
||||
use tonic::transport::Server;
|
||||
|
||||
@@ -30,8 +29,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
.await
|
||||
.expect("Failed to read plugins dir");
|
||||
let manager = PluginManager::new(&app, plugin_dirs).await;
|
||||
let manager_state = Mutex::new(manager);
|
||||
app.manage(manager_state);
|
||||
app.manage(manager);
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
@@ -41,8 +39,8 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
api.prevent_exit();
|
||||
tauri::async_runtime::block_on(async move {
|
||||
info!("Exiting plugin runtime due to app exit");
|
||||
let manager: State<Mutex<PluginManager>> = app.state();
|
||||
manager.lock().await.cleanup().await;
|
||||
let manager: State<PluginManager> = app.state();
|
||||
manager.cleanup().await;
|
||||
exit(0);
|
||||
});
|
||||
}
|
||||
@@ -79,7 +77,7 @@ pub async fn start_server(
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
server.unsubscribe(rx_id).await;
|
||||
server.unsubscribe(rx_id.as_str()).await;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -95,8 +95,8 @@ impl PluginRuntimeGrpcServer {
|
||||
(id, rx)
|
||||
}
|
||||
|
||||
pub async fn unsubscribe(&self, rx_id: String) {
|
||||
self.subscribers.lock().await.remove(rx_id.as_str());
|
||||
pub async fn unsubscribe(&self, rx_id: &str) {
|
||||
self.subscribers.lock().await.remove(rx_id);
|
||||
}
|
||||
|
||||
pub async fn remove_plugins(&self, plugin_ids: Vec<String>) {
|
||||
@@ -214,6 +214,13 @@ impl PluginRuntimeGrpcServer {
|
||||
let msg = format!("Failed to find plugin for {plugin_name}");
|
||||
Err(PluginNotFoundErr(msg))
|
||||
}
|
||||
|
||||
pub async fn send(&self, payload: &InternalEventPayload, plugin_ref_id: &str, reply_id: Option<String>)-> Result<()> {
|
||||
let plugin = self.plugin_by_ref_id(plugin_ref_id).await?;
|
||||
let event = plugin.build_event_to_send(payload, reply_id);
|
||||
plugin.send(&event).await
|
||||
}
|
||||
|
||||
|
||||
pub async fn send_to_plugin(
|
||||
&self,
|
||||
@@ -301,7 +308,7 @@ impl PluginRuntimeGrpcServer {
|
||||
break;
|
||||
}
|
||||
}
|
||||
server.unsubscribe(rx_id).await;
|
||||
server.unsubscribe(rx_id.as_str()).await;
|
||||
|
||||
found_events
|
||||
})
|
||||
@@ -321,30 +328,6 @@ impl PluginRuntimeGrpcServer {
|
||||
Ok(events)
|
||||
}
|
||||
|
||||
pub async fn send(&self, payload: InternalEventPayload) -> Result<Vec<InternalEvent>> {
|
||||
let mut events: Vec<InternalEvent> = Vec::new();
|
||||
let plugins = self.plugin_ref_to_plugin.lock().await;
|
||||
if plugins.is_empty() {
|
||||
return Err(NoPluginsErr("Send failed because no plugins exist".into()));
|
||||
}
|
||||
|
||||
for ph in plugins.values() {
|
||||
let event = ph.build_event_to_send(&payload, None);
|
||||
self.send_to_plugin_handle(ph, &event).await?;
|
||||
events.push(event);
|
||||
}
|
||||
|
||||
Ok(events)
|
||||
}
|
||||
|
||||
async fn send_to_plugin_handle(
|
||||
&self,
|
||||
plugin: &PluginHandle,
|
||||
event: &InternalEvent,
|
||||
) -> Result<()> {
|
||||
plugin.send(event).await
|
||||
}
|
||||
|
||||
async fn load_plugins(
|
||||
&self,
|
||||
to_plugin_tx: mpsc::Sender<tonic::Result<EventStreamEvent>>,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "templates"
|
||||
name = "yaak_templates"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
Reference in New Issue
Block a user