// // SSEWriter.swift // Zyquo Router // // Author: Simon-Pierre Boucher // Mail: contact@spboucher.ai // // Spec-exact Server-Sent Events emission for /v1/chat/completions streaming: // each event is `data: \n\n`, the stream ends with `data: [DONE]\n\n`. // Every write flushes; a write against a disconnected client throws, which // cancels the calling route task and, with it, the upstream provider call. // import Foundation import NIOCore import NIOHTTP1 struct SSEWriter { let outbound: NIOAsyncChannelOutboundWriter private static let encoder: JSONEncoder = { let encoder = JSONEncoder() encoder.outputFormatting = [.withoutEscapingSlashes] return encoder }() /// Emits one `data:` event carrying an encodable payload (a chunk object). func send(_ payload: T) async throws { try await send(raw: Self.encoder.encode(payload)) } /// Emits one `data:` event carrying pre-serialized JSON (pass-through path). func send(raw json: Data) async throws { var buffer = ByteBuffer() buffer.writeString("data: ") buffer.writeBytes(json) buffer.writeString("\n\n") try await outbound.write(.body(.byteBuffer(buffer))) } /// Emits an SSE comment line (keep-alive heartbeat). func sendHeartbeat() async throws { try await outbound.write(.body(.byteBuffer(ByteBuffer(string: ": keep-alive\n\n")))) } /// Terminates the stream per the OpenAI contract. func sendDone() async throws { try await outbound.write(.body(.byteBuffer(ByteBuffer(string: "data: [DONE]\n\n")))) } }