mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-09-07 18:31:49 +02:00
feat(send): link every response to the request version that produced it
HTTP snapshots in resolve_send_inputs, the last point in the pipeline that still holds the stored request — below it the request has been resolved against its folder and workspace and then rendered, and neither is what a restore should put back. Every host reaches sending through that function, so the desktop, the CLI and plugin-triggered sends all get versions without each knowing about them. gRPC and WebSocket connect do the same at their connection upserts. snapshot_request_for_send swallows its own errors: a send is not worth failing over history that couldn't be written, and an ephemeral request has no id to version. Either way the response just has no version to offer.
This commit is contained in:
@@ -40,6 +40,7 @@ use yaak_models::models::{
|
||||
CookieJar, Environment, GrpcConnection, GrpcConnectionState, GrpcEvent,
|
||||
GrpcEventType, HttpRequest, HttpResponse, HttpResponseState, Workspace,
|
||||
};
|
||||
use yaak_models::queries::any_request::AnyRequest;
|
||||
use yaak_models::util::{BatchUpsertResult, ImportDestination, ImportPlan, UpdateSource};
|
||||
use yaak_plugins::events::{
|
||||
Color, ErrorResponse, FilterResponse, InternalEvent, InternalEventPayload, PluginContext,
|
||||
@@ -330,6 +331,12 @@ async fn cmd_grpc_go<R: Runtime>(
|
||||
let settings = app_handle.db().get_settings();
|
||||
let client_cert = find_client_certificate(&request.url, &settings.client_certificates);
|
||||
|
||||
// Capture the stored request, not the rendered one: what a restore should
|
||||
// put back is what the user typed
|
||||
let version_id = app_handle
|
||||
.db()
|
||||
.snapshot_request_for_send(&AnyRequest::GrpcRequest(unrendered_request.clone()));
|
||||
|
||||
let conn = app_handle.db().upsert_grpc_connection(
|
||||
&GrpcConnection {
|
||||
workspace_id: request.workspace_id.clone(),
|
||||
@@ -338,6 +345,7 @@ async fn cmd_grpc_go<R: Runtime>(
|
||||
elapsed: 0,
|
||||
state: GrpcConnectionState::Initialized,
|
||||
url: request.url.clone(),
|
||||
version_id,
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
|
||||
@@ -20,6 +20,7 @@ use yaak_models::models::{
|
||||
HttpResponseHeader, WebsocketConnection, WebsocketConnectionState, WebsocketEvent,
|
||||
WebsocketEventType,
|
||||
};
|
||||
use yaak_models::queries::any_request::AnyRequest;
|
||||
use yaak_models::util::UpdateSource;
|
||||
use yaak_plugins::events::{CallHttpAuthenticationRequest, HttpHeader, RenderPurpose};
|
||||
use yaak_plugins::template_callback::PluginTemplateCallback;
|
||||
@@ -169,10 +170,17 @@ pub async fn cmd_ws_connect<R: Runtime>(
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Capture the stored request, not the rendered one: what a restore should
|
||||
// put back is what the user typed
|
||||
let version_id = app_handle
|
||||
.db()
|
||||
.snapshot_request_for_send(&AnyRequest::WebsocketRequest(unrendered_request.clone()));
|
||||
|
||||
let connection = app_handle.db().upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
workspace_id: request.workspace_id.clone(),
|
||||
request_id: request_id.to_string(),
|
||||
version_id,
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::models::{
|
||||
use crate::queries::any_request::AnyRequest;
|
||||
use crate::util::UpdateSource;
|
||||
use crate::versions::{apply_version_document, content_hash, version_document};
|
||||
use log::warn;
|
||||
use sea_query::{Expr, ExprTrait, Query, SqliteQueryBuilder};
|
||||
use sea_query_rusqlite::RusqliteBinder;
|
||||
|
||||
@@ -68,6 +69,24 @@ impl<'a> ClientDb<'a> {
|
||||
self.snapshot_request(&self.get_any_request(request_id)?, reason)
|
||||
}
|
||||
|
||||
/// What every send calls: capture the request, and don't make a fuss.
|
||||
///
|
||||
/// A send is not worth failing over history that couldn't be written, and
|
||||
/// a request with no id is ephemeral and has nothing to version. Either way
|
||||
/// the response just has no version to offer.
|
||||
pub fn snapshot_request_for_send(&self, request: &AnyRequest) -> Option<String> {
|
||||
if request.id().is_empty() {
|
||||
return None;
|
||||
}
|
||||
match self.snapshot_request(request, ModelVersionReason::Send) {
|
||||
Ok(version) => Some(version.id),
|
||||
Err(err) => {
|
||||
warn!("Failed to snapshot request before send: {err}");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a version's content back over the live request.
|
||||
///
|
||||
/// Anything the live request has picked up since its last version is
|
||||
|
||||
+18
-3
@@ -24,9 +24,10 @@ use yaak_http::types::{
|
||||
use yaak_models::blob_manager::{BlobManager, BodyChunk};
|
||||
use yaak_models::models::{
|
||||
ClientCertificate, Cookie, CookieJar, DnsOverride, Environment, HttpRequest, HttpResponse,
|
||||
HttpResponseEvent, HttpResponseEventData, HttpResponseHeader, HttpResponseState, ProxySetting,
|
||||
ProxySettingAuth, ResolvedHttpRequestSettings,
|
||||
HttpResponseEvent, HttpResponseEventData, HttpResponseHeader, HttpResponseState,
|
||||
ProxySetting, ProxySettingAuth, ResolvedHttpRequestSettings,
|
||||
};
|
||||
use yaak_models::queries::any_request::AnyRequest;
|
||||
use yaak_models::query_manager::QueryManager;
|
||||
use yaak_models::render::render_http_request;
|
||||
use yaak_models::util::{UpdateSource, generate_prefixed_id};
|
||||
@@ -283,6 +284,9 @@ pub struct HttpSendInputs {
|
||||
/// Cookies the send starts with. The store is shared, so reading it back after the send
|
||||
/// returns (or fails) yields the cookies the transaction collected.
|
||||
pub cookie_store: Option<CookieStore>,
|
||||
/// The version holding the request's content as it was when this send was resolved,
|
||||
/// which the response will point at. `None` for an ephemeral request with no id.
|
||||
pub version_id: Option<String>,
|
||||
}
|
||||
|
||||
/// Where a send writes its response. Without it, the send keeps everything in memory: no
|
||||
@@ -434,6 +438,13 @@ pub fn resolve_send_inputs(
|
||||
client_certificates: settings.client_certificates,
|
||||
},
|
||||
cookie_store: cookies.map(CookieStore::from_cookies),
|
||||
// Captured here rather than deeper in the send because this is the last place that
|
||||
// still holds the *stored* request: further down it has been resolved against its
|
||||
// folder and workspace and then rendered, and neither of those is what a restore
|
||||
// should put back. Every host reaches sending through this function — the desktop,
|
||||
// the CLI, plugin-triggered sends — so every response gets a version without each
|
||||
// of them remembering to ask for one.
|
||||
version_id: db.snapshot_request_for_send(&AnyRequest::HttpRequest(request.clone())),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -581,7 +592,8 @@ pub async fn send_http_request_by_id<T: TemplateCallback>(
|
||||
pub async fn send_http_request<T: TemplateCallback>(
|
||||
params: SendHttpRequestParams<'_, T>,
|
||||
) -> Result<SendHttpRequestResult> {
|
||||
let HttpSendInputs { request, environment_chain, runtime_config, cookie_store } = params.inputs;
|
||||
let HttpSendInputs { request, environment_chain, runtime_config, cookie_store, version_id } =
|
||||
params.inputs;
|
||||
let (request, auth_context_id) = request.into_parts();
|
||||
let storage = params.storage;
|
||||
let send_options = runtime_config.send_options();
|
||||
@@ -619,6 +631,7 @@ pub async fn send_http_request<T: TemplateCallback>(
|
||||
let mut response = params.existing_response.unwrap_or_default();
|
||||
response.request_id = request.id.clone();
|
||||
response.workspace_id = request.workspace_id.clone();
|
||||
response.version_id = version_id;
|
||||
response.request_content_length = request_content_length;
|
||||
response.request_headers = sendable_request
|
||||
.headers
|
||||
@@ -1345,6 +1358,7 @@ mod tests {
|
||||
client_certificates: Vec::new(),
|
||||
},
|
||||
cookie_store: Some(CookieStore::new()),
|
||||
version_id: None,
|
||||
},
|
||||
template_callback: &NoopTemplateCallback,
|
||||
storage: None,
|
||||
@@ -1414,6 +1428,7 @@ mod tests {
|
||||
client_certificates: Vec::new(),
|
||||
},
|
||||
cookie_store: Some(CookieStore::new()),
|
||||
version_id: None,
|
||||
},
|
||||
template_callback: &NoopTemplateCallback,
|
||||
storage: None,
|
||||
|
||||
Reference in New Issue
Block a user