78 lines
2.2 KiB
TypeScript
78 lines
2.2 KiB
TypeScript
import { BaseStream, type StreamMessage, type StreamResponse } from './base-stream.ts';
|
|
|
|
/**
|
|
* One-shot connection stream used to run normal HTTP through the route API.
|
|
*
|
|
* Sending stores a response until the handler returns; no bytes are committed
|
|
* early, so route errors can still replace it with the shared public error.
|
|
*/
|
|
export class HttpRequestStream extends BaseStream {
|
|
readonly streaming = false;
|
|
readonly bidirectional = false;
|
|
|
|
/** Buffered route response, committed only after dispatch completes. */
|
|
private response: StreamResponse | undefined;
|
|
|
|
/** Observers notified when the logical request ends. */
|
|
private readonly closeCallbacks: Array<() => void> = [];
|
|
|
|
/** Guards against sends after the request lifecycle ends. */
|
|
private closed = false;
|
|
|
|
/**
|
|
* Buffer exactly one route response for later HTTP encoding.
|
|
*
|
|
* @param message - Must be a response envelope, not an event.
|
|
*/
|
|
async send(message: StreamMessage): Promise<void> {
|
|
if (this.closed) {
|
|
throw new Error('Cannot send to a closed HTTP request');
|
|
}
|
|
|
|
if (!('body' in message)) {
|
|
throw new Error('Normal HTTP requests can only send a response');
|
|
}
|
|
|
|
if (this.response) {
|
|
throw new Error('Normal HTTP requests can only send one response');
|
|
}
|
|
|
|
this.response = message;
|
|
}
|
|
|
|
/**
|
|
* Return the buffered response for the transport adapter to encode.
|
|
*
|
|
* @returns The stored response, or undefined if the handler sent nothing.
|
|
*/
|
|
getResponse(): StreamResponse | undefined {
|
|
return this.response;
|
|
}
|
|
|
|
/** End the logical request and notify lifecycle observers. */
|
|
close(): void {
|
|
if (this.closed) {
|
|
return;
|
|
}
|
|
|
|
this.closed = true;
|
|
const callbacks = this.closeCallbacks.splice(0);
|
|
callbacks.forEach((callback) => callback());
|
|
}
|
|
|
|
/**
|
|
* Register a callback invoked when the request closes.
|
|
*
|
|
* @param callback - Called immediately if the request is already closed.
|
|
*/
|
|
onClose(callback: () => void): void {
|
|
if (this.closed) {
|
|
callback();
|
|
|
|
return;
|
|
}
|
|
|
|
this.closeCallbacks.push(callback);
|
|
}
|
|
}
|