use serde::{Deserialize, Serialize};
use crate::server::PendingResults;
#[tauri::command]
pub async fn pw_result(
pending: tauri::State<'_, PendingResults>,
id: String,
ok: bool,
data: Option<String>,
error: Option<String>,
) -> Result<(), String> {
let mut map = pending.lock().await;
if let Some(tx) = map.remove(&id) {
let result = if ok {
let v: serde_json::Value = data
.as_deref()
.and_then(|d| serde_json::from_str(d).ok())
.unwrap_or(serde_json::Value::Null);
serde_json::json!({"ok": true, "v": v}).to_string()
} else {
let err_str = error.unwrap_or_else(|| "unknown".to_string());
let escaped = serde_json::to_string(&err_str).unwrap_or_else(|_| r#""unknown""#.to_string());
format!(r#"{{"ok":false,"e":{}}}"#, escaped)
};
let _ = tx.send(result);
}
Ok(())
}
#[derive(Debug, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum Command {
Ping,
Eval { script: String },
Click {
selector: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
Dblclick {
selector: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
Hover {
selector: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
Fill {
selector: String,
text: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
TypeText {
selector: String,
text: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
Press {
selector: String,
key: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
Check {
selector: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
Uncheck {
selector: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
SelectOption {
selector: String,
value: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
Focus {
selector: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
Blur {
selector: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
DragAndDrop {
source: String,
target: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
SetInputFiles {
selector: String,
files: Vec<FilePayload>,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
TextContent {
selector: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
InnerHtml {
selector: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
InnerText {
selector: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
GetAttribute {
selector: String,
name: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
InputValue {
selector: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
BoundingBox {
selector: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
IsVisible { selector: String },
IsChecked { selector: String },
IsDisabled { selector: String },
IsEditable { selector: String },
AllTextContents { selector: String },
AllInnerTexts { selector: String },
Count { selector: String },
WaitForSelector {
selector: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
WaitForFunction {
expression: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
DispatchEvent {
selector: String,
event_type: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
GetComputedStyle {
selector: String,
property: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
IsFocused { selector: String },
Title,
Url,
Content,
Goto { url: String },
Reload,
GoBack,
GoForward,
WaitForUrl {
pattern: String,
#[serde(default = "default_timeout")]
timeout_ms: u64,
},
InstallDialogHandler {
#[serde(default)]
default_confirm: bool,
#[serde(default)]
default_prompt_text: Option<String>,
},
GetDialogs,
ClearDialogs,
AddNetworkRoute {
pattern: String,
status: u16,
body: String,
#[serde(default)]
content_type: Option<String>,
},
RemoveNetworkRoute { pattern: String },
ClearNetworkRoutes,
GetNetworkRequests,
ClearNetworkRequests,
Screenshot {
#[serde(default)]
path: Option<String>,
},
NativeScreenshot {
#[serde(default)]
path: Option<String>,
},
StartRecording {
path: String,
#[serde(default = "default_fps")]
fps: u32,
},
StopRecording,
}
fn default_timeout() -> u64 {
5000
}
fn default_fps() -> u32 {
10
}
#[derive(Debug, Deserialize)]
pub struct FilePayload {
pub name: String,
pub mime_type: String,
pub base64: String,
}
#[derive(Debug, Serialize)]
pub struct Response {
pub ok: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
impl Response {
pub fn ok(data: impl Into<Option<serde_json::Value>>) -> Self {
Self {
ok: true,
data: data.into(),
error: None,
}
}
pub fn err(msg: impl Into<String>) -> Self {
Self {
ok: false,
data: None,
error: Some(msg.into()),
}
}
}