mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-08-28 14:17:25 +02:00
Let the model layer default the response row; require requestId
This commit is contained in:
@@ -71,13 +71,11 @@ const HANDLERS: Partial<Record<AppCmd, Handler>> = {
|
|||||||
|
|
||||||
// The tab renders and stores; a stateless proxy puts the bytes on the wire.
|
// The tab renders and stores; a stateless proxy puts the bytes on the wire.
|
||||||
// See send.ts for the whole shape of it.
|
// See send.ts for the whole shape of it.
|
||||||
cmd_send_http_request: (payload, db) =>
|
cmd_send_http_request: (payload, db) => {
|
||||||
sendHttpRequest(
|
const requestId = str(payload, "requestId");
|
||||||
db,
|
if (requestId == null) throw new Error("cmd_send_http_request needs a requestId");
|
||||||
text(payload, "requestId"),
|
return sendHttpRequest(db, requestId, str(payload, "environmentId"), str(payload, "cookieJarId"));
|
||||||
str(payload, "environmentId"),
|
},
|
||||||
str(payload, "cookieJarId"),
|
|
||||||
),
|
|
||||||
|
|
||||||
/* -------------------------------- app ---------------------------------- */
|
/* -------------------------------- app ---------------------------------- */
|
||||||
|
|
||||||
|
|||||||
@@ -36,27 +36,36 @@ interface HttpResponseHeader {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The subset of the `http_response` model this sender writes. */
|
/**
|
||||||
|
* The fields of the `http_response` model this sender writes as a send
|
||||||
|
* progresses. Every one is optional: a field this file never sets takes the
|
||||||
|
* model layer's default, the same way the desktop's row does. Defaults live in
|
||||||
|
* Rust, once.
|
||||||
|
*/
|
||||||
interface ResponsePatch {
|
interface ResponsePatch {
|
||||||
|
state?: "initialized" | "connected" | "closed";
|
||||||
|
url?: string;
|
||||||
|
status?: number;
|
||||||
|
statusReason?: string | null;
|
||||||
|
version?: string | null;
|
||||||
|
remoteAddr?: string | null;
|
||||||
|
headers?: HttpResponseHeader[];
|
||||||
|
requestHeaders?: HttpResponseHeader[];
|
||||||
|
contentLength?: number | null;
|
||||||
|
contentLengthCompressed?: number | null;
|
||||||
|
elapsed?: number;
|
||||||
|
elapsedHeaders?: number;
|
||||||
|
elapsedDns?: number;
|
||||||
|
error?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The row itself: what identifies it, plus whatever has been written so far. */
|
||||||
|
type ResponseRow = {
|
||||||
model: "http_response";
|
model: "http_response";
|
||||||
id: string;
|
id?: string;
|
||||||
requestId: string;
|
requestId: string;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
state: "initialized" | "connected" | "closed";
|
} & ResponsePatch;
|
||||||
url: string;
|
|
||||||
status: number;
|
|
||||||
statusReason: string | null;
|
|
||||||
version: string | null;
|
|
||||||
remoteAddr: string | null;
|
|
||||||
headers: HttpResponseHeader[];
|
|
||||||
requestHeaders: HttpResponseHeader[];
|
|
||||||
contentLength: number | null;
|
|
||||||
contentLengthCompressed: number | null;
|
|
||||||
elapsed: number;
|
|
||||||
elapsedHeaders: number;
|
|
||||||
elapsedDns: number;
|
|
||||||
error: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CookieJarModel {
|
interface CookieJarModel {
|
||||||
model: "cookie_jar";
|
model: "cookie_jar";
|
||||||
@@ -88,26 +97,7 @@ export async function sendHttpRequest(
|
|||||||
// a failure to render or to reach the proxy lands in the response pane as
|
// a failure to render or to reach the proxy lands in the response pane as
|
||||||
// that response's error rather than as a toast that names no request.
|
// that response's error rather than as a toast that names no request.
|
||||||
const workspaceId = await workspaceIdOfRequest(db, requestId);
|
const workspaceId = await workspaceIdOfRequest(db, requestId);
|
||||||
const response = new ResponseWriter(db, {
|
const response = new ResponseWriter(db, { model: "http_response", requestId, workspaceId });
|
||||||
model: "http_response",
|
|
||||||
id: "",
|
|
||||||
requestId,
|
|
||||||
workspaceId,
|
|
||||||
state: "initialized",
|
|
||||||
url: "",
|
|
||||||
status: 0,
|
|
||||||
statusReason: null,
|
|
||||||
version: null,
|
|
||||||
remoteAddr: null,
|
|
||||||
headers: [],
|
|
||||||
requestHeaders: [],
|
|
||||||
contentLength: null,
|
|
||||||
contentLengthCompressed: null,
|
|
||||||
elapsed: 0,
|
|
||||||
elapsedHeaders: 0,
|
|
||||||
elapsedDns: 0,
|
|
||||||
error: null,
|
|
||||||
});
|
|
||||||
await response.create();
|
await response.create();
|
||||||
|
|
||||||
const cancel = new AbortController();
|
const cancel = new AbortController();
|
||||||
@@ -237,7 +227,7 @@ async function runSend(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function headOf(frame: ProxySendResponse): Partial<ResponsePatch> {
|
function headOf(frame: ProxySendResponse): ResponsePatch {
|
||||||
return {
|
return {
|
||||||
state: "connected",
|
state: "connected",
|
||||||
status: frame.status,
|
status: frame.status,
|
||||||
@@ -261,34 +251,34 @@ function headOf(frame: ProxySendResponse): Partial<ResponsePatch> {
|
|||||||
* `models_upsert`, so every tab on this database sees the response land.
|
* `models_upsert`, so every tab on this database sees the response land.
|
||||||
*/
|
*/
|
||||||
class ResponseWriter {
|
class ResponseWriter {
|
||||||
private state: ResponsePatch;
|
private state: ResponseRow;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly db: WorkerConnection,
|
private readonly db: WorkerConnection,
|
||||||
initial: ResponsePatch,
|
initial: ResponseRow,
|
||||||
) {
|
) {
|
||||||
this.state = initial;
|
this.state = initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
get id(): string {
|
get id(): string {
|
||||||
return this.state.id;
|
return this.state.id ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
get workspaceId(): string {
|
get workspaceId(): string {
|
||||||
return this.state.workspaceId;
|
return this.state.workspaceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
current(): ResponsePatch {
|
current(): ResponseRow {
|
||||||
return this.state;
|
return this.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Create the row. Everything but its identity is the model layer's default. */
|
||||||
async create(): Promise<void> {
|
async create(): Promise<void> {
|
||||||
const { id: _, ...withoutId } = this.state;
|
const id = await this.db.rpc<string>("models_upsert", { model: this.state });
|
||||||
const id = await this.db.rpc<string>("models_upsert", { model: withoutId });
|
|
||||||
this.state = { ...this.state, id };
|
this.state = { ...this.state, id };
|
||||||
}
|
}
|
||||||
|
|
||||||
async patch(patch: Partial<ResponsePatch>): Promise<void> {
|
async patch(patch: ResponsePatch): Promise<void> {
|
||||||
// Structured clone carries `undefined` across to the worker as a present
|
// Structured clone carries `undefined` across to the worker as a present
|
||||||
// key, and the model layer reads that as "wrong type" and refuses the whole
|
// key, and the model layer reads that as "wrong type" and refuses the whole
|
||||||
// model. Nothing here should produce one, but a missing wire field must
|
// model. Nothing here should produce one, but a missing wire field must
|
||||||
@@ -298,7 +288,7 @@ class ResponseWriter {
|
|||||||
await this.db.rpc("models_upsert", { model: this.state });
|
await this.db.rpc("models_upsert", { model: this.state });
|
||||||
}
|
}
|
||||||
|
|
||||||
async finish(patch: Partial<ResponsePatch>): Promise<void> {
|
async finish(patch: ResponsePatch): Promise<void> {
|
||||||
await this.patch({ ...patch, state: "closed" });
|
await this.patch({ ...patch, state: "closed" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user