tunnel/source/server/relay/pending.ts

64 lines
1.5 KiB
TypeScript
Raw Normal View History

2026-07-16 12:17:00 +00:00
export interface RelayResponse
{
reqId: string;
status: number;
2026-07-16 12:17:00 +00:00
headers: Record<string, string>;
body: string; // base64 — legacy single-shot
2026-07-16 12:17:00 +00:00
}
export type AgentMsg =
| { type: 'res_start'; reqId: string; status: number; headers: Record<string, string> }
| { type: 'res_data'; reqId: string; chunk: string } // base64
| { type: 'res_end'; reqId: string }
| RelayResponse; // legacy: no type field
2026-07-16 12:17:00 +00:00
export interface StreamHandler
2026-07-16 12:17:00 +00:00
{
onStart: ( status: number, headers: Record<string, string> ) => void;
onData: ( chunk: Buffer ) => void;
onEnd: () => void;
2026-07-16 12:17:00 +00:00
}
const pending = new Map<string, StreamHandler>();
export function addPending( reqId: string, handler: StreamHandler ): void
2026-07-16 12:17:00 +00:00
{
pending.set( reqId, handler );
2026-07-16 12:17:00 +00:00
}
export function removePending( reqId: string ): void
{
pending.delete( reqId );
}
export function dispatchAgentMsg( msg: AgentMsg ): void
{
const handler = pending.get( msg.reqId );
if ( !handler ) return;
if ( 'type' in msg )
{
if ( msg.type === 'res_start' )
{
handler.onStart( msg.status, msg.headers );
}
else if ( msg.type === 'res_data' )
{
handler.onData( Buffer.from( msg.chunk, 'base64' ) );
}
else if ( msg.type === 'res_end' )
{
pending.delete( msg.reqId );
handler.onEnd();
}
}
else
{
// Legacy single-shot RelayResponse — forward as stream
handler.onStart( msg.status, msg.headers );
handler.onData( Buffer.from( msg.body, 'base64' ) );
pending.delete( msg.reqId );
handler.onEnd();
}
2026-07-16 12:17:00 +00:00
}