add sse client for real-time backend events

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 12:21:42 +01:00
parent 1b24cb721a
commit e53a207583

View File

@@ -0,0 +1,67 @@
import Foundation
struct ServerEvent {
let id: String?
let event: String?
let data: String
}
@Observable
final class SSEClient {
private let url: URL
private var task: Task<Void, Never>?
var lastEvent: ServerEvent?
init(url: URL) {
self.url = url
}
func connect(onEvent: @escaping (ServerEvent) -> Void) {
task = Task {
do {
var request = URLRequest(url: url)
request.setValue("text/event-stream", forHTTPHeaderField: "Accept")
let (bytes, _) = try await URLSession.shared.bytes(for: request)
var currentEvent: String?
var currentData = ""
var currentId: String?
for try await line in bytes.lines {
if line.isEmpty {
if !currentData.isEmpty {
let event = ServerEvent(
id: currentId,
event: currentEvent,
data: currentData.trimmingCharacters(in: .newlines)
)
self.lastEvent = event
onEvent(event)
currentEvent = nil
currentData = ""
currentId = nil
}
} else if line.hasPrefix("data: ") {
currentData += String(line.dropFirst(6)) + "\n"
} else if line.hasPrefix("event: ") {
currentEvent = String(line.dropFirst(7))
} else if line.hasPrefix("id: ") {
currentId = String(line.dropFirst(4))
}
}
} catch {
if !Task.isCancelled {
try? await Task.sleep(for: .seconds(5))
connect(onEvent: onEvent)
}
}
}
}
func disconnect() {
task?.cancel()
task = nil
}
}