mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-18 23:43:55 +01:00
Url parameters for websocket URLs
This commit is contained in:
12
src-tauri/Cargo.lock
generated
12
src-tauri/Cargo.lock
generated
@@ -7619,9 +7619,9 @@ dependencies = [
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"ts-rs",
|
||||
"urlencoding",
|
||||
"uuid",
|
||||
"yaak-grpc",
|
||||
"yaak-http",
|
||||
"yaak-license",
|
||||
"yaak-models",
|
||||
"yaak-plugins",
|
||||
@@ -7659,6 +7659,15 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaak-http"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"urlencoding",
|
||||
"yaak-models",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaak-license"
|
||||
version = "0.1.0"
|
||||
@@ -7774,6 +7783,7 @@ dependencies = [
|
||||
"thiserror 2.0.11",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"yaak-http",
|
||||
"yaak-models",
|
||||
"yaak-plugins",
|
||||
"yaak-templates",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"yaak-grpc",
|
||||
"yaak-http",
|
||||
"yaak-license",
|
||||
"yaak-models",
|
||||
"yaak-plugins",
|
||||
@@ -70,9 +71,9 @@ tauri-plugin-window-state = "2.2.1"
|
||||
tokio = { version = "1.43.0", features = ["sync"] }
|
||||
tokio-stream = "0.1.17"
|
||||
ts-rs = { workspace = true }
|
||||
urlencoding = "2.1.3"
|
||||
uuid = "1.12.1"
|
||||
yaak-grpc = { path = "yaak-grpc" }
|
||||
yaak-http = { workspace = true }
|
||||
yaak-license = { path = "yaak-license" }
|
||||
yaak-models = { workspace = true }
|
||||
yaak-plugins = { workspace = true }
|
||||
@@ -92,5 +93,6 @@ thiserror = "2.0.3"
|
||||
ts-rs = "10.0.0"
|
||||
yaak-models = { path = "yaak-models" }
|
||||
yaak-plugins = { path = "yaak-plugins" }
|
||||
yaak-http = { path = "yaak-http" }
|
||||
yaak-sse = { path = "yaak-sse" }
|
||||
yaak-templates = { path = "yaak-templates" }
|
||||
|
||||
2
src-tauri/gen/schemas/acl-manifests.json
generated
2
src-tauri/gen/schemas/acl-manifests.json
generated
File diff suppressed because one or more lines are too long
10
src-tauri/gen/schemas/desktop-schema.json
generated
10
src-tauri/gen/schemas/desktop-schema.json
generated
@@ -5517,6 +5517,11 @@
|
||||
"type": "string",
|
||||
"const": "yaak-ws:allow-delete-request"
|
||||
},
|
||||
{
|
||||
"description": "Enables the duplicate_request command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-ws:allow-duplicate-request"
|
||||
},
|
||||
{
|
||||
"description": "Enables the list_connections command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -5587,6 +5592,11 @@
|
||||
"type": "string",
|
||||
"const": "yaak-ws:deny-delete-request"
|
||||
},
|
||||
{
|
||||
"description": "Denies the duplicate_request command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-ws:deny-duplicate-request"
|
||||
},
|
||||
{
|
||||
"description": "Denies the list_connections command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
||||
10
src-tauri/gen/schemas/macOS-schema.json
generated
10
src-tauri/gen/schemas/macOS-schema.json
generated
@@ -5517,6 +5517,11 @@
|
||||
"type": "string",
|
||||
"const": "yaak-ws:allow-delete-request"
|
||||
},
|
||||
{
|
||||
"description": "Enables the duplicate_request command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-ws:allow-duplicate-request"
|
||||
},
|
||||
{
|
||||
"description": "Enables the list_connections command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -5587,6 +5592,11 @@
|
||||
"type": "string",
|
||||
"const": "yaak-ws:deny-delete-request"
|
||||
},
|
||||
{
|
||||
"description": "Denies the duplicate_request command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "yaak-ws:deny-duplicate-request"
|
||||
},
|
||||
{
|
||||
"description": "Denies the list_connections command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
||||
@@ -203,7 +203,7 @@ pub async fn track_event<R: Runtime>(
|
||||
}
|
||||
}
|
||||
|
||||
fn get_os() -> &'static str {
|
||||
pub fn get_os() -> &'static str {
|
||||
if cfg!(target_os = "windows") {
|
||||
"windows"
|
||||
} else if cfg!(target_os = "macos") {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::time::SystemTime;
|
||||
|
||||
use crate::analytics::get_num_launches;
|
||||
use crate::analytics::{get_num_launches, get_os};
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use log::debug;
|
||||
use reqwest::Method;
|
||||
@@ -66,8 +66,9 @@ impl YaakNotifier {
|
||||
let req = reqwest::Client::default()
|
||||
.request(Method::GET, "https://notify.yaak.app/notifications")
|
||||
.query(&[
|
||||
("version", info.version.to_string()),
|
||||
("launches", num_launches.to_string()),
|
||||
("version", info.version.to_string().as_str()),
|
||||
("launches", num_launches.to_string().as_str()),
|
||||
("platform", get_os())
|
||||
]);
|
||||
let resp = req.send().await.map_err(|e| e.to_string())?;
|
||||
if resp.status() != 200 {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use serde_json::Value;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use yaak_http::apply_path_placeholders;
|
||||
use yaak_models::models::{
|
||||
Environment, GrpcMetadataEntry, GrpcRequest, HttpRequest,
|
||||
HttpRequestHeader, HttpUrlParameter,
|
||||
Environment, GrpcMetadataEntry, GrpcRequest, HttpRequest, HttpRequestHeader, HttpUrlParameter,
|
||||
};
|
||||
use yaak_models::render::make_vars_hashmap;
|
||||
use yaak_templates::{parse_and_render, render_json_value_raw, TemplateCallback};
|
||||
@@ -99,17 +99,18 @@ pub async fn render_http_request<T: TemplateCallback>(
|
||||
}
|
||||
|
||||
let url = render(r.url.clone().as_str(), vars, cb).await;
|
||||
let req = HttpRequest {
|
||||
|
||||
// This doesn't fit perfectly with the concept of "rendering" but it kind of does
|
||||
let (url, url_parameters) = apply_path_placeholders(&url, url_parameters);
|
||||
|
||||
HttpRequest {
|
||||
url,
|
||||
url_parameters,
|
||||
headers,
|
||||
body,
|
||||
authentication,
|
||||
..r.to_owned()
|
||||
};
|
||||
|
||||
// This doesn't fit perfectly with the concept of "rendering" but it kind of does
|
||||
apply_path_placeholders(req)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn render<T: TemplateCallback>(
|
||||
@@ -119,180 +120,3 @@ pub async fn render<T: TemplateCallback>(
|
||||
) -> String {
|
||||
parse_and_render(template, vars, cb).await
|
||||
}
|
||||
|
||||
fn replace_path_placeholder(p: &HttpUrlParameter, url: &str) -> String {
|
||||
if !p.enabled {
|
||||
return url.to_string();
|
||||
}
|
||||
|
||||
if !p.name.starts_with(":") {
|
||||
return url.to_string();
|
||||
}
|
||||
|
||||
let re = regex::Regex::new(format!("(/){}([/?#]|$)", p.name).as_str()).unwrap();
|
||||
let result = re
|
||||
.replace_all(url, |cap: ®ex::Captures| {
|
||||
format!(
|
||||
"{}{}{}",
|
||||
cap[1].to_string(),
|
||||
urlencoding::encode(p.value.as_str()),
|
||||
cap[2].to_string()
|
||||
)
|
||||
})
|
||||
.into_owned();
|
||||
result
|
||||
}
|
||||
|
||||
fn apply_path_placeholders(rendered_request: HttpRequest) -> HttpRequest {
|
||||
let mut url = rendered_request.url.to_owned();
|
||||
let mut url_parameters = Vec::new();
|
||||
for p in rendered_request.url_parameters.clone() {
|
||||
if !p.enabled || p.name.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Replace path parameters with values from URL parameters
|
||||
let old_url_string = url.clone();
|
||||
url = replace_path_placeholder(&p, url.as_str());
|
||||
|
||||
// Remove as param if it modified the URL
|
||||
if old_url_string == url {
|
||||
url_parameters.push(p);
|
||||
}
|
||||
}
|
||||
|
||||
let mut request = rendered_request.clone();
|
||||
request.url_parameters = url_parameters;
|
||||
request.url = url;
|
||||
request
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod placeholder_tests {
|
||||
use crate::render::{apply_path_placeholders, replace_path_placeholder};
|
||||
use yaak_models::models::{HttpRequest, HttpUrlParameter};
|
||||
|
||||
#[test]
|
||||
fn placeholder_middle() {
|
||||
let p = HttpUrlParameter {
|
||||
name: ":foo".into(),
|
||||
value: "xxx".into(),
|
||||
enabled: true,
|
||||
id: None,
|
||||
};
|
||||
assert_eq!(
|
||||
replace_path_placeholder(&p, "https://example.com/:foo/bar"),
|
||||
"https://example.com/xxx/bar",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placeholder_end() {
|
||||
let p = HttpUrlParameter {
|
||||
name: ":foo".into(),
|
||||
value: "xxx".into(),
|
||||
enabled: true,
|
||||
id: None,
|
||||
};
|
||||
assert_eq!(
|
||||
replace_path_placeholder(&p, "https://example.com/:foo"),
|
||||
"https://example.com/xxx",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placeholder_query() {
|
||||
let p = HttpUrlParameter {
|
||||
name: ":foo".into(),
|
||||
value: "xxx".into(),
|
||||
enabled: true,
|
||||
id: None,
|
||||
};
|
||||
assert_eq!(
|
||||
replace_path_placeholder(&p, "https://example.com/:foo?:foo"),
|
||||
"https://example.com/xxx?:foo",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placeholder_missing() {
|
||||
let p = HttpUrlParameter {
|
||||
enabled: true,
|
||||
name: "".to_string(),
|
||||
value: "".to_string(),
|
||||
id: None,
|
||||
};
|
||||
assert_eq!(
|
||||
replace_path_placeholder(&p, "https://example.com/:missing"),
|
||||
"https://example.com/:missing",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placeholder_disabled() {
|
||||
let p = HttpUrlParameter {
|
||||
enabled: false,
|
||||
name: ":foo".to_string(),
|
||||
value: "xxx".to_string(),
|
||||
id: None,
|
||||
};
|
||||
assert_eq!(
|
||||
replace_path_placeholder(&p, "https://example.com/:foo"),
|
||||
"https://example.com/:foo",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placeholder_prefix() {
|
||||
let p = HttpUrlParameter {
|
||||
name: ":foo".into(),
|
||||
value: "xxx".into(),
|
||||
enabled: true,
|
||||
id: None,
|
||||
};
|
||||
assert_eq!(
|
||||
replace_path_placeholder(&p, "https://example.com/:foooo"),
|
||||
"https://example.com/:foooo",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placeholder_encode() {
|
||||
let p = HttpUrlParameter {
|
||||
name: ":foo".into(),
|
||||
value: "Hello World".into(),
|
||||
enabled: true,
|
||||
id: None,
|
||||
};
|
||||
assert_eq!(
|
||||
replace_path_placeholder(&p, "https://example.com/:foo"),
|
||||
"https://example.com/Hello%20World",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_placeholder() {
|
||||
let result = apply_path_placeholders(HttpRequest {
|
||||
url: "example.com/:a/bar".to_string(),
|
||||
url_parameters: vec![
|
||||
HttpUrlParameter {
|
||||
name: "b".to_string(),
|
||||
value: "bbb".to_string(),
|
||||
enabled: true,
|
||||
id: None,
|
||||
},
|
||||
HttpUrlParameter {
|
||||
name: ":a".to_string(),
|
||||
value: "aaa".to_string(),
|
||||
enabled: true,
|
||||
id: None,
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
});
|
||||
assert_eq!(result.url, "example.com/aaa/bar");
|
||||
assert_eq!(result.url_parameters.len(), 1);
|
||||
assert_eq!(result.url_parameters[0].name, "b");
|
||||
assert_eq!(result.url_parameters[0].value, "bbb");
|
||||
}
|
||||
}
|
||||
|
||||
10
src-tauri/yaak-http/Cargo.toml
Normal file
10
src-tauri/yaak-http/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "yaak-http"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
yaak-models = { workspace = true }
|
||||
regex = "1.11.0"
|
||||
urlencoding = "2.1.3"
|
||||
183
src-tauri/yaak-http/src/lib.rs
Normal file
183
src-tauri/yaak-http/src/lib.rs
Normal file
@@ -0,0 +1,183 @@
|
||||
use yaak_models::models::HttpUrlParameter;
|
||||
|
||||
pub fn apply_path_placeholders(
|
||||
url: &str,
|
||||
parameters: Vec<HttpUrlParameter>,
|
||||
) -> (String, Vec<HttpUrlParameter>) {
|
||||
let mut new_parameters = Vec::new();
|
||||
|
||||
let mut url = url.to_string();
|
||||
for p in parameters {
|
||||
if !p.enabled || p.name.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Replace path parameters with values from URL parameters
|
||||
let old_url_string = url.clone();
|
||||
url = replace_path_placeholder(&p, url.as_str());
|
||||
|
||||
// Remove as param if it modified the URL
|
||||
if old_url_string == *url {
|
||||
new_parameters.push(p);
|
||||
}
|
||||
}
|
||||
|
||||
(url, new_parameters)
|
||||
}
|
||||
|
||||
fn replace_path_placeholder(p: &HttpUrlParameter, url: &str) -> String {
|
||||
if !p.enabled {
|
||||
return url.to_string();
|
||||
}
|
||||
|
||||
if !p.name.starts_with(":") {
|
||||
return url.to_string();
|
||||
}
|
||||
|
||||
let re = regex::Regex::new(format!("(/){}([/?#]|$)", p.name).as_str()).unwrap();
|
||||
let result = re
|
||||
.replace_all(url, |cap: ®ex::Captures| {
|
||||
format!(
|
||||
"{}{}{}",
|
||||
cap[1].to_string(),
|
||||
urlencoding::encode(p.value.as_str()),
|
||||
cap[2].to_string()
|
||||
)
|
||||
})
|
||||
.into_owned();
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod placeholder_tests {
|
||||
use crate::{apply_path_placeholders, replace_path_placeholder};
|
||||
use yaak_models::models::{HttpRequest, HttpUrlParameter};
|
||||
|
||||
#[test]
|
||||
fn placeholder_middle() {
|
||||
let p = HttpUrlParameter {
|
||||
name: ":foo".into(),
|
||||
value: "xxx".into(),
|
||||
enabled: true,
|
||||
id: None,
|
||||
};
|
||||
assert_eq!(
|
||||
replace_path_placeholder(&p, "https://example.com/:foo/bar"),
|
||||
"https://example.com/xxx/bar",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placeholder_end() {
|
||||
let p = HttpUrlParameter {
|
||||
name: ":foo".into(),
|
||||
value: "xxx".into(),
|
||||
enabled: true,
|
||||
id: None,
|
||||
};
|
||||
assert_eq!(
|
||||
replace_path_placeholder(&p, "https://example.com/:foo"),
|
||||
"https://example.com/xxx",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placeholder_query() {
|
||||
let p = HttpUrlParameter {
|
||||
name: ":foo".into(),
|
||||
value: "xxx".into(),
|
||||
enabled: true,
|
||||
id: None,
|
||||
};
|
||||
assert_eq!(
|
||||
replace_path_placeholder(&p, "https://example.com/:foo?:foo"),
|
||||
"https://example.com/xxx?:foo",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placeholder_missing() {
|
||||
let p = HttpUrlParameter {
|
||||
enabled: true,
|
||||
name: "".to_string(),
|
||||
value: "".to_string(),
|
||||
id: None,
|
||||
};
|
||||
assert_eq!(
|
||||
replace_path_placeholder(&p, "https://example.com/:missing"),
|
||||
"https://example.com/:missing",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placeholder_disabled() {
|
||||
let p = HttpUrlParameter {
|
||||
enabled: false,
|
||||
name: ":foo".to_string(),
|
||||
value: "xxx".to_string(),
|
||||
id: None,
|
||||
};
|
||||
assert_eq!(
|
||||
replace_path_placeholder(&p, "https://example.com/:foo"),
|
||||
"https://example.com/:foo",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placeholder_prefix() {
|
||||
let p = HttpUrlParameter {
|
||||
name: ":foo".into(),
|
||||
value: "xxx".into(),
|
||||
enabled: true,
|
||||
id: None,
|
||||
};
|
||||
assert_eq!(
|
||||
replace_path_placeholder(&p, "https://example.com/:foooo"),
|
||||
"https://example.com/:foooo",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placeholder_encode() {
|
||||
let p = HttpUrlParameter {
|
||||
name: ":foo".into(),
|
||||
value: "Hello World".into(),
|
||||
enabled: true,
|
||||
id: None,
|
||||
};
|
||||
assert_eq!(
|
||||
replace_path_placeholder(&p, "https://example.com/:foo"),
|
||||
"https://example.com/Hello%20World",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_placeholder() {
|
||||
let req = HttpRequest {
|
||||
url: "example.com/:a/bar".to_string(),
|
||||
url_parameters: vec![
|
||||
HttpUrlParameter {
|
||||
name: "b".to_string(),
|
||||
value: "bbb".to_string(),
|
||||
enabled: true,
|
||||
id: None,
|
||||
},
|
||||
HttpUrlParameter {
|
||||
name: ":a".to_string(),
|
||||
value: "aaa".to_string(),
|
||||
enabled: true,
|
||||
id: None,
|
||||
},
|
||||
],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let (url, url_parameters) = apply_path_placeholders(&req.url, req.url_parameters);
|
||||
|
||||
// Pattern match back to access it
|
||||
assert_eq!(url, "example.com/aaa/bar");
|
||||
assert_eq!(url_parameters.len(), 1);
|
||||
assert_eq!(url_parameters[0].name, "b");
|
||||
assert_eq!(url_parameters[0].value, "bbb");
|
||||
}
|
||||
}
|
||||
@@ -1054,6 +1054,20 @@ pub async fn upsert_websocket_event<R: Runtime>(
|
||||
Ok(m)
|
||||
}
|
||||
|
||||
pub async fn duplicate_websocket_request<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
id: &str,
|
||||
update_source: &UpdateSource,
|
||||
) -> Result<WebsocketRequest> {
|
||||
let mut request = match get_websocket_request(window, id).await? {
|
||||
None => return Err(ModelNotFound(id.to_string())),
|
||||
Some(r) => r,
|
||||
};
|
||||
request.id = "".to_string();
|
||||
request.sort_priority = request.sort_priority + 0.001;
|
||||
upsert_websocket_request(window, request, update_source).await
|
||||
}
|
||||
|
||||
pub async fn upsert_websocket_request<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
request: WebsocketRequest,
|
||||
@@ -2653,7 +2667,9 @@ pub async fn get_workspace_export_resources<R: Runtime>(
|
||||
data.resources.folders.append(&mut list_folders(mgr, workspace_id).await?);
|
||||
data.resources.http_requests.append(&mut list_http_requests(mgr, workspace_id).await?);
|
||||
data.resources.grpc_requests.append(&mut list_grpc_requests(mgr, workspace_id).await?);
|
||||
data.resources.websocket_requests.append(&mut list_websocket_requests(mgr, workspace_id).await?);
|
||||
data.resources
|
||||
.websocket_requests
|
||||
.append(&mut list_websocket_requests(mgr, workspace_id).await?);
|
||||
}
|
||||
|
||||
// Nuke environments if we don't want them
|
||||
|
||||
@@ -17,6 +17,7 @@ thiserror = "2.0.11"
|
||||
tokio = { version = "1.0", default-features = false, features = ["macros", "time", "test-util"] }
|
||||
tokio-tungstenite = { version = "0.26.1", default-features = false, features = ["rustls-tls-native-roots", "connect"] }
|
||||
yaak-models = { workspace = true }
|
||||
yaak-http = { workspace = true }
|
||||
yaak-plugins = { workspace = true }
|
||||
yaak-templates = { workspace = true }
|
||||
serde_json = "1.0.132"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use tauri_plugin;
|
||||
const COMMANDS: &[&str] = &[
|
||||
"close",
|
||||
"connect",
|
||||
"close",
|
||||
"delete_connection",
|
||||
"delete_connections",
|
||||
"delete_request",
|
||||
"duplicate_request",
|
||||
"list_connections",
|
||||
"list_events",
|
||||
"list_requests",
|
||||
|
||||
@@ -9,6 +9,12 @@ export function upsertWebsocketRequest(
|
||||
}) as Promise<WebsocketRequest>;
|
||||
}
|
||||
|
||||
export function duplicateWebsocketRequest(requestId: string) {
|
||||
return invoke('plugin:yaak-ws|duplicate_request', {
|
||||
requestId,
|
||||
}) as Promise<WebsocketRequest>;
|
||||
}
|
||||
|
||||
export function deleteWebsocketRequest(requestId: string) {
|
||||
return invoke('plugin:yaak-ws|delete_request', {
|
||||
requestId,
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
"$schema" = "../../schemas/schema.json"
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-duplicate-request"
|
||||
description = "Enables the duplicate_request command without any pre-configured scope."
|
||||
commands.allow = ["duplicate_request"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-duplicate-request"
|
||||
description = "Denies the duplicate_request command without any pre-configured scope."
|
||||
commands.deny = ["duplicate_request"]
|
||||
@@ -7,6 +7,7 @@ Default permissions for the plugin
|
||||
- `allow-delete-connection`
|
||||
- `allow-delete-connections`
|
||||
- `allow-delete-request`
|
||||
- `allow-duplicate-request`
|
||||
- `allow-list-connections`
|
||||
- `allow-list-events`
|
||||
- `allow-list-requests`
|
||||
@@ -181,6 +182,32 @@ Denies the delete_request command without any pre-configured scope.
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-ws:allow-duplicate-request`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Enables the duplicate_request command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-ws:deny-duplicate-request`
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
Denies the duplicate_request command without any pre-configured scope.
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
`yaak-ws:allow-list-connections`
|
||||
|
||||
</td>
|
||||
|
||||
@@ -6,6 +6,7 @@ permissions = [
|
||||
"allow-delete-connection",
|
||||
"allow-delete-connections",
|
||||
"allow-delete-request",
|
||||
"allow-duplicate-request",
|
||||
"allow-list-connections",
|
||||
"allow-list-events",
|
||||
"allow-list-requests",
|
||||
|
||||
@@ -354,6 +354,16 @@
|
||||
"type": "string",
|
||||
"const": "deny-delete-request"
|
||||
},
|
||||
{
|
||||
"description": "Enables the duplicate_request command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-duplicate-request"
|
||||
},
|
||||
{
|
||||
"description": "Denies the duplicate_request command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-duplicate-request"
|
||||
},
|
||||
{
|
||||
"description": "Enables the list_connections command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
|
||||
@@ -6,10 +6,11 @@ use chrono::Utc;
|
||||
use log::{info, warn};
|
||||
use std::str::FromStr;
|
||||
use tauri::http::{HeaderMap, HeaderName};
|
||||
use tauri::{AppHandle, Manager, Runtime, State, WebviewWindow};
|
||||
use tauri::{AppHandle, Manager, Runtime, State, Url, WebviewWindow};
|
||||
use tokio::sync::{mpsc, Mutex};
|
||||
use tokio_tungstenite::tungstenite::http::HeaderValue;
|
||||
use tokio_tungstenite::tungstenite::Message;
|
||||
use yaak_http::apply_path_placeholders;
|
||||
use yaak_models::models::{
|
||||
HttpResponseHeader, WebsocketConnection, WebsocketConnectionState, WebsocketEvent,
|
||||
WebsocketEventType, WebsocketRequest,
|
||||
@@ -33,6 +34,14 @@ pub(crate) async fn upsert_request<R: Runtime>(
|
||||
Ok(queries::upsert_websocket_request(&w, request, &UpdateSource::Window).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) async fn duplicate_request<R: Runtime>(
|
||||
request_id: &str,
|
||||
w: WebviewWindow<R>,
|
||||
) -> Result<WebsocketRequest> {
|
||||
Ok(queries::duplicate_websocket_request(&w, request_id, &UpdateSource::Window).await?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub(crate) async fn delete_request<R: Runtime>(
|
||||
request_id: &str,
|
||||
@@ -290,7 +299,22 @@ pub(crate) async fn connect<R: Runtime>(
|
||||
});
|
||||
}
|
||||
|
||||
let response = match ws_manager.connect(&connection.id, &request.url, headers, receive_tx).await
|
||||
|
||||
let (url, url_parameters) = apply_path_placeholders(&request.url, request.url_parameters);
|
||||
|
||||
// Add URL parameters to URL
|
||||
let mut url = Url::parse(&url).unwrap();
|
||||
{
|
||||
let mut query_pairs = url.query_pairs_mut();
|
||||
for p in url_parameters.clone() {
|
||||
if !p.enabled || p.name.is_empty() {
|
||||
continue;
|
||||
}
|
||||
query_pairs.append_pair(p.name.as_str(), p.value.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
let response = match ws_manager.connect(&connection.id, url.as_str(), headers, receive_tx).await
|
||||
{
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
@@ -298,6 +322,7 @@ pub(crate) async fn connect<R: Runtime>(
|
||||
&window,
|
||||
&WebsocketConnection {
|
||||
error: Some(format!("{e:?}")),
|
||||
state: WebsocketConnectionState::Closed,
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::Window,
|
||||
|
||||
@@ -5,8 +5,8 @@ mod manager;
|
||||
mod render;
|
||||
|
||||
use crate::cmd::{
|
||||
close, connect, delete_connection, delete_connections, delete_request, list_connections,
|
||||
list_events, list_requests, send, upsert_request,
|
||||
connect, close, delete_connection, delete_connections, delete_request, duplicate_request,
|
||||
list_connections, list_events, list_requests, send, upsert_request,
|
||||
};
|
||||
use crate::manager::WebsocketManager;
|
||||
use tauri::plugin::{Builder, TauriPlugin};
|
||||
@@ -16,11 +16,12 @@ use tokio::sync::Mutex;
|
||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
Builder::new("yaak-ws")
|
||||
.invoke_handler(generate_handler![
|
||||
close,
|
||||
connect,
|
||||
close,
|
||||
delete_connection,
|
||||
delete_connections,
|
||||
delete_request,
|
||||
duplicate_request,
|
||||
list_connections,
|
||||
list_events,
|
||||
list_requests,
|
||||
|
||||
Reference in New Issue
Block a user