Refactor model emit, and recent conn dropdown

This commit is contained in:
Gregory Schier
2024-02-05 10:39:47 -08:00
parent bf90f84d16
commit a7f2a86d71
29 changed files with 691 additions and 458 deletions

View File

@@ -1,6 +1,6 @@
{
"db_name": "SQLite",
"query": "\n SELECT id, model, workspace_id, request_id, created_at, updated_at, service, method\n FROM grpc_connections\n WHERE id = ?\n ",
"query": "\n SELECT\n id, model, workspace_id, request_id, created_at, updated_at, service,\n method, elapsed\n FROM grpc_connections\n WHERE id = ?\n ",
"describe": {
"columns": [
{
@@ -42,6 +42,11 @@
"name": "method",
"ordinal": 7,
"type_info": "Text"
},
{
"name": "elapsed",
"ordinal": 8,
"type_info": "Int64"
}
],
"parameters": {
@@ -55,8 +60,9 @@
false,
false,
false,
false,
false
]
},
"hash": "1ca8044e7eebe465e740623d4b5491e9fedc0e24a7bd3cc78ef8de795fdaef01"
"hash": "3330be44d8851f8e3456c403b5d1067f4e70e85ef8829b7aaad5b1993c3d01e8"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n DELETE FROM grpc_connections\n WHERE id = ?\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "42bc0ded60b44dab19daf6d8fc7df83d83af5d88ea0b84514fdc877a668c27cd"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "SQLite",
"query": "\n SELECT id, model, workspace_id, request_id, created_at, updated_at, service, method\n FROM grpc_connections\n WHERE request_id = ?\n ORDER BY created_at DESC\n ",
"query": "\n SELECT\n id, model, workspace_id, request_id, created_at, updated_at, service,\n method, elapsed\n FROM grpc_connections\n WHERE request_id = ?\n ORDER BY created_at DESC\n ",
"describe": {
"columns": [
{
@@ -42,6 +42,11 @@
"name": "method",
"ordinal": 7,
"type_info": "Text"
},
{
"name": "elapsed",
"ordinal": 8,
"type_info": "Int64"
}
],
"parameters": {
@@ -55,8 +60,9 @@
false,
false,
false,
false,
false
]
},
"hash": "a7b969f33ed0424188b429227d6e3fac2bef52f2e1b0eb1d3846d1293d41f86c"
"hash": "80a85f83d0946d532a60f0add87aa0ade7e35a6b56cb058e2caf9ca005ce6407"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO grpc_connections (\n id, workspace_id, request_id, service, method, elapsed\n )\n VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n service = excluded.service,\n method = excluded.method,\n elapsed = excluded.elapsed\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 6
},
"nullable": []
},
"hash": "9d7bc2b0eb0c09652d9826db4a7ae47591405e1b5bec1229f2e2734c73e66163"
}

View File

@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO grpc_connections (\n id, workspace_id, request_id, service, method\n )\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n service = excluded.service,\n method = excluded.method\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 5
},
"nullable": []
},
"hash": "f7df06213eff80e2ce5100b77ec244c83de39048e77c5af0b0b5d188d3279ca4"
}

68
src-tauri/Cargo.lock generated
View File

