0.4.4
This commit is contained in:
226
kb_app/src/demo_http.rs
Normal file
226
kb_app/src/demo_http.rs
Normal file
@@ -0,0 +1,226 @@
|
||||
// file: kb_app/src/demo_http.rs
|
||||
|
||||
//! Tauri commands for the HTTP demo window.
|
||||
//!
|
||||
//! This module exposes a small manual test surface over the HTTP endpoint pool.
|
||||
|
||||
use tauri::Manager;
|
||||
|
||||
/// Request payload for one demo HTTP execution.
|
||||
#[derive(Clone, Debug, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct KbDemoHttpRequest {
|
||||
/// Logical role used to select one endpoint from the pool.
|
||||
pub role: std::string::String,
|
||||
/// JSON-RPC HTTP method name.
|
||||
pub method: std::string::String,
|
||||
/// Optional first string argument, used by methods such as
|
||||
/// `getBalance`, `getAccountInfo`, `getProgramAccounts`,
|
||||
/// `getSignaturesForAddress`, `getTransaction`, `sendTransaction`.
|
||||
pub first_arg: std::option::Option<std::string::String>,
|
||||
/// Optional JSON config payload encoded as a string.
|
||||
pub config_json: std::option::Option<std::string::String>,
|
||||
}
|
||||
|
||||
/// Response payload for one demo HTTP execution.
|
||||
#[derive(Clone, Debug, serde::Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct KbDemoHttpExecutionPayload {
|
||||
/// Selected endpoint name.
|
||||
pub endpoint_name: std::string::String,
|
||||
/// Selected endpoint provider.
|
||||
pub provider: std::string::String,
|
||||
/// Selected endpoint URL.
|
||||
pub endpoint_url: std::string::String,
|
||||
/// Requested role.
|
||||
pub role: std::string::String,
|
||||
/// Executed method name.
|
||||
pub method: std::string::String,
|
||||
/// Classified method family.
|
||||
pub method_class: std::string::String,
|
||||
/// Pretty-printed JSON response payload.
|
||||
pub response_json: std::string::String,
|
||||
}
|
||||
|
||||
/// Opens the dedicated HTTP demo window.
|
||||
#[tauri::command]
|
||||
pub(crate) fn open_demo_http_window(
|
||||
app_handle: tauri::AppHandle,
|
||||
) -> Result<(), std::string::String> {
|
||||
let existing_window_option = app_handle.get_webview_window("demo_http");
|
||||
|
||||
let demo_window = match existing_window_option {
|
||||
Some(demo_window) => demo_window,
|
||||
None => {
|
||||
let builder = tauri::WebviewWindowBuilder::new(
|
||||
&app_handle,
|
||||
"demo_http",
|
||||
tauri::WebviewUrl::App("demo_http.html".into()),
|
||||
)
|
||||
.title("Demo Http")
|
||||
.inner_size(1400.0, 768.0)
|
||||
.min_inner_size(800.0, 600.0)
|
||||
.center()
|
||||
.visible(true)
|
||||
.transparent(false)
|
||||
.decorations(true);
|
||||
let build_result = builder.build();
|
||||
match build_result {
|
||||
Ok(window) => window,
|
||||
Err(error) => {
|
||||
return Err(format!("cannot create demo_http window: {error:?}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let show_result = demo_window.show();
|
||||
if let Err(error) = show_result {
|
||||
return Err(format!("cannot show demo_http window: {error:?}"));
|
||||
}
|
||||
let focus_result = demo_window.set_focus();
|
||||
if let Err(error) = focus_result {
|
||||
return Err(format!("cannot focus demo_http window: {error:?}"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns a fresh snapshot of the HTTP endpoint pool.
|
||||
#[tauri::command]
|
||||
pub(crate) async fn demo_http_list_pool_clients(
|
||||
state: tauri::State<'_, crate::KbAppState>,
|
||||
) -> Result<std::vec::Vec<kb_lib::KbHttpPoolClientSnapshot>, std::string::String> {
|
||||
Ok(state.http_pool.snapshot().await)
|
||||
}
|
||||
|
||||
/// Executes one manual HTTP request through the endpoint pool.
|
||||
#[tauri::command]
|
||||
pub(crate) async fn demo_http_execute_request(
|
||||
state: tauri::State<'_, crate::KbAppState>,
|
||||
request: KbDemoHttpRequest,
|
||||
) -> Result<KbDemoHttpExecutionPayload, std::string::String> {
|
||||
let role = request.role.trim().to_string();
|
||||
if role.is_empty() {
|
||||
return Err("demo http role must not be empty".to_string());
|
||||
}
|
||||
let method = request.method.trim().to_string();
|
||||
if method.is_empty() {
|
||||
return Err("demo http method must not be empty".to_string());
|
||||
}
|
||||
let config_json_value_result = kb_parse_optional_demo_http_json(request.config_json);
|
||||
let config_json_value = match config_json_value_result {
|
||||
Ok(config_json_value) => config_json_value,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let params_result =
|
||||
kb_build_demo_http_params(&method, request.first_arg.as_deref(), config_json_value);
|
||||
let params = match params_result {
|
||||
Ok(params) => params,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let selected_client_result = state
|
||||
.http_pool
|
||||
.select_client_for_role_and_method(&role, &method)
|
||||
.await;
|
||||
let selected_client = match selected_client_result {
|
||||
Ok(selected_client) => selected_client,
|
||||
Err(error) => return Err(error.to_string()),
|
||||
};
|
||||
let method_class = kb_lib::HttpClient::classify_method(&method);
|
||||
let method_class_text = kb_demo_http_method_class_to_string(method_class);
|
||||
tracing::info!(
|
||||
endpoint_name = %selected_client.endpoint_name(),
|
||||
endpoint_url = %selected_client.endpoint_url(),
|
||||
role = %role,
|
||||
method = %method,
|
||||
method_class = %method_class_text,
|
||||
"executing demo http request"
|
||||
);
|
||||
let response_value_result = selected_client
|
||||
.execute_json_rpc_result_raw(method.clone(), params)
|
||||
.await;
|
||||
let response_value = match response_value_result {
|
||||
Ok(response_value) => response_value,
|
||||
Err(error) => return Err(error.to_string()),
|
||||
};
|
||||
let response_json_result = serde_json::to_string_pretty(&response_value);
|
||||
let response_json = match response_json_result {
|
||||
Ok(response_json) => response_json,
|
||||
Err(error) => {
|
||||
return Err(format!(
|
||||
"cannot pretty-print demo http response for method '{}': {}",
|
||||
method, error
|
||||
));
|
||||
}
|
||||
};
|
||||
Ok(KbDemoHttpExecutionPayload {
|
||||
endpoint_name: selected_client.endpoint_name().to_string(),
|
||||
provider: selected_client.endpoint_config().provider.clone(),
|
||||
endpoint_url: selected_client.endpoint_url().to_string(),
|
||||
role,
|
||||
method,
|
||||
method_class: method_class_text.to_string(),
|
||||
response_json,
|
||||
})
|
||||
}
|
||||
|
||||
fn kb_parse_optional_demo_http_json(
|
||||
config_json: std::option::Option<std::string::String>,
|
||||
) -> Result<std::option::Option<serde_json::Value>, std::string::String> {
|
||||
let config_json = match config_json {
|
||||
Some(config_json) => config_json.trim().to_string(),
|
||||
None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
if config_json.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
let value_result = serde_json::from_str::<serde_json::Value>(&config_json);
|
||||
match value_result {
|
||||
Ok(value) => Ok(Some(value)),
|
||||
Err(error) => Err(format!("invalid configJson: {}", error)),
|
||||
}
|
||||
}
|
||||
|
||||
fn kb_build_demo_http_params(
|
||||
method: &str,
|
||||
first_arg: std::option::Option<&str>,
|
||||
config_json: std::option::Option<serde_json::Value>,
|
||||
) -> Result<std::vec::Vec<serde_json::Value>, std::string::String> {
|
||||
let needs_first_arg = matches!(
|
||||
method,
|
||||
"getBalance"
|
||||
| "getAccountInfo"
|
||||
| "getProgramAccounts"
|
||||
| "getSignaturesForAddress"
|
||||
| "getTransaction"
|
||||
| "sendTransaction"
|
||||
);
|
||||
if needs_first_arg {
|
||||
let first_arg = match first_arg {
|
||||
Some(first_arg) => first_arg.trim(),
|
||||
None => "",
|
||||
};
|
||||
if first_arg.is_empty() {
|
||||
return Err(format!("method '{}' requires firstArg", method));
|
||||
}
|
||||
let mut params = vec![serde_json::Value::String(first_arg.to_string())];
|
||||
if let Some(config_json) = config_json {
|
||||
params.push(config_json);
|
||||
}
|
||||
return Ok(params);
|
||||
}
|
||||
let mut params = std::vec::Vec::new();
|
||||
if let Some(config_json) = config_json {
|
||||
params.push(config_json);
|
||||
}
|
||||
Ok(params)
|
||||
}
|
||||
|
||||
fn kb_demo_http_method_class_to_string(method_class: kb_lib::KbHttpMethodClass) -> &'static str {
|
||||
match method_class {
|
||||
kb_lib::KbHttpMethodClass::GeneralRpc => "GeneralRpc",
|
||||
kb_lib::KbHttpMethodClass::SendTransaction => "SendTransaction",
|
||||
kb_lib::KbHttpMethodClass::HeavyRead => "HeavyRead",
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user