use crate::{ db::{self, Update}, request::{ self, url::{RequestUrl, RequestUrlOwned, Segment, UrlError}, EntryRequestBody, HttpRequestParameters, HttpResponse, RequestBody, RequestHeader, RequestHeaderInsert, RequestHeaderUpdate, RequestPathParam, RequestPathUpdate, }, state::AppState, var::{expand_vars, parse_vars}, workspace::{ Workspace, WorkspaceEntry, WorkspaceEntryBase, WorkspaceEntryCreate, WorkspaceEntryUpdate, WorkspaceEntryUpdateBase, WorkspaceEnvVariable, WorkspaceEnvironment, }, }; use tauri_plugin_log::log; #[tauri::command] pub async fn list_workspaces(state: tauri::State<'_, AppState>) -> Result, String> { match db::list_workspaces(state.db.clone()).await { Ok(ws) => Ok(ws), Err(e) => Err(e.to_string()), } } #[tauri::command] pub async fn create_workspace( state: tauri::State<'_, AppState>, name: String, ) -> Result { match db::create_workspace(state.db.clone(), name).await { Ok(ws) => Ok(ws), Err(e) => Err(e.to_string()), } } #[tauri::command] pub async fn list_workspace_entries( state: tauri::State<'_, AppState>, id: i64, ) -> Result, String> { match db::list_workspace_entries(state.db.clone(), id).await { Ok(ws) => Ok(ws), Err(e) => Err(e.to_string()), } } #[tauri::command] pub async fn create_workspace_entry( state: tauri::State<'_, AppState>, data: WorkspaceEntryCreate, ) -> Result { match db::create_workspace_entry(state.db.clone(), data).await { Ok(ws) => Ok(ws), Err(e) => Err(e.to_string()), } } #[tauri::command] pub async fn update_workspace_entry( state: tauri::State<'_, AppState>, entry_id: i64, data: WorkspaceEntryUpdate, ) -> Result<(), String> { match db::update_workspace_entry(state.db.clone(), entry_id, data).await { Ok(()) => Ok(()), Err(e) => Err(e.to_string()), } } #[tauri::command] pub async fn insert_request_body( state: tauri::State<'_, AppState>, entry_id: i64, body: RequestBody, ) -> Result { match db::insert_request_body(state.db.clone(), entry_id, body).await { Ok(b) => Ok(b), Err(e) => return Err(e.to_string()), } } #[tauri::command] pub async fn update_request_body( state: tauri::State<'_, AppState>, id: i64, body: Update, ) -> Result<(), String> { if let Err(e) = db::update_request_body(state.db.clone(), id, body).await { return Err(e.to_string()); } Ok(()) } #[tauri::command] pub async fn parse_url(url: String) -> Result { match RequestUrl::parse(&url) { Ok(url_parsed) => Ok(url_parsed.into()), Err(e) => { log::debug!("{e:?}"); Err(UrlError::Parse(e)) } } } #[tauri::command] pub async fn expand_url( state: tauri::State<'_, AppState>, entry_id: i64, env_id: Option, mut url: String, ) -> Result { if let Some(env_id) = env_id { let vars = match parse_vars(&url) { Ok(vars) => vars.iter().map(|v| v.name).collect::>(), Err(e) => return Err(UrlError::Var(e.to_string())), }; if !vars.is_empty() { let vars = match db::get_env_variables(state.db.clone(), env_id, &vars).await { Ok(v) => v, Err(e) => return Err(UrlError::Db(e.to_string())), }; url = expand_vars(&url, &vars); } } match RequestUrl::parse(&url) { Ok(mut url) => { let params = match db::list_request_path_params(state.db.clone(), entry_id).await { Ok(p) => p, Err(e) => return Err(UrlError::Db(e.to_string())), }; url.populate_path( params .iter() .map(|p| (p.name.as_str(), p.value.as_str())) .collect(), ); let url = url.to_string(); let vars = match parse_vars(&url) { Ok(vars) => vars.iter().map(|v| v.name).collect::>(), Err(e) => return Err(UrlError::Var(e.to_string())), }; if vars.is_empty() { return Ok(url); } let Some(env_id) = env_id else { return Ok(url); }; let vars = match db::get_env_variables(state.db.clone(), env_id, &vars).await { Ok(v) => v, Err(e) => return Err(UrlError::Db(e.to_string())), }; Ok(expand_vars(&url.to_string(), &vars)) } Err(e) => { log::debug!("{e:?}"); Err(UrlError::Parse(e)) } } } /// Updates a URL. /// /// * `entry_id`: The request entry ID whose URL will be updated. /// * `env_id`: The environment to use for expanding variables. /// * `url`: The URL string which will be populated from the env and parsed with [RequestUrl]. /// * `path_params`: List of dynamic path params to persist for the URL. #[tauri::command] pub async fn update_url( state: tauri::State<'_, AppState>, entry_id: i64, use_path_params: bool, url: String, // Dynamic path params path_params: Vec, ) -> Result<(RequestUrlOwned, Vec), UrlError> { match RequestUrl::parse(&url) { Ok(mut url_parsed) => { let mut update: Vec = vec![]; let mut subs = vec![]; for seg in url_parsed.path.iter_mut() { if let Segment::Dynamic(seg, position) = seg { let Some(path_param) = path_params .iter() .find(|pp| pp.position as usize == *position || &pp.name == seg) else { update.push(RequestPathUpdate { position: *position, name: seg.to_string(), value: None, }); continue; }; if use_path_params { update.push(RequestPathUpdate { position: *position, name: path_param.name.clone(), value: Some(path_param.value.clone()), }); subs.push(Segment::Dynamic(&path_param.name, *position)); } else { update.push(RequestPathUpdate { position: *position, name: seg.to_string(), value: Some(path_param.value.clone()), }) } } } dbg!(&subs); for sub in subs { url_parsed.swap_path_segment(sub); } dbg!(&update, &url_parsed); db::update_workspace_entry( state.db.clone(), entry_id, WorkspaceEntryUpdate::Request { path_params: Some(update), url: Some(url_parsed.to_string()), base: WorkspaceEntryUpdateBase::default(), method: None, }, ) .await .map_err(|e| UrlError::Db(e.to_string()))?; let params = match db::list_request_path_params(state.db.clone(), entry_id).await { Ok(p) => p, Err(e) => return Err(UrlError::Db(e.to_string())), }; dbg!(&url_parsed, ¶ms); Ok((url_parsed.into(), params)) } Err(e) => { log::debug!("{e:?}"); Err(UrlError::Parse(e)) } } } #[tauri::command] pub async fn send_request( state: tauri::State<'_, AppState>, req_id: i64, env_id: Option, ) -> Result { let mut req = match db::get_workspace_request(state.db.clone(), req_id).await { Ok(req) => req, Err(e) => return Err(e.to_string()), }; req.url = if let Some(env_id) = env_id { let vars = match parse_vars(&req.url) { Ok(vars) => vars.iter().map(|v| v.name).collect::>(), Err(e) => return Err(e.to_string()), }; let vars = match db::get_env_variables(state.db.clone(), env_id, &vars).await { Ok(v) => v, Err(e) => return Err(e.to_string()), }; expand_vars(&req.url, &vars) } else { req.url }; let req = match RequestUrl::parse(&req.url.to_string()) { Ok(mut url) => { let params = match db::list_request_path_params(state.db.clone(), req_id).await { Ok(p) => p, Err(e) => return Err(e.to_string()), }; url.populate_path( params .iter() .map(|p| (p.name.as_str(), p.value.as_str())) .collect(), ); req.url = url.to_string(); let vars = match parse_vars(&req.url) { Ok(vars) => vars.iter().map(|v| v.name).collect::>(), Err(e) => return Err(e.to_string()), }; req.url = if let Some(env_id) = env_id { let vars = match db::get_env_variables(state.db.clone(), env_id, &vars).await { Ok(v) => v, Err(e) => return Err(e.to_string()), }; expand_vars(&url.to_string(), &vars) } else { req.url }; HttpRequestParameters::try_from(req)? } Err(e) => { log::debug!("{e:?}"); return Err(String::from("error parsing URL")); } }; let response = match request::send(state.client.clone(), req).await { Ok(res) => res, Err(e) => return Err(e.to_string()), }; Ok(response) } #[tauri::command] pub async fn list_environments( state: tauri::State<'_, AppState>, workspace_id: i64, ) -> Result, String> { match db::list_environments(state.db.clone(), workspace_id).await { Ok(ws) => Ok(ws), Err(e) => Err(e.to_string()), } } #[tauri::command] pub async fn create_env( state: tauri::State<'_, AppState>, workspace_id: i64, name: String, ) -> Result { match db::create_environment(state.db.clone(), workspace_id, name).await { Ok(ws) => Ok(ws), Err(e) => Err(e.to_string()), } } #[tauri::command] pub async fn update_env( state: tauri::State<'_, AppState>, id: i64, name: String, ) -> Result<(), String> { if let Err(e) = db::update_environment(state.db.clone(), id, name).await { return Err(e.to_string()); } Ok(()) } #[tauri::command] pub async fn insert_env_var( state: tauri::State<'_, AppState>, workspace_id: i64, env_id: i64, name: String, value: String, secret: bool, ) -> Result { match db::insert_env_var(state.db.clone(), workspace_id, env_id, name, value, secret).await { Ok(var) => Ok(var), Err(e) => Err(e.to_string()), } } #[tauri::command] pub async fn update_env_var( state: tauri::State<'_, AppState>, id: i64, name: Option, value: Option, secret: Option, ) -> Result<(), String> { if let Err(e) = db::update_env_var(state.db.clone(), id, name, value, secret).await { return Err(e.to_string()); } Ok(()) } #[tauri::command] pub async fn delete_env_var(state: tauri::State<'_, AppState>, id: i64) -> Result<(), String> { if let Err(e) = db::delete_env_var(state.db.clone(), id).await { return Err(e.to_string()); } Ok(()) } #[tauri::command] pub async fn insert_header( state: tauri::State<'_, AppState>, entry_id: i64, insert: RequestHeaderInsert, ) -> Result { match db::insert_headers(state.db.clone(), entry_id, vec![insert]).await { Ok(header) => Ok(header), Err(e) => return Err(e.to_string()), } } #[tauri::command] pub async fn update_header( state: tauri::State<'_, AppState>, update: RequestHeaderUpdate, ) -> Result<(), String> { if let Err(e) = db::update_header(state.db.clone(), update).await { return Err(e.to_string()); } Ok(()) } #[tauri::command] pub async fn delete_header( state: tauri::State<'_, AppState>, header_id: i64, ) -> Result<(), String> { if let Err(e) = db::delete_header(state.db.clone(), header_id).await { return Err(e.to_string()); } Ok(()) }