@@ -161,6 +161,16 @@ dependencies = [
"num-traits",
]
[[package]]
name = "atomic-write-file"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436"
dependencies = [
"nix",
"rand 0.8.5",
]
[[package]]
name = "autocfg"
version = "1.1.0"
@@ -2392,9 +2402,9 @@ dependencies = [
[[package]]
name = "libsqlite3-sys"
version = "0.26.0"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326"
checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716"
dependencies = [
"cc",
"pkg-config",
@@ -2641,6 +2651,17 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "nix"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
dependencies = [
"bitflags 2.4.1",
"cfg-if",
"libc",
]
[[package]]
name = "nodrop"
version = "0.1.14"
@@ -4220,9 +4241,9 @@ dependencies = [
[[package]]
name = "sqlx"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e50c216e3624ec8e7ecd14c6a6a6370aad6ee5d8cfc3ab30b5162eeeef2ed33"
checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf"
dependencies = [
"sqlx-core",
"sqlx-macros",
@@ -4233,9 +4254,9 @@ dependencies = [
[[package]]
name = "sqlx-core"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d6753e460c998bbd4cd8c6f0ed9a64346fcca0723d6e75e52fdc351c5d2169d"
checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd"
dependencies = [
"ahash",
"atoi",
@@ -4278,9 +4299,9 @@ dependencies = [
[[package]]
name = "sqlx-macros"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a793bb3ba331ec8359c1853bd39eed32cdd7baaf22c35ccf5c92a7e8d1189ec"
checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5"
dependencies = [
"proc-macro2",
"quote",
@@ -4291,10 +4312,11 @@ dependencies = [
[[package]]
name = "sqlx-macros-core"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a4ee1e104e00dedb6aa5ffdd1343107b0a4702e862a84320ee7cc74782d96fc"
checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841"
dependencies = [
"atomic-write-file",
"dotenvy",
"either",
"heck 0.4.1",
@@ -4317,9 +4339,9 @@ dependencies = [
[[package]]
name = "sqlx-mysql"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864b869fdf56263f4c95c45483191ea0af340f9f3e3e7b4d57a61c7c87a970db"
checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4"
dependencies = [
"atoi",
"base64 0.21.5",
@@ -4361,9 +4383,9 @@ dependencies = [
[[package]]
name = "sqlx-postgres"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb7ae0e6a97fb3ba33b23ac2671a5ce6e3cabe003f451abd5a56e7951d975624"
checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24"
dependencies = [
"atoi",
"base64 0.21.5",
@@ -4402,9 +4424,9 @@ dependencies = [
[[package]]
name = "sqlx-sqlite"
version = "0.7.2"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59dc83cf45d89c555a577694534fcd1b55c545a816c816ce51f20bbe56a4f3f"
checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490"
dependencies = [
"atoi",
"chrono",
@@ -4422,6 +4444,7 @@ dependencies = [
"time",
"tracing",
"url",
"urlencoding",
]
[[package]]
@@ -5402,6 +5425,12 @@ dependencies = [
"serde",
]
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]]
name = "utf-8"
version = "0.7.6"
@@ -5666,12 +5695,9 @@ dependencies = [
[[package]]
name = "webpki-roots"
version = "0.24.0"
version = "0.25.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888"
dependencies = [
"rustls-webpki",
]
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
[[package]]
name = "webview2-com"

View File

@@ -33,7 +33,7 @@ reqwest = { version = "0.11.23", features = ["multipart", "cookies", "gzip", "br
cookie = { version = "0.18.0" }
serde = { version = "1.0.195", features = ["derive"] }
serde_json = { version = "1.0.111", features = ["raw_value"] }
sqlx = { version = "0.7.2", features = ["sqlite", "runtime-tokio-rustls", "json", "chrono", "time"] }
sqlx = { version = "0.7.3", features = ["sqlite", "runtime-tokio-rustls", "json", "chrono", "time"] }
tauri = { version = "1.5.2", features = [
"config-toml",
"devtools",

View File

@@ -33,7 +33,8 @@ CREATE TABLE grpc_connections
created_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
service TEXT NOT NULL,
method TEXT NOT NULL
method TEXT NOT NULL,
elapsed INTEGER NOT NULL
);
CREATE TABLE grpc_messages

View File

@@ -14,6 +14,8 @@ pub enum AnalyticsResource {
Dialog,
Environment,
Folder,
GrpcConnection,
GrpcMessage,
GrpcRequest,
HttpRequest,
HttpResponse,
@@ -30,6 +32,8 @@ impl AnalyticsResource {
"CookieJar" => Some(AnalyticsResource::CookieJar),
"Environment" => Some(AnalyticsResource::Environment),
"Folder" => Some(AnalyticsResource::Folder),
"GrpcConnection" => Some(AnalyticsResource::GrpcConnection),
"GrpcMessage" => Some(AnalyticsResource::GrpcMessage),
"GrpcRequest" => Some(AnalyticsResource::GrpcRequest),
"HttpRequest" => Some(AnalyticsResource::HttpRequest),
"HttpResponse" => Some(AnalyticsResource::HttpResponse),
@@ -91,6 +95,8 @@ fn resource_name(resource: AnalyticsResource) -> &'static str {
AnalyticsResource::Environment => "environment",
AnalyticsResource::Folder => "folder",
AnalyticsResource::GrpcRequest => "grpc_request",
AnalyticsResource::GrpcConnection => "grpc_connection",
AnalyticsResource::GrpcMessage => "grpc_message",
AnalyticsResource::HttpRequest => "http_request",
AnalyticsResource::HttpResponse => "http_response",
AnalyticsResource::KeyValue => "key_value",

View File

@@ -15,7 +15,7 @@ use reqwest::{multipart, Url};
use sqlx::types::{Json, JsonValue};
use tauri::AppHandle;
use crate::{emit_side_effect, models, render, response_err};
use crate::{models, render, response_err};
pub async fn send_http_request(
app_handle: &AppHandle,
@@ -363,9 +363,6 @@ pub async fn send_http_request(
response = models::update_response_if_id(app_handle, &response)
.await
.expect("Failed to update response");
if !request.id.is_empty() {
emit_side_effect(app_handle, "upserted_model", &response);
}
// Copy response to download path, if specified
match (download_path, response.body_path.clone()) {
@@ -395,13 +392,8 @@ pub async fn send_http_request(
.collect::<Vec<_>>(),
);
cookie_jar.cookies = json_cookies;
match models::upsert_cookie_jar(&app_handle, &cookie_jar).await {
Ok(updated_jar) => {
emit_side_effect(app_handle, "upserted_model", &updated_jar);
}
Err(e) => {
error!("Failed to update cookie jar: {}", e);
}
if let Err(e) = models::upsert_cookie_jar(&app_handle, &cookie_jar).await {
error!("Failed to update cookie jar: {}", e);
};
}

View File

@@ -20,7 +20,6 @@ use fern::colors::ColoredLevelConfig;
use futures::StreamExt;
use log::{debug, error, info, warn};
use rand::random;
use serde::Serialize;
use serde_json::{json, Value};
use sqlx::migrate::Migrator;
use sqlx::types::Json;
@@ -42,11 +41,12 @@ use window_ext::TrafficLightWindowExt;
use crate::analytics::{AnalyticsAction, AnalyticsResource};
use crate::http::send_http_request;
use crate::models::{
cancel_pending_responses, create_response, delete_all_responses, delete_cookie_jar,
delete_environment, delete_folder, delete_request, delete_response, delete_workspace,
duplicate_grpc_request, duplicate_http_request, generate_id, get_cookie_jar, get_environment,
get_folder, get_grpc_request, get_http_request, get_key_value_raw, get_or_create_settings,
get_response, get_workspace, get_workspace_export_resources, list_cookie_jars,
cancel_pending_responses, create_response, delete_all_grpc_connections,
delete_all_http_responses, delete_cookie_jar, delete_environment, delete_folder,
delete_grpc_connection, delete_http_request, delete_http_response, delete_workspace,
duplicate_grpc_request, duplicate_http_request, get_cookie_jar, get_environment, get_folder,
get_grpc_request, get_http_request, get_http_response, get_key_value_raw,
get_or_create_settings, get_workspace, get_workspace_export_resources, list_cookie_jars,
list_environments, list_folders, list_grpc_connections, list_grpc_messages, list_grpc_requests,
list_requests, list_responses, list_workspaces, set_key_value_raw, update_response_if_id,
update_settings, upsert_cookie_jar, upsert_environment, upsert_folder, upsert_grpc_connection,
@@ -119,7 +119,6 @@ async fn cmd_grpc_call_unary(
.await
.map_err(|e| e.to_string())?
};
emit_side_effect(&app_handle, "upserted_model", conn.clone());
{
let req = req.clone();
@@ -140,11 +139,11 @@ async fn cmd_grpc_call_unary(
};
let uri = safe_uri(&req.url).map_err(|e| e.to_string())?;
let conn_id = generate_id(Some("grpc"));
let start = std::time::Instant::now();
let msg = match grpc_handle
.lock()
.await
.connect(&conn_id, uri)
.connect(&conn.clone().id, uri)
.await
.unary(
&req.service.unwrap_or_default(),
@@ -160,7 +159,7 @@ async fn cmd_grpc_call_unary(
message: msg,
workspace_id: req.workspace_id,
request_id: req.id,
connection_id: conn.id,
connection_id: conn.clone().id,
is_server: true,
..Default::default()
},
@@ -170,6 +169,16 @@ async fn cmd_grpc_call_unary(
Err(e) => return Err(e.to_string()),
};
upsert_grpc_connection(
&app_handle,
&GrpcConnection {
elapsed: start.elapsed().as_millis() as i64,
..conn
},
)
.await
.map_err(|e| e.to_string())?;
msg.map_err(|e| e.to_string())
}
@@ -194,7 +203,6 @@ async fn cmd_grpc_client_streaming(
.await
.map_err(|e| e.to_string())?
};
emit_side_effect(&app_handle, "upserted_model", conn.clone());
{
let conn = conn.clone();
@@ -296,6 +304,7 @@ async fn cmd_grpc_client_streaming(
let event_handler =
app_handle.listen_global(format!("grpc_client_msg_{}", conn.id).as_str(), cb);
let start = std::time::Instant::now();
let grpc_listen = {
let app_handle = app_handle.clone();
let conn = conn.clone();
@@ -308,10 +317,11 @@ async fn cmd_grpc_client_streaming(
.client_streaming(&conn.id, uri, &service, &method, in_msg_stream)
.await
.unwrap();
let message = serde_json::to_string(&msg).unwrap();
upsert_grpc_message(
&app_handle,
&GrpcMessage {
message: msg.to_string(),
message,
workspace_id: req.workspace_id,
request_id: req.id,
connection_id: conn.id,
@@ -336,12 +346,21 @@ async fn cmd_grpc_client_streaming(
message: "Connection completed".to_string(),
workspace_id: req.workspace_id,
request_id: req.id,
connection_id: conn.id,
connection_id: conn.clone().id,
is_info: true,
..Default::default()
},
)
.await.map_err(|e| e.to_string()).unwrap();
.await.unwrap();
upsert_grpc_connection(
&app_handle,
&GrpcConnection {
elapsed: start.elapsed().as_millis() as i64,
..conn
},
)
.await
.unwrap();
},
_ = cancelled_rx.changed() => {
upsert_grpc_message(
@@ -350,13 +369,22 @@ async fn cmd_grpc_client_streaming(
message: "Connection cancelled".to_string(),
workspace_id: req.workspace_id,
request_id: req.id,
connection_id: conn.id,
connection_id: conn.clone().id,
is_info: true,
..Default::default()
},
)
.await.unwrap();
upsert_grpc_connection(
&app_handle,
&GrpcConnection {
elapsed: start.elapsed().as_millis() as i64,
..conn
},
)
.await
.map_err(|e| e.to_string()).unwrap();
.unwrap();
},
}
app_handle.unlisten(event_handler);
@@ -388,7 +416,6 @@ async fn cmd_grpc_streaming(
.await
.map_err(|e| e.to_string())?
};
emit_side_effect(&app_handle, "upserted_model", conn.clone());
{
let conn = conn.clone();
@@ -423,6 +450,7 @@ async fn cmd_grpc_streaming(
}
};
let start = std::time::Instant::now();
let mut stream = grpc_handle
.lock()
.await
@@ -533,26 +561,40 @@ async fn cmd_grpc_streaming(
message: "Connection completed".to_string(),
workspace_id: req.workspace_id,
request_id: req.id,
connection_id: conn.id,
connection_id: conn.clone().id,
is_info: true,
..Default::default()
},
)
.await.map_err(|e| e.to_string()).unwrap();
.await.unwrap();
upsert_grpc_connection(
&app_handle,
&GrpcConnection{
elapsed: start.elapsed().as_millis() as i64,
..conn
},
).await.unwrap();
},
_ = cancelled_rx.changed() => {
upsert_grpc_message(
&app_handle,
&GrpcMessage {
message: "Connection cancelled".to_string(),
workspace_id: req.workspace_id,
request_id: req.id,
connection_id: conn.id,
is_info: true,
..Default::default()
},
)
.await.map_err(|e| e.to_string()).unwrap();
upsert_grpc_message(
&app_handle,
&GrpcMessage {
message: "Connection cancelled".to_string(),
workspace_id: req.workspace_id,
request_id: req.id,
connection_id: conn.clone().id,
is_info: true,
..Default::default()
},
)
.await.unwrap();
upsert_grpc_connection(
&app_handle,
&GrpcConnection{
elapsed: start.elapsed().as_millis() as i64,
..conn
},
).await.unwrap();
},
}
app_handle.unlisten(event_handler);
@@ -585,7 +627,6 @@ async fn cmd_grpc_server_streaming(
.await
.map_err(|e| e.to_string())?
};
emit_side_effect(&app_handle, "upserted_model", conn.clone());
{
let req = req.clone();
@@ -647,6 +688,7 @@ async fn cmd_grpc_server_streaming(
let event_handler =
app_handle.listen_global(format!("grpc_client_msg_{}", conn.id).as_str(), cb);
let start = std::time::Instant::now();
let grpc_listen = {
let conn_id = conn.clone().id;
let app_handle = app_handle.clone();
@@ -694,32 +736,46 @@ async fn cmd_grpc_server_streaming(
tauri::async_runtime::spawn(async move {
tokio::select! {
_ = grpc_listen => {
upsert_grpc_message(
&app_handle,
&GrpcMessage {
message: "Connection completed".to_string(),
workspace_id: req.workspace_id,
request_id: req.id,
connection_id: conn.id,
is_info: true,
..Default::default()
},
)
.await.unwrap();
upsert_grpc_message(
&app_handle,
&GrpcMessage {
message: "Connection completed".to_string(),
workspace_id: req.workspace_id,
request_id: req.id,
connection_id: conn.clone().id,
is_info: true,
..Default::default()
},
)
.await.unwrap();
upsert_grpc_connection(
&app_handle,
&GrpcConnection{
elapsed: start.elapsed().as_millis() as i64,
..conn
},
).await.unwrap();
},
_ = cancelled_rx.changed() => {
upsert_grpc_message(
&app_handle,
&GrpcMessage {
message: "Connection cancelled".to_string(),
workspace_id: req.workspace_id,
request_id: req.id,
connection_id: conn.id,
is_info: true,
..Default::default()
},
)
.await.unwrap();
upsert_grpc_message(
&app_handle,
&GrpcMessage {
message: "Connection cancelled".to_string(),
workspace_id: req.workspace_id,
request_id: req.id,
connection_id: conn.clone().id,
is_info: true,
..Default::default()
},
)
.await.unwrap();
upsert_grpc_connection(
&app_handle,
&GrpcConnection{
elapsed: start.elapsed().as_millis() as i64,
..conn
},
).await.unwrap();
},
}
app_handle.unlisten(event_handler);
@@ -774,7 +830,7 @@ async fn cmd_filter_response(
response_id: &str,
filter: &str,
) -> Result<String, String> {
let response = get_response(&app_handle, response_id)
let response = get_http_response(&app_handle, response_id)
.await
.expect("Failed to get response");
@@ -958,8 +1014,6 @@ async fn cmd_send_request(
None
};
emit_side_effect(&app_handle, "upserted_model", response.clone());
send_http_request(
&app_handle,
request.clone(),
@@ -982,7 +1036,6 @@ async fn response_err(
response = update_response_if_id(&app_handle, &response)
.await
.expect("Failed to update response");
emit_side_effect(&app_handle, "upserted_model", &response);
Ok(response)
}
@@ -1009,12 +1062,10 @@ async fn cmd_track_event(
}
#[tauri::command]
async fn cmd_set_update_mode(
update_mode: &str,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<KeyValue, String> {
cmd_set_key_value("app", "update_mode", update_mode, window, app_handle).await
async fn cmd_set_update_mode(update_mode: &str, app_handle: AppHandle) -> Result<KeyValue, String> {
cmd_set_key_value("app", "update_mode", update_mode, app_handle)
.await
.map_err(|e| e.to_string())
}
#[tauri::command]
@@ -1032,64 +1083,46 @@ async fn cmd_set_key_value(
namespace: &str,
key: &str,
value: &str,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<KeyValue, String> {
let (key_value, created) = set_key_value_raw(&app_handle, namespace, key, value).await;
if created {
emit_and_return(&window, "upserted_model", key_value)
} else {
emit_and_return(&window, "upserted_model", key_value)
}
let (key_value, _created) = set_key_value_raw(&app_handle, namespace, key, value).await;
Ok(key_value)
}
#[tauri::command]
async fn cmd_create_workspace(
name: &str,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<Workspace, String> {
let created_workspace = upsert_workspace(&app_handle, Workspace::new(name.to_string()))
async fn cmd_create_workspace(name: &str, app_handle: AppHandle) -> Result<Workspace, String> {
upsert_workspace(&app_handle, Workspace::new(name.to_string()))
.await
.expect("Failed to create Workspace");
emit_and_return(&window, "upserted_model", created_workspace)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_update_cookie_jar(
cookie_jar: CookieJar,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<CookieJar, String> {
let updated = upsert_cookie_jar(&app_handle, &cookie_jar)
upsert_cookie_jar(&app_handle, &cookie_jar)
.await
.expect("Failed to update cookie jar");
emit_and_return(&window, "upserted_model", updated)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_delete_cookie_jar(
window: Window<Wry>,
app_handle: AppHandle,
cookie_jar_id: &str,
) -> Result<CookieJar, String> {
let req = delete_cookie_jar(&app_handle, cookie_jar_id)
delete_cookie_jar(&app_handle, cookie_jar_id)
.await
.expect("Failed to delete cookie jar");
emit_and_return(&window, "deleted_model", req)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_create_cookie_jar(
workspace_id: &str,
name: &str,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<CookieJar, String> {
let created_cookie_jar = upsert_cookie_jar(
upsert_cookie_jar(
&app_handle,
&CookieJar {
name: name.to_string(),
@@ -1098,9 +1131,7 @@ async fn cmd_create_cookie_jar(
},
)
.await
.expect("Failed to create cookie jar");
emit_and_return(&window, "upserted_model", created_cookie_jar)
.map_err(|e| e.to_string())
}
#[tauri::command]
@@ -1108,10 +1139,9 @@ async fn cmd_create_environment(
workspace_id: &str,
name: &str,
variables: Vec<EnvironmentVariable>,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<Environment, String> {
let created_environment = upsert_environment(
upsert_environment(
&app_handle,
Environment {
workspace_id: workspace_id.to_string(),
@@ -1121,9 +1151,7 @@ async fn cmd_create_environment(
},
)
.await
.expect("Failed to create environment");
emit_and_return(&window, "upserted_model", created_environment)
.map_err(|e| e.to_string())
}
#[tauri::command]
@@ -1132,10 +1160,9 @@ async fn cmd_create_grpc_request(
name: &str,
sort_priority: f64,
folder_id: Option<&str>,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<GrpcRequest, String> {
let created = upsert_grpc_request(
upsert_grpc_request(
&app_handle,
&GrpcRequest {
workspace_id: workspace_id.to_string(),
@@ -1146,21 +1173,17 @@ async fn cmd_create_grpc_request(
},
)
.await
.expect("Failed to create grpc request");
emit_and_return(&window, "upserted_model", created)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_duplicate_grpc_request(
id: &str,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<GrpcRequest, String> {
let request = duplicate_grpc_request(&app_handle, id)
duplicate_grpc_request(&app_handle, id)
.await
.expect("Failed to duplicate grpc request");
emit_and_return(&window, "upserted_model", request)
.map_err(|e| e.to_string())
}
#[tauri::command]
@@ -1169,10 +1192,9 @@ async fn cmd_create_http_request(
name: &str,
sort_priority: f64,
folder_id: Option<&str>,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<HttpRequest, String> {
let created_request = upsert_http_request(
upsert_http_request(
&app_handle,
HttpRequest {
workspace_id: workspace_id.to_string(),
@@ -1184,95 +1206,77 @@ async fn cmd_create_http_request(
},
)
.await
.expect("Failed to create http request");
emit_and_return(&window, "upserted_model", created_request)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_duplicate_http_request(
id: &str,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<HttpRequest, String> {
let request = duplicate_http_request(&app_handle, id)
duplicate_http_request(&app_handle, id)
.await
.expect("Failed to duplicate http request");
emit_and_return(&window, "upserted_model", request)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_update_workspace(
workspace: Workspace,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<Workspace, String> {
let updated_workspace = upsert_workspace(&app_handle, workspace)
upsert_workspace(&app_handle, workspace)
.await
.expect("Failed to update request");
emit_and_return(&window, "upserted_model", updated_workspace)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_update_environment(
environment: Environment,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<Environment, String> {
let updated_environment = upsert_environment(&app_handle, environment)
upsert_environment(&app_handle, environment)
.await
.expect("Failed to update environment");
emit_and_return(&window, "upserted_model", updated_environment)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_update_grpc_request(
request: GrpcRequest,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<GrpcRequest, String> {
let updated_request = upsert_grpc_request(&app_handle, &request)
upsert_grpc_request(&app_handle, &request)
.await
.expect("Failed to update grpc request");
emit_and_return(&window, "upserted_model", updated_request)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_update_http_request(
request: HttpRequest,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<HttpRequest, String> {
let updated_request = upsert_http_request(&app_handle, request)
upsert_http_request(&app_handle, request)
.await
.expect("Failed to update request");
emit_and_return(&window, "upserted_model", updated_request)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_delete_grpc_request(
window: Window<Wry>,
app_handle: AppHandle,
request_id: &str,
) -> Result<HttpRequest, String> {
let req = delete_request(&app_handle, request_id)
delete_http_request(&app_handle, request_id)
.await
.expect("Failed to delete request");
emit_and_return(&window, "deleted_model", req)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_delete_http_request(
window: Window<Wry>,
app_handle: AppHandle,
request_id: &str,
) -> Result<HttpRequest, String> {
let req = delete_request(&app_handle, request_id)
delete_http_request(&app_handle, request_id)
.await
.expect("Failed to delete request");
emit_and_return(&window, "deleted_model", req)
.map_err(|e| e.to_string())
}
#[tauri::command]
@@ -1291,10 +1295,9 @@ async fn cmd_create_folder(
name: &str,
sort_priority: f64,
folder_id: Option<&str>,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<Folder, String> {
let created_request = upsert_folder(
upsert_folder(
&app_handle,
Folder {
workspace_id: workspace_id.to_string(),
@@ -1305,45 +1308,31 @@ async fn cmd_create_folder(
},
)
.await
.expect("Failed to create folder");
emit_and_return(&window, "upserted_model", created_request)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_update_folder(
folder: Folder,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<Folder, String> {
let updated_folder = upsert_folder(&app_handle, folder)
async fn cmd_update_folder(folder: Folder, app_handle: AppHandle) -> Result<Folder, String> {
upsert_folder(&app_handle, folder)
.await
.expect("Failed to update request");
emit_and_return(&window, "upserted_model", updated_folder)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_delete_folder(
window: Window<Wry>,
app_handle: AppHandle,
folder_id: &str,
) -> Result<Folder, String> {
let req = delete_folder(&app_handle, folder_id)
async fn cmd_delete_folder(app_handle: AppHandle, folder_id: &str) -> Result<Folder, String> {
delete_folder(&app_handle, folder_id)
.await
.expect("Failed to delete folder");
emit_and_return(&window, "deleted_model", req)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_delete_environment(
window: Window<Wry>,
app_handle: AppHandle,
environment_id: &str,
) -> Result<Environment, String> {
let req = delete_environment(&app_handle, environment_id)
delete_environment(&app_handle, environment_id)
.await
.expect("Failed to delete environment");
emit_and_return(&window, "deleted_model", req)
.map_err(|e| e.to_string())
}
#[tauri::command]
@@ -1409,14 +1398,11 @@ async fn cmd_get_settings(app_handle: AppHandle) -> Result<Settings, ()> {
#[tauri::command]
async fn cmd_update_settings(
settings: Settings,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<Settings, String> {
let updated_settings = update_settings(&app_handle, settings)
update_settings(&app_handle, settings)
.await
.expect("Failed to update settings");
emit_and_return(&window, "upserted_model", updated_settings)
.map_err(|e| e.to_string())
}
#[tauri::command]
@@ -1497,20 +1483,38 @@ async fn cmd_list_http_responses(
}
#[tauri::command]
async fn cmd_delete_response(
id: &str,
window: Window<Wry>,
app_handle: AppHandle,
) -> Result<HttpResponse, String> {
let response = delete_response(&app_handle, id)
async fn cmd_delete_http_response(id: &str, app_handle: AppHandle) -> Result<HttpResponse, String> {
delete_http_response(&app_handle, id)
.await
.expect("Failed to delete response");
emit_and_return(&window, "deleted_model", response)
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_delete_all_responses(request_id: &str, app_handle: AppHandle) -> Result<(), String> {
delete_all_responses(&app_handle, request_id)
async fn cmd_delete_grpc_connection(
id: &str,
app_handle: AppHandle,
) -> Result<GrpcConnection, String> {
delete_grpc_connection(&app_handle, id)
.await
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_delete_all_grpc_connections(
request_id: &str,
app_handle: AppHandle,
) -> Result<(), String> {
delete_all_grpc_connections(&app_handle, request_id)
.await
.map_err(|e| e.to_string())
}
#[tauri::command]
async fn cmd_delete_all_http_responses(
request_id: &str,
app_handle: AppHandle,
) -> Result<(), String> {
delete_all_http_responses(&app_handle, request_id)
.await
.map_err(|e| e.to_string())
}
@@ -1544,14 +1548,12 @@ async fn cmd_new_window(window: Window<Wry>, url: &str) -> Result<(), String> {
#[tauri::command]
async fn cmd_delete_workspace(
window: Window<Wry>,
app_handle: AppHandle,
workspace_id: &str,
) -> Result<Workspace, String> {
let workspace = delete_workspace(&app_handle, workspace_id)
delete_workspace(&app_handle, workspace_id)
.await
.expect("Failed to delete Workspace");
emit_and_return(&window, "deleted_model", workspace)
.map_err(|e| e.to_string())
}
#[tauri::command]
@@ -1646,13 +1648,15 @@ fn main() {
cmd_create_grpc_request,
cmd_create_http_request,
cmd_create_workspace,
cmd_delete_all_responses,
cmd_delete_all_http_responses,
cmd_delete_all_grpc_connections,
cmd_delete_cookie_jar,
cmd_delete_environment,
cmd_delete_folder,
cmd_delete_grpc_request,
cmd_delete_grpc_connection,
cmd_delete_http_request,
cmd_delete_response,
cmd_delete_http_response,
cmd_delete_workspace,
cmd_duplicate_http_request,
cmd_duplicate_grpc_request,
@@ -1858,21 +1862,6 @@ fn create_window(handle: &AppHandle, url: Option<&str>) -> Window<Wry> {
win
}
/// Emit an event to all windows, with a source window
fn emit_and_return<S: Serialize + Clone, E>(
current_window: &Window<Wry>,
event: &str,
payload: S,
) -> Result<S, E> {
current_window.emit_all(event, &payload).unwrap();
Ok(payload)
}
/// Emit an event to all windows, used for side-effects where there is no source window to attribute. This
fn emit_side_effect<S: Serialize + Clone>(app_handle: &AppHandle, event: &str, payload: S) {
app_handle.emit_all(event, &payload).unwrap();
}
async fn get_update_mode(app_handle: &AppHandle) -> UpdateMode {
let settings = get_or_create_settings(app_handle).await;
update_mode_from_str(settings.update_channel.as_str())

View File

@@ -217,6 +217,7 @@ pub struct GrpcConnection {
pub updated_at: NaiveDateTime,
pub service: String,
pub method: String,
pub elapsed: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
@@ -416,10 +417,10 @@ pub async fn delete_workspace(app_handle: &AppHandle, id: &str) -> Result<Worksp
.await;
for r in list_responses_by_workspace_id(app_handle, id).await? {
delete_response(app_handle, &r.id).await?;
delete_http_response(app_handle, &r.id).await?;
}
Ok(workspace)
emit_deleted_model(app_handle, workspace)
}
pub async fn get_cookie_jar(app_handle: &AppHandle, id: &str) -> Result<CookieJar, sqlx::Error> {
@@ -471,7 +472,7 @@ pub async fn delete_cookie_jar(app_handle: &AppHandle, id: &str) -> Result<Cooki
.execute(&db)
.await;
Ok(cookie_jar)
emit_deleted_model(app_handle, cookie_jar)
}
pub async fn duplicate_grpc_request(
@@ -522,7 +523,10 @@ pub async fn upsert_grpc_request(
.execute(&db)
.await?;
get_grpc_request(app_handle, &id).await
match get_grpc_request(app_handle, &id).await {
Ok(m) => Ok(emit_upserted_model(app_handle, m)),
Err(e) => Err(e),
}
}
pub async fn get_grpc_request(
@@ -577,24 +581,29 @@ pub async fn upsert_grpc_connection(
sqlx::query!(
r#"
INSERT INTO grpc_connections (
id, workspace_id, request_id, service, method
id, workspace_id, request_id, service, method, elapsed
)
VALUES (?, ?, ?, ?, ?)
VALUES (?, ?, ?, ?, ?, ?)
ON CONFLICT (id) DO UPDATE SET
updated_at = CURRENT_TIMESTAMP,
service = excluded.service,
method = excluded.method
method = excluded.method,
elapsed = excluded.elapsed
"#,
id,
connection.workspace_id,
connection.request_id,
connection.service,
connection.method,
connection.elapsed,
)
.execute(&db)
.await?;
get_grpc_connection(app_handle, &id).await
match get_grpc_connection(app_handle, &id).await {
Ok(m) => Ok(emit_upserted_model(app_handle, m)),
Err(e) => Err(e),
}
}
pub async fn get_grpc_connection(
@@ -605,7 +614,9 @@ pub async fn get_grpc_connection(
sqlx::query_as!(
GrpcConnection,
r#"
SELECT id, model, workspace_id, request_id, created_at, updated_at, service, method
SELECT
id, model, workspace_id, request_id, created_at, updated_at, service,
method, elapsed
FROM grpc_connections
WHERE id = ?
"#,
@@ -623,7 +634,9 @@ pub async fn list_grpc_connections(
sqlx::query_as!(
GrpcConnection,
r#"
SELECT id, model, workspace_id, request_id, created_at, updated_at, service, method
SELECT
id, model, workspace_id, request_id, created_at, updated_at, service,
method, elapsed
FROM grpc_connections
WHERE request_id = ?
ORDER BY created_at DESC
@@ -666,9 +679,8 @@ pub async fn upsert_grpc_message(
.execute(&db)
.await?;
let msg = get_grpc_message(app_handle, &id).await;
match msg {
Ok(msg) => Ok(emit_upserted_model(app_handle, msg.clone()).await),
match get_grpc_message(app_handle, &id).await {
Ok(m) => Ok(emit_upserted_model(app_handle, m)),
Err(e) => Err(e),
}
}
@@ -743,7 +755,10 @@ pub async fn upsert_cookie_jar(
.execute(&db)
.await?;
get_cookie_jar(&app_handle, &id).await
match get_cookie_jar(app_handle, &id).await {
Ok(m) => Ok(emit_upserted_model(app_handle, m)),
Err(e) => Err(e),
}
}
pub async fn list_environments(
@@ -781,7 +796,7 @@ pub async fn delete_environment(
.execute(&db)
.await;
Ok(env)
emit_deleted_model(app_handle, env)
}
async fn get_settings(app_handle: &AppHandle) -> Result<Settings, sqlx::Error> {
@@ -837,7 +852,11 @@ pub async fn update_settings(
)
.execute(&db)
.await?;
get_settings(app_handle).await
match get_settings(app_handle).await {
Ok(m) => Ok(emit_upserted_model(app_handle, m)),
Err(e) => Err(e),
}
}
pub async fn upsert_environment(
@@ -868,7 +887,11 @@ pub async fn upsert_environment(
)
.execute(&db)
.await?;
get_environment(app_handle, &id).await
match get_environment(app_handle, &id).await {
Ok(m) => Ok(emit_upserted_model(app_handle, m)),
Err(e) => Err(e),
}
}
pub async fn get_environment(app_handle: &AppHandle, id: &str) -> Result<Environment, sqlx::Error> {
@@ -924,7 +947,7 @@ pub async fn list_folders(
}
pub async fn delete_folder(app_handle: &AppHandle, id: &str) -> Result<Folder, sqlx::Error> {
let env = get_folder(app_handle, id).await?;
let folder = get_folder(app_handle, id).await?;
let db = get_db(app_handle).await;
let _ = sqlx::query!(
r#"
@@ -936,7 +959,7 @@ pub async fn delete_folder(app_handle: &AppHandle, id: &str) -> Result<Folder, s
.execute(&db)
.await;
Ok(env)
emit_deleted_model(app_handle, folder)
}
pub async fn upsert_folder(app_handle: &AppHandle, r: Folder) -> Result<Folder, sqlx::Error> {
@@ -968,7 +991,10 @@ pub async fn upsert_folder(app_handle: &AppHandle, r: Folder) -> Result<Folder,
.execute(&db)
.await?;
get_folder(&app_handle, &id).await
match get_folder(app_handle, &id).await {
Ok(m) => Ok(emit_upserted_model(app_handle, m)),
Err(e) => Err(e),
}
}
pub async fn duplicate_http_request(
@@ -1032,7 +1058,10 @@ pub async fn upsert_http_request(
.execute(&db)
.await?;
get_http_request(app_handle, &id).await
match get_http_request(app_handle, &id).await {
Ok(m) => Ok(emit_upserted_model(app_handle, m)),
Err(e) => Err(e),
}
}
pub async fn list_requests(
@@ -1084,11 +1113,14 @@ pub async fn get_http_request(
.await
}
pub async fn delete_request(app_handle: &AppHandle, id: &str) -> Result<HttpRequest, sqlx::Error> {
pub async fn delete_http_request(
app_handle: &AppHandle,
id: &str,
) -> Result<HttpRequest, sqlx::Error> {
let req = get_http_request(app_handle, id).await?;
// DB deletes will cascade but this will delete the files
delete_all_responses(app_handle, id).await?;
delete_all_http_responses(app_handle, id).await?;
let db = get_db(app_handle).await;
let _ = sqlx::query!(
@@ -1101,7 +1133,7 @@ pub async fn delete_request(app_handle: &AppHandle, id: &str) -> Result<HttpRequ
.execute(&db)
.await;
Ok(req)
emit_deleted_model(app_handle, req)
}
#[allow(clippy::too_many_arguments)]
@@ -1148,7 +1180,7 @@ pub async fn create_response(
.execute(&db)
.await?;
get_response(app_handle, &id).await
get_http_response(app_handle, &id).await
}
pub async fn cancel_pending_responses(app_handle: &AppHandle) -> Result<(), sqlx::Error> {
@@ -1214,7 +1246,10 @@ pub async fn upsert_workspace(
.execute(&db)
.await?;
get_workspace(app_handle, &id).await
match get_workspace(app_handle, &id).await {
Ok(m) => Ok(emit_upserted_model(app_handle, m)),
Err(e) => Err(e),
}
}
pub async fn update_response(
@@ -1245,10 +1280,17 @@ pub async fn update_response(
)
.execute(&db)
.await?;
get_response(app_handle, &response.id).await
match get_http_response(app_handle, &response.id).await {
Ok(m) => Ok(emit_upserted_model(app_handle, m)),
Err(e) => Err(e),
}
}
pub async fn get_response(app_handle: &AppHandle, id: &str) -> Result<HttpResponse, sqlx::Error> {
pub async fn get_http_response(
app_handle: &AppHandle,
id: &str,
) -> Result<HttpResponse, sqlx::Error> {
let db = get_db(app_handle).await;
sqlx::query_as!(
HttpResponse,
@@ -1317,11 +1359,31 @@ pub async fn list_responses_by_workspace_id(
.await
}
pub async fn delete_response(
pub async fn delete_grpc_connection(
app_handle: &AppHandle,
id: &str,
) -> Result<GrpcConnection, sqlx::Error> {
let resp = get_grpc_connection(app_handle, id).await?;
let db = get_db(app_handle).await;
let _ = sqlx::query!(
r#"
DELETE FROM grpc_connections
WHERE id = ?
"#,
id,
)
.execute(&db)
.await;
emit_deleted_model(app_handle, resp)
}
pub async fn delete_http_response(
app_handle: &AppHandle,
id: &str,
) -> Result<HttpResponse, sqlx::Error> {
let resp = get_response(app_handle, id).await?;
let resp = get_http_response(app_handle, id).await?;
// Delete the body file if it exists
if let Some(p) = resp.body_path.clone() {
@@ -1341,15 +1403,25 @@ pub async fn delete_response(
.execute(&db)
.await;
Ok(resp)
emit_deleted_model(app_handle, resp)
}
pub async fn delete_all_responses(
pub async fn delete_all_grpc_connections(
app_handle: &AppHandle,
request_id: &str,
) -> Result<(), sqlx::Error> {
for r in list_grpc_connections(app_handle, request_id).await? {
delete_grpc_connection(app_handle, &r.id).await?;
}
Ok(())
}
pub async fn delete_all_http_responses(
app_handle: &AppHandle,
request_id: &str,
) -> Result<(), sqlx::Error> {
for r in list_responses(app_handle, request_id, None).await? {
delete_response(app_handle, &r.id).await?;
delete_http_response(app_handle, &r.id).await?;
}
Ok(())
}
@@ -1406,13 +1478,18 @@ pub async fn get_workspace_export_resources(
};
}
async fn emit_upserted_model<S: Serialize + Clone>(app_handle: &AppHandle, model: S) -> S {
fn emit_upserted_model<S: Serialize + Clone>(app_handle: &AppHandle, model: S) -> S {
app_handle
.emit_all("upserted_model", model.clone())
.unwrap();
model
}
fn emit_deleted_model<S: Serialize + Clone, E>(app_handle: &AppHandle, model: S) -> Result<S, E> {
app_handle.emit_all("deleted_model", model.clone()).unwrap();
Ok(model)
}
async fn get_db(app_handle: &AppHandle) -> Pool<Sqlite> {
let db_state = app_handle.state::<Mutex<Pool<Sqlite>>>();
let db = &*db_state.lock().await;