import { Context, Effect, Layer } from "effect"
import * as Log from "@opencode-ai/core/util/log"
import { Global } from "@opencode-ai/core/global"
import { LocalCrypto } from "@/security/local-crypto"
import { sessionChatIdMap } from "@/plugin/deveco"
import fs from "fs"
import path from "path"
const authFilePath = path.join(Global.Path.data, "auth.json")
function loadAccessTokenFromDisk(): string {
try {
if (!fs.existsSync(authFilePath)) return ""
const raw = JSON.parse(fs.readFileSync(authFilePath, "utf-8")) as Record<string, unknown>
const data = LocalCrypto.decryptAuthData(raw) as Record<string, unknown>
const deveco = data.deveco as Record<string, unknown> | undefined
if (deveco?.type === "oauth" && typeof deveco.access === "string") {
return deveco.access
}
} catch {
}
return ""
}
export interface Interface {
readonly exit: (sessionID: string, modelId: string) => Effect.Effect<void>
}
export class Service extends Context.Service<Service, Interface>()("@opencode/ExitQueue") {}
const log = Log.create({ service: "session.exit-queue" })
export const layer = Layer.effect(
Service,
Effect.gen(function* () {
const exit: Interface["exit"] = Effect.fn("ExitQueue.exit")(function* (
sessionID: string,
modelId: string,
) {
const chatId = sessionChatIdMap.get(sessionID)
const url = `https://cn.devecostudio.huawei.com/sse/codeGenie/exitSessionQueue?modelId=${encodeURIComponent(modelId)}`
const accessToken = loadAccessTokenFromDisk()
yield* Effect.tryPromise({
try: () =>
fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Session-Id": sessionID,
...(chatId ? { "Chat-Id": chatId } : {}),
...(accessToken ? { authorization: `Bearer ${accessToken}` } : {}),
},
}),
catch: (e) => {
log.error("failed to exit queue", { error: e })
},
}).pipe(Effect.timeout("5 seconds"), Effect.ignore)
})
return Service.of({ exit })
}),
)
export const defaultLayer = layer
export * as ExitQueue from "./exit-queue"