diff --git a/crates/lynx-core/src/proxy/https_proxy.rs b/crates/lynx-core/src/proxy/https_proxy.rs index 0a41f63..d24f5b8 100644 --- a/crates/lynx-core/src/proxy/https_proxy.rs +++ b/crates/lynx-core/src/proxy/https_proxy.rs @@ -67,7 +67,7 @@ pub async fn https_proxy( .serve_connection_with_upgrades(TokioIo::new(stream), service) .await { - error!("HTTPS proxy connect error: {}", err.to_string()); + error!("HTTPS proxy connect error: {:?}", err); } } Err(e) => { diff --git a/crates/lynx-core/src/self_service/mod.rs b/crates/lynx-core/src/self_service/mod.rs index f0f624a..609c0f3 100644 --- a/crates/lynx-core/src/self_service/mod.rs +++ b/crates/lynx-core/src/self_service/mod.rs @@ -15,14 +15,15 @@ use http_body_util::{BodyExt, StreamBody}; use hyper::body::{Frame, Incoming}; use hyper::{Request, Response}; use schemars::schema_for; -use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; +use sea_orm::{ColumnTrait, EntityTrait, ModelTrait, QueryFilter}; use tokio::fs::File; -use tokio_stream::wrappers::BroadcastStream; +use tokio_stream::wrappers::{BroadcastStream, ReadDirStream}; use tokio_util::io::ReaderStream; -use tracing::{debug, error}; +use tracing::{debug, error, trace}; +use tracing_subscriber::fmt::format; use utils::{ - internal_server_error, operation_error, parse_query_params, response_ok, validate_error, - OperationError, ValidateError, + internal_server_error, not_found, operation_error, parse_query_params, response_ok, + validate_error, OperationError, ValidateError, }; pub mod api; @@ -35,14 +36,17 @@ pub const RULE_GROUP_ADD: &str = "/__self_service_path__/rule_group/add"; pub const RULE_GROUP_UPDATE: &str = "/__self_service_path__/rule_group/update"; pub const RULE_GROUP_DELETE: &str = "/__self_service_path__/rule_group/delete"; pub const RULE_GROUP_LIST: &str = "/__self_service_path__/rule_group/list"; + pub const RULE_ADD: &str = "/__self_service_path__/rule/add"; pub const RULE_UPDATE: &str = "/__self_service_path__/rule/update"; pub const RULE_DELETE: &str = "/__self_service_path__/rule/delete"; pub const RULE_DETAIL: &str = "/__self_service_path__/rule"; pub const RULE_CONTEXT_SCHEMA: &str = "/__self_service_path__/rule/context/schema"; +pub const REQUEST_CLEAR: &str = "/__self_service_path__/request/clear"; pub const REQUEST_LOG: &str = "/__self_service_path__/request_log"; pub const REQUEST_BODY: &str = "/__self_service_path__/request_body"; + pub const RESPONSE: &str = "/__self_service_path__/response"; pub const RESPONSE_BODY: &str = "/__self_service_path__/response_body"; @@ -55,14 +59,15 @@ pub fn match_self_service(req: &Request) -> bool { req.uri().path().starts_with(SELF_SERVICE_PATH_PREFIX) } -pub async fn handle_self_service( +pub async fn self_service_router( req: Request, ) -> Result>> { let method = req.method(); let path = req.uri().path(); - debug!("handle_self_service: method: {:?}, path: {}", method, path); - let res = match (method, path) { + trace!("self_service_router: method: {:?}, path: {}", method, path); + + match (method, path) { (&method::Method::GET, HELLO_PATH) => { return Ok(Response::new(full(Bytes::from("Hello, World!")))); } @@ -143,6 +148,30 @@ pub async fn handle_self_service( return Ok(res); } + (&method::Method::POST, REQUEST_CLEAR) => { + trace!("clear request and response data"); + let db = DB.get().unwrap(); + request::Entity::delete_many().exec(db).await?; + response::Entity::delete_many().exec(db).await?; + + trace!("clear raw data"); + let raw_root_dir = &APP_CONFIG.get().unwrap().raw_root_dir; + trace!("clear raw data: {}", raw_root_dir.display()); + let entries = tokio::fs::read_dir(raw_root_dir) + .await + .map_err(|e| anyhow!(e).context(format!("clear raw data error")))?; + + let read_dir_stream = ReadDirStream::new(entries); + read_dir_stream + .for_each(|entry| async { + if let Ok(path) = entry { + let p = path.path(); + tokio::fs::remove_dir_all(p).await.unwrap(); + } + }) + .await; + return response_ok::>(None); + } (&method::Method::GET, RESPONSE) => { let params: HashMap = req .uri() @@ -304,8 +333,12 @@ pub async fn handle_self_service( return Ok(res); } - - (&method::Method::GET, path) if path.starts_with(SELF_SERVICE_PATH_PREFIX) => { + (&method::Method::GET, path) + if path == SELF_SERVICE_PATH_PREFIX + || path == &format!("{}/", SELF_SERVICE_PATH_PREFIX) + || path == &format!("{}/index.html", SELF_SERVICE_PATH_PREFIX) + || path == &format!("{}/static", SELF_SERVICE_PATH_PREFIX) => + { let mut static_path = &path[SELF_SERVICE_PATH_PREFIX.len()..]; if static_path.starts_with("/") { static_path = &static_path[1..]; @@ -331,7 +364,7 @@ pub async fn handle_self_service( let static_file = static_file; if static_file.is_err() { - return Err(anyhow!(OperationError::new("file not found".to_string()))); + return Ok(not_found()); } let static_file = static_file.unwrap(); @@ -347,14 +380,15 @@ pub async fn handle_self_service( } _ => { - let res = Response::builder() - .status(http::status::StatusCode::NOT_FOUND) - .header(CONTENT_TYPE, "text/plain") - .body(full(Bytes::from("Not Found"))) - .unwrap(); - return Ok(res); + return Ok(not_found()); } - }; + } +} + +pub async fn handle_self_service( + req: Request, +) -> Result>> { + let res = self_service_router(req).await; match res { Ok(res) => Ok(res), diff --git a/crates/lynx-core/src/self_service/utils/mod.rs b/crates/lynx-core/src/self_service/utils/mod.rs index 12250cf..9b0e6c4 100644 --- a/crates/lynx-core/src/self_service/utils/mod.rs +++ b/crates/lynx-core/src/self_service/utils/mod.rs @@ -10,7 +10,7 @@ use hyper::body::Incoming; use hyper::Response; use schemars::schema::RootSchema; -use crate::utils::full; +use crate::utils::{empty, full}; pub async fn parse_body_params(body: Incoming, schema: RootSchema) -> Result where @@ -143,7 +143,6 @@ where pub fn not_found() -> Response> { return Response::builder() .status(http::status::StatusCode::NOT_FOUND) - .header(CONTENT_TYPE, "text/plain") - .body(full(Bytes::from("Not Found"))) + .body(empty()) .unwrap(); } diff --git a/crates/lynx-proxy/src/App.tsx b/crates/lynx-proxy/src/App.tsx index cabf0f8..e684f18 100644 --- a/crates/lynx-proxy/src/App.tsx +++ b/crates/lynx-proxy/src/App.tsx @@ -7,7 +7,12 @@ import { import { StyleProvider } from '@ant-design/cssinjs'; import { routeTree } from './routeTree.gen'; import { ConfigProvider, theme } from 'antd'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { + MutationCache, + QueryCache, + QueryClient, + QueryClientProvider, +} from '@tanstack/react-query'; const hashHistory = createHashHistory(); // Set up a Router instance @@ -30,6 +35,16 @@ const queryClient = new QueryClient({ retry: false, }, }, + queryCache: new QueryCache({ + onError: (error) => { + console.log(error); + }, + }), + mutationCache: new MutationCache({ + onError: (error) => { + console.log(error); + }, + }), }); const App = () => { diff --git a/crates/lynx-proxy/src/api/app.ts b/crates/lynx-proxy/src/api/app.ts index a9b79f8..b16ff79 100644 --- a/crates/lynx-proxy/src/api/app.ts +++ b/crates/lynx-proxy/src/api/app.ts @@ -9,7 +9,7 @@ export const useChangeRecordStatus = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: ({ status }: { status: RecordStatusEnum }) => + mutationFn: async ({ status }: { status: RecordStatusEnum }) => fetch(`/__self_service_path__/app_config/record_status`, { method: 'POST', body: JSON.stringify({ status }), @@ -25,7 +25,7 @@ export const useChangeRecordStatus = () => { export const useGetAppConfig = () => { return useQuery({ queryKey: ['/__self_service_path__/app_config'], - queryFn: () => + queryFn: async () => fetch(`/__self_service_path__/app_config`).then( (res) => res.json() as Promise, ), diff --git a/crates/lynx-proxy/src/api/request.ts b/crates/lynx-proxy/src/api/request.ts index dd36ba4..f7dc8e0 100644 --- a/crates/lynx-proxy/src/api/request.ts +++ b/crates/lynx-proxy/src/api/request.ts @@ -1,6 +1,6 @@ import { message } from 'antd'; import { IRequestModel, IResponseBoxView } from './models'; -import { useQuery } from '@tanstack/react-query'; +import { useMutation, useQuery } from '@tanstack/react-query'; import queryString from 'query-string'; export function fetchRequest(cb: (data: { add: IRequestModel }) => void) { @@ -27,7 +27,7 @@ export function fetchRequest(cb: (data: { add: IRequestModel }) => void) { } const json = JSON.parse(line); console.log('json', json); - + cb(json); }); } catch (e) { @@ -43,7 +43,7 @@ export function fetchRequest(cb: (data: { add: IRequestModel }) => void) { export const useGetRequestBodyQuery = (params: { id?: number }) => { return useQuery({ queryKey: ['/__self_service_path__/request_body', params], - queryFn: () => + queryFn: async () => fetch( `/__self_service_path__/request_body?${queryString.stringify(params)}`, ).then((res) => res.blob().then((blob) => blob.arrayBuffer())), @@ -54,7 +54,7 @@ export const useGetRequestBodyQuery = (params: { id?: number }) => { export const useGetResponseQuery = (params: { requestId?: number }) => { return useQuery({ queryKey: ['/__self_service_path__/response', params], - queryFn: () => + queryFn: async () => fetch( `/__self_service_path__/response?${queryString.stringify(params)}`, ).then((res) => res.json() as Promise), @@ -65,9 +65,18 @@ export const useGetResponseQuery = (params: { requestId?: number }) => { export const useGetResponseBodyQuery = (params: { requestId?: number }) => { return useQuery({ queryKey: ['/__self_service_path__/response_body', params], - queryFn: () => + queryFn: async () => fetch( `/__self_service_path__/response_body?${queryString.stringify(params)}`, ).then((res) => res.blob().then((blob) => blob.arrayBuffer())), }); }; + +export const useClearRequestLog = () => { + return useMutation({ + mutationFn: async () => + fetch(`/__self_service_path__/request/clear`, { + method: 'POST', + }).then((res) => res.json()), + }); +}; diff --git a/crates/lynx-proxy/src/api/rule.ts b/crates/lynx-proxy/src/api/rule.ts index 8f07d15..ab99729 100644 --- a/crates/lynx-proxy/src/api/rule.ts +++ b/crates/lynx-proxy/src/api/rule.ts @@ -8,7 +8,7 @@ import queryString from 'query-string'; export const useGetRuleTreeQuery = () => { return useQuery({ queryKey: ['/__self_service_path__/rule_group/list'], - queryFn: () => + queryFn: async () => fetch(`/__self_service_path__/rule_group/list`).then( (res) => res.json() as Promise, ), @@ -18,7 +18,7 @@ export const useGetRuleTreeQuery = () => { export const useGetRuleDetailQuery = (params: { id?: number }) => { return useQuery({ queryKey: ['/__self_service_path__/rule', params], - queryFn: () => + queryFn: async () => fetch( `/__self_service_path__/rule?${queryString.stringify(params)}`, ).then((res) => res.json() as Promise), @@ -29,7 +29,7 @@ export const useGetRuleDetailQuery = (params: { id?: number }) => { export const useAddRuleGroup = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: (params: { name: string }) => + mutationFn: async (params: { name: string }) => fetch(`/__self_service_path__/rule_group/add`, { method: 'POST', body: JSON.stringify(params), diff --git a/crates/lynx-proxy/src/components/SideBar/index.tsx b/crates/lynx-proxy/src/components/SideBar/index.tsx index fad1660..301b0b4 100644 --- a/crates/lynx-proxy/src/components/SideBar/index.tsx +++ b/crates/lynx-proxy/src/components/SideBar/index.tsx @@ -7,7 +7,7 @@ export const SideBar: React.FC = (_props) => { const navigate = useNavigate(); return ( -
+
+ ); +}; diff --git a/crates/lynx-proxy/src/routes/network/components/RecordingStatusButton/index.tsx b/crates/lynx-proxy/src/routes/network/components/RecordingStatusButton/index.tsx index 513dfad..af52992 100644 --- a/crates/lynx-proxy/src/routes/network/components/RecordingStatusButton/index.tsx +++ b/crates/lynx-proxy/src/routes/network/components/RecordingStatusButton/index.tsx @@ -13,11 +13,11 @@ export const RecordingStatusButton: React.FC< const changeRecordStatus = useChangeRecordStatus(); const recordingStatus = appConfigData?.data?.recordingStatus; - console.log('recordingStatus',appConfigData, recordingStatus); return (
); }; diff --git a/crates/lynx-proxy/src/routes/network/components/Sequence/index.tsx b/crates/lynx-proxy/src/routes/network/components/Sequence/index.tsx index cb75bfa..145a2cd 100644 --- a/crates/lynx-proxy/src/routes/network/components/Sequence/index.tsx +++ b/crates/lynx-proxy/src/routes/network/components/Sequence/index.tsx @@ -2,18 +2,28 @@ import { Splitter } from 'antd'; import React from 'react'; import { Detail } from '../Detail'; import { RequestTable } from '../RequestTable'; +import { ShowTypeSegmented } from '../ShowTypeSegmented'; +import { Toolbar } from '../Toolbar'; interface ISequenceProps {} export const Sequence: React.FC = () => { return ( - - - - - - - - +
+
+ + +
+
+ + + + + + + + +
+
); }; diff --git a/crates/lynx-proxy/src/routes/network/components/Structure/index.tsx b/crates/lynx-proxy/src/routes/network/components/Structure/index.tsx index 6f92f37..356b91d 100644 --- a/crates/lynx-proxy/src/routes/network/components/Structure/index.tsx +++ b/crates/lynx-proxy/src/routes/network/components/Structure/index.tsx @@ -4,6 +4,7 @@ import { Detail } from '../Detail'; import { ShowTypeSegmented } from '../ShowTypeSegmented'; import { RequestTree } from '../RequestTree'; import { useSize } from 'ahooks'; +import { Toolbar } from '../Toolbar'; interface IStructureProps {} @@ -21,32 +22,37 @@ export const Structure: React.FC = () => { console.log(sizes, size); return ( -
- {size && ( - { - if (sizes[0] < 240) { - return; - } - setSizes(sizes); - }} - className="h-full bg-white" - layout="horizontal" - > - +
+ {size && ( + { + if (sizes[0] < 240) { + return; + } + setSizes(sizes); + }} + className="h-full bg-white" + layout="horizontal" > - - - - - - - - )} + + + + + +
+ + +
+
+ + )} +
); }; diff --git a/crates/lynx-proxy/src/routes/network/components/Toolbar/index.tsx b/crates/lynx-proxy/src/routes/network/components/Toolbar/index.tsx new file mode 100644 index 0000000..e472c9e --- /dev/null +++ b/crates/lynx-proxy/src/routes/network/components/Toolbar/index.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { RecordingStatusButton } from '../RecordingStatusButton'; +import { CleanRequestButton } from '../CleanRequestButton'; + +export const Toolbar: React.FC = () => { + return ( +
+ + +
+ ); +}; diff --git a/crates/lynx-proxy/src/routes/network/index.tsx b/crates/lynx-proxy/src/routes/network/index.tsx index 3a6c104..a2933ec 100644 --- a/crates/lynx-proxy/src/routes/network/index.tsx +++ b/crates/lynx-proxy/src/routes/network/index.tsx @@ -2,11 +2,9 @@ import { createFileRoute } from '@tanstack/react-router'; import { Sequence } from './components/Sequence'; import { Structure } from './components/Structure'; import { - ShowTypeSegmented, ShowTypeSegmentedStateContextProvider, - useShowTypeSegmentedStateContext, + useShowTypeSegmentedStateContext } from './components/ShowTypeSegmented'; -import { RecordingStatusButton } from './components/RecordingStatusButton'; import { UseSelectRequestProvider } from './components/store/selectRequestStore'; export const Route = createFileRoute('/network/')({ component: RouteComponent, @@ -17,22 +15,8 @@ function InnerComponent() { return (
- {state === 'Sequence' && ( -
-
- - -
-
- -
-
- )} - {state === 'Structure' && ( -
- -
- )} + {state === 'Sequence' && } + {state === 'Structure' && }
); } diff --git a/taskfile.yml b/taskfile.yml index e1c6bcb..dc17f57 100644 --- a/taskfile.yml +++ b/taskfile.yml @@ -1,5 +1,4 @@ version: "3" -output: prefixed tasks: dev: