feat(server): stream events across locations
This commit is contained in:
parent
57ce1b9ca8
commit
595cc91ddc
11 changed files with 2172 additions and 310 deletions
|
|
@ -1,34 +1,34 @@
|
|||
import { EventV2 } from "@opencode-ai/core/event"
|
||||
import { Location } from "@opencode-ai/core/location"
|
||||
import { Schema } from "effect"
|
||||
import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi"
|
||||
import { LocationQuery, locationQueryOpenApi, LocationMiddleware } from "./location"
|
||||
import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
|
||||
|
||||
const Event = Schema.Struct({
|
||||
id: EventV2.ID,
|
||||
type: Schema.String,
|
||||
location: Location.Info.pipe(Schema.optional),
|
||||
metadata: Schema.Record(Schema.String, Schema.Unknown).pipe(Schema.optional),
|
||||
version: Schema.Number.pipe(Schema.optional),
|
||||
data: Schema.Unknown,
|
||||
})
|
||||
const Event = Schema.Union([
|
||||
...EventV2.definitions().map((definition) =>
|
||||
Schema.Struct({
|
||||
...EventV2.Payload.fields,
|
||||
type: Schema.Literal(definition.type),
|
||||
data: definition.data,
|
||||
}).annotate({ identifier: `V2Event.${definition.type}` }),
|
||||
),
|
||||
Schema.Struct({
|
||||
...EventV2.Payload.fields,
|
||||
type: Schema.Literal("server.connected"),
|
||||
data: Schema.Struct({}),
|
||||
}).annotate({ identifier: "V2Event.server.connected" }),
|
||||
]).annotate({ identifier: "V2Event" })
|
||||
|
||||
export const EventGroup = HttpApiGroup.make("server.event")
|
||||
.add(
|
||||
HttpApiEndpoint.get("event.subscribe", "/api/event", {
|
||||
query: LocationQuery,
|
||||
success: Schema.String.pipe(HttpApiSchema.asText({ contentType: "text/event-stream" })),
|
||||
})
|
||||
.annotateMerge(locationQueryOpenApi)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "v2.event.subscribe",
|
||||
summary: "Subscribe to events",
|
||||
description: "Subscribe to native event payloads for a location.",
|
||||
}),
|
||||
),
|
||||
success: Event,
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "v2.event.subscribe",
|
||||
summary: "Subscribe to events",
|
||||
description: "Subscribe to native event payloads for the server.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
.annotateMerge(OpenApi.annotations({ title: "events", description: "Experimental event stream route." }))
|
||||
.middleware(LocationMiddleware)
|
||||
|
||||
export type Event = typeof Event.Type
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { EventV2 } from "@opencode-ai/core/event"
|
||||
import { Location } from "@opencode-ai/core/location"
|
||||
import { Effect, Stream } from "effect"
|
||||
import { HttpServerResponse } from "effect/unstable/http"
|
||||
import { HttpApiBuilder } from "effect/unstable/httpapi"
|
||||
|
|
@ -20,30 +19,14 @@ export const EventHandler = HttpApiBuilder.group(Api, "server.event", (handlers)
|
|||
const events = yield* EventV2.Service
|
||||
return handlers.handleRaw("event.subscribe", () =>
|
||||
Effect.gen(function* () {
|
||||
const location = yield* Location.Service
|
||||
const connected = {
|
||||
id: EventV2.ID.create(),
|
||||
type: "server.connected",
|
||||
location: new Location.Info({
|
||||
directory: location.directory,
|
||||
workspaceID: location.workspaceID,
|
||||
project: location.project,
|
||||
}),
|
||||
data: {},
|
||||
}
|
||||
return HttpServerResponse.stream(
|
||||
Stream.make(connected).pipe(
|
||||
Stream.concat(
|
||||
events
|
||||
.all()
|
||||
.pipe(
|
||||
Stream.filter(
|
||||
(event) =>
|
||||
event.location?.directory === location.directory &&
|
||||
event.location.workspaceID === location.workspaceID,
|
||||
),
|
||||
),
|
||||
),
|
||||
Stream.concat(events.all()),
|
||||
Stream.map(eventData),
|
||||
Stream.pipeThroughChannel(Sse.encode()),
|
||||
Stream.encodeText,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue