use std::sync::Arc;
use axum::extract::{Path, State};
use axum::Json;
use serde::Deserialize;
use serde_json::Value;
use tauri::Runtime;
use crate::platform::FrameId;
use crate::server::response::{WebDriverErrorResponse, WebDriverResponse, WebDriverResult};
use crate::server::AppState;
#[derive(Debug, Deserialize)]
pub struct SwitchFrameRequest {
pub id: Value,
}
pub async fn switch_to_frame<R: Runtime + 'static>(
State(state): State<Arc<AppState<R>>>,
Path(session_id): Path<String>,
Json(request): Json<SwitchFrameRequest>,
) -> WebDriverResult {
let sessions = state.sessions.read().await;
let session = sessions.get(&session_id)?;
let current_window = session.current_window.clone();
let timeouts = session.timeouts.clone();
let current_frame_context = session.frame_context.clone();
let (frame_id, js_var_for_element) = match &request.id {
Value::Null => {
drop(sessions);
let mut sessions = state.sessions.write().await;
let session = sessions.get_mut(&session_id)?;
session.frame_context.clear();
return Ok(WebDriverResponse::null());
}
Value::Number(n) => {
let index = n.as_u64().ok_or_else(|| {
WebDriverErrorResponse::invalid_argument(
"Frame index must be a non-negative integer",
)
})?;
let index = u32::try_from(index)
.map_err(|_| WebDriverErrorResponse::invalid_argument("Frame index too large"))?;
(FrameId::Index(index), None)
}
Value::Object(obj) => {
if let Some(element_id) = obj.get("element-6066-11e4-a52e-4f735466cecf") {
let element_id = element_id.as_str().ok_or_else(|| {
WebDriverErrorResponse::invalid_argument("Element reference must be a string")
})?;
let element = session
.elements
.get(element_id)
.ok_or_else(WebDriverErrorResponse::no_such_element)?;
let js_var = element.js_ref.clone();
(FrameId::Element(js_var.clone()), Some(js_var))
} else {
return Err(WebDriverErrorResponse::invalid_argument(
"Invalid frame identifier object",
));
}
}
_ => {
return Err(WebDriverErrorResponse::invalid_argument(
"Frame ID must be null, a number, or an element reference",
));
}
};
drop(sessions);
let executor =
state.get_executor_for_window(¤t_window, timeouts, current_frame_context)?;
executor.switch_to_frame(frame_id.clone()).await?;
let mut sessions = state.sessions.write().await;
let session = sessions.get_mut(&session_id)?;
match &frame_id {
FrameId::Index(_) => {
session.frame_context.push(frame_id);
}
FrameId::Element(_) => {
if let Some(js_var) = js_var_for_element {
session.frame_context.push(FrameId::Element(js_var));
}
}
}
Ok(WebDriverResponse::null())
}
pub async fn switch_to_parent_frame<R: Runtime + 'static>(
State(state): State<Arc<AppState<R>>>,
Path(session_id): Path<String>,
) -> WebDriverResult {
let mut sessions = state.sessions.write().await;
let session = sessions.get_mut(&session_id)?;
session.frame_context.pop();
let current_window = session.current_window.clone();
let timeouts = session.timeouts.clone();
let frame_context = session.frame_context.clone();
drop(sessions);
let executor = state.get_executor_for_window(¤t_window, timeouts, frame_context)?;
executor.switch_to_parent_frame().await?;
Ok(WebDriverResponse::null())
}