From 67007b1f5cc82e273150005e283fccb341d8f70b Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Fri, 14 Apr 2023 13:50:41 -0700 Subject: [PATCH] Fix text encoding and delete responses --- src-tauri/sqlx-data.json | 100 +++++++++++++++++++++++++-- src-tauri/src/main.rs | 5 +- src-tauri/src/models.rs | 63 ++++++++++------- src-tauri/tauri.conf.json | 4 +- src-web/components/ResponsePane.tsx | 4 +- src-web/hooks/useLatestResponse.ts | 2 +- src-web/hooks/useResponseBodyText.ts | 3 +- 7 files changed, 146 insertions(+), 35 deletions(-) diff --git a/src-tauri/sqlx-data.json b/src-tauri/sqlx-data.json index 66284071..d7e2858e 100644 --- a/src-tauri/sqlx-data.json +++ b/src-tauri/sqlx-data.json @@ -58,15 +58,107 @@ }, "query": "\n DELETE FROM http_responses\n WHERE id = ?\n " }, - "0fa36011553f7ca91113459a5cefd47f990f9b548a95e475ffd6e4b017059488": { + "26072725d536c3cfdffd9a681d17c0ee2f246ca98e0459630a2430236d3bbdd2": { "describe": { - "columns": [], - "nullable": [], + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "model", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "workspace_id", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "request_id", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "updated_at", + "ordinal": 4, + "type_info": "Datetime" + }, + { + "name": "created_at", + "ordinal": 5, + "type_info": "Datetime" + }, + { + "name": "url", + "ordinal": 6, + "type_info": "Text" + }, + { + "name": "status", + "ordinal": 7, + "type_info": "Int64" + }, + { + "name": "status_reason", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "content_length", + "ordinal": 9, + "type_info": "Int64" + }, + { + "name": "body", + "ordinal": 10, + "type_info": "Blob" + }, + { + "name": "body_path", + "ordinal": 11, + "type_info": "Text" + }, + { + "name": "elapsed", + "ordinal": 12, + "type_info": "Int64" + }, + { + "name": "error", + "ordinal": 13, + "type_info": "Text" + }, + { + "name": "headers!: sqlx::types::Json>", + "ordinal": 14, + "type_info": "Text" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + true, + false + ], "parameters": { "Right": 1 } }, - "query": "\n DELETE FROM http_responses\n WHERE request_id = ?\n " + "query": "\n SELECT id, model, workspace_id, request_id, updated_at, created_at, url,\n status, status_reason, content_length, body, body_path, elapsed, error,\n headers AS \"headers!: sqlx::types::Json>\"\n FROM http_responses\n WHERE workspace_id = ?\n ORDER BY created_at DESC\n " }, "448a1d1f1866ab42c0f81fcf8eb2930bf21dfdd43ca4831bc1a198cf45ac3732": { "describe": { diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index f129d794..5a4ed8ba 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -9,6 +9,7 @@ extern crate objc; use std::collections::HashMap; use std::env::current_dir; +use std::fs; use std::fs::{create_dir_all, File}; use std::io::Write; @@ -225,7 +226,9 @@ async fn actually_send_ephemeral_request( let body_bytes = v.bytes().await.expect("Failed to get body").to_vec(); response.content_length = Some(body_bytes.len() as i64); let dir = app_handle.path_resolver().app_data_dir().unwrap(); - let body_path = dir.join(response.id.clone()); + let base_dir = dir.join("responses"); + create_dir_all(base_dir.clone()).expect("Failed to create responses dir"); + let body_path = base_dir.join(response.id.clone()); let mut f = File::options() .create(true) .write(true) diff --git a/src-tauri/src/models.rs b/src-tauri/src/models.rs index 32783eec..4f93252c 100644 --- a/src-tauri/src/models.rs +++ b/src-tauri/src/models.rs @@ -154,9 +154,7 @@ pub async fn get_workspace(id: &str, pool: &Pool) -> Result) -> Result { - let workspace = get_workspace(id, pool) - .await - .expect("Failed to get request to delete"); + let workspace = get_workspace(id, pool).await?; let _ = sqlx::query!( r#" DELETE FROM workspaces @@ -166,6 +164,11 @@ pub async fn delete_workspace(id: &str, pool: &Pool) -> Result) -> Result { - let existing = get_request(id, pool) - .await - .expect("Failed to get request to duplicate"); + let existing = get_request(id, pool).await?; // TODO: Figure out how to make this better let b2; @@ -289,8 +289,7 @@ pub async fn upsert_request( sort_priority, ) .execute(pool) - .await - .expect("Failed to insert new request"); + .await?; get_request(id, pool).await } @@ -354,9 +353,7 @@ pub async fn get_request(id: &str, pool: &Pool) -> Result) -> Result { - let req = get_request(id, pool) - .await - .expect("Failed to get request to delete"); + let req = get_request(id, pool).await?; let _ = sqlx::query!( r#" DELETE FROM http_requests @@ -367,6 +364,8 @@ pub async fn delete_request(id: &str, pool: &Pool) -> Result, pool: &Pool, ) -> Result { - let req = get_request(request_id, pool) - .await - .expect("Failed to get request"); + let req = get_request(request_id, pool).await?; let id = generate_id("rp"); let headers_json = Json(headers); sqlx::query!( @@ -417,8 +414,7 @@ pub async fn create_response( headers_json, ) .execute(pool) - .await - .expect("Failed to insert new response"); + .await?; get_response(&id, pool).await } @@ -447,8 +443,8 @@ pub async fn update_workspace( workspace.id, ) .execute(pool) - .await - .expect("Failed to update workspace"); + .await?; + get_workspace(&workspace.id, pool).await } @@ -484,8 +480,7 @@ pub async fn update_response( response.id, ) .execute(pool) - .await - .expect("Failed to update response"); + .await?; get_response(&response.id, pool).await } @@ -525,10 +520,28 @@ pub async fn find_responses( .await } +pub async fn find_responses_by_workspace_id( + workspace_id: &str, + pool: &Pool, +) -> Result, sqlx::Error> { + sqlx::query_as!( + HttpResponse, + r#" + SELECT id, model, workspace_id, request_id, updated_at, created_at, url, + status, status_reason, content_length, body, body_path, elapsed, error, + headers AS "headers!: sqlx::types::Json>" + FROM http_responses + WHERE workspace_id = ? + ORDER BY created_at DESC + "#, + workspace_id, + ) + .fetch_all(pool) + .await +} + pub async fn delete_response(id: &str, pool: &Pool) -> Result { - let resp = get_response(id, pool) - .await - .expect("Failed to get response to delete"); + let resp = get_response(id, pool).await?; // Delete the body file if it exists if let Some(p) = resp.body_path.clone() { diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 360f9ca4..7569c682 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -15,14 +15,14 @@ "allowlist": { "all": false, "protocol": { - "assetScope": ["$APPDATA/*"], + "assetScope": ["$APPDATA/responses/*"], "asset": true }, "fs": { "readFile": true, "scope": [ "$RESOURCE/*", - "$APPDATA/*" + "$APPDATA/responses/*" ] }, "shell": { diff --git a/src-web/components/ResponsePane.tsx b/src-web/components/ResponsePane.tsx index 1e2c8c53..d45f5ad5 100644 --- a/src-web/components/ResponsePane.tsx +++ b/src-web/components/ResponsePane.tsx @@ -5,6 +5,7 @@ import { createGlobalState } from 'react-use'; import { useActiveRequestId } from '../hooks/useActiveRequestId'; import { useDeleteResponse } from '../hooks/useDeleteResponse'; import { useDeleteResponses } from '../hooks/useDeleteResponses'; +import { useLatestResponse } from '../hooks/useLatestResponse'; import { useResponseContentType } from '../hooks/useResponseContentType'; import { useResponses } from '../hooks/useResponses'; import { useResponseViewMode } from '../hooks/useResponseViewMode'; @@ -38,10 +39,11 @@ const useActiveTab = createGlobalState('body'); export const ResponsePane = memo(function ResponsePane({ style, className }: Props) { const [pinnedResponseId, setPinnedResponseId] = useState(null); const activeRequestId = useActiveRequestId(); + const latestResponse = useLatestResponse(activeRequestId); const responses = useResponses(activeRequestId); const activeResponse: HttpResponse | null = pinnedResponseId ? responses.find((r) => r.id === pinnedResponseId) ?? null - : responses[0] ?? null; + : latestResponse ?? null; const [viewMode, setViewMode] = useResponseViewMode(activeResponse?.requestId); const deleteResponse = useDeleteResponse(activeResponse?.id ?? null); const deleteAllResponses = useDeleteResponses(activeResponse?.requestId); diff --git a/src-web/hooks/useLatestResponse.ts b/src-web/hooks/useLatestResponse.ts index b588b1ae..9f802715 100644 --- a/src-web/hooks/useLatestResponse.ts +++ b/src-web/hooks/useLatestResponse.ts @@ -3,5 +3,5 @@ import { useResponses } from './useResponses'; export function useLatestResponse(requestId: string | null): HttpResponse | null { const responses = useResponses(requestId); - return responses[responses.length - 1] ?? null; + return responses[0] ?? null; } diff --git a/src-web/hooks/useResponseBodyText.ts b/src-web/hooks/useResponseBodyText.ts index b69e54e3..5a70b03d 100644 --- a/src-web/hooks/useResponseBodyText.ts +++ b/src-web/hooks/useResponseBodyText.ts @@ -8,7 +8,8 @@ export function useResponseBodyText(response: HttpResponse) { initialData: null, queryFn: async () => { if (response.body) { - return String.fromCharCode.apply(null, response.body); + const uint8Array = Uint8Array.of(...response.body); + return new TextDecoder().decode(uint8Array); } if (response.bodyPath) {