share.ts 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import { Bus } from "../bus"
  2. import { Installation } from "../installation"
  3. import { Session } from "../session"
  4. import { MessageV2 } from "../session/message-v2"
  5. import { Log } from "../util/log"
  6. export namespace Share {
  7. const log = Log.create({ service: "share" })
  8. let queue: Promise<void> = Promise.resolve()
  9. const pending = new Map<string, any>()
  10. export async function sync(key: string, content: any) {
  11. if (disabled) return
  12. const [root, ...splits] = key.split("/")
  13. if (root !== "session") return
  14. const [sub, sessionID] = splits
  15. if (sub === "share") return
  16. const share = await Session.getShare(sessionID).catch(() => {})
  17. if (!share) return
  18. const { secret } = share
  19. pending.set(key, content)
  20. queue = queue
  21. .then(async () => {
  22. const content = pending.get(key)
  23. if (content === undefined) return
  24. pending.delete(key)
  25. return fetch(`${URL}/share_sync`, {
  26. method: "POST",
  27. body: JSON.stringify({
  28. sessionID: sessionID,
  29. secret,
  30. key: key,
  31. content,
  32. }),
  33. })
  34. })
  35. .then((x) => {
  36. if (x) {
  37. log.info("synced", {
  38. key: key,
  39. status: x.status,
  40. })
  41. }
  42. })
  43. }
  44. export function init() {
  45. Bus.subscribe(Session.Event.Updated, async (evt) => {
  46. await sync("session/info/" + evt.properties.info.id, evt.properties.info)
  47. })
  48. Bus.subscribe(MessageV2.Event.Updated, async (evt) => {
  49. await sync("session/message/" + evt.properties.info.sessionID + "/" + evt.properties.info.id, evt.properties.info)
  50. })
  51. Bus.subscribe(MessageV2.Event.PartUpdated, async (evt) => {
  52. await sync(
  53. "session/part/" +
  54. evt.properties.part.sessionID +
  55. "/" +
  56. evt.properties.part.messageID +
  57. "/" +
  58. evt.properties.part.id,
  59. evt.properties.part,
  60. )
  61. })
  62. }
  63. export const URL =
  64. process.env["OPENCODE_API"] ??
  65. (Installation.isPreview() || Installation.isLocal() ? "https://api.dev.opencode.ai" : "https://api.opencode.ai")
  66. const disabled = process.env["OPENCODE_DISABLE_SHARE"] === "true" || process.env["OPENCODE_DISABLE_SHARE"] === "1"
  67. export async function create(sessionID: string) {
  68. if (disabled) return { url: "", secret: "" }
  69. return fetch(`${URL}/share_create`, {
  70. method: "POST",
  71. body: JSON.stringify({ sessionID: sessionID }),
  72. })
  73. .then((x) => x.json())
  74. .then((x) => x as { url: string; secret: string })
  75. }
  76. export async function remove(sessionID: string, secret: string) {
  77. if (disabled) return {}
  78. return fetch(`${URL}/share_delete`, {
  79. method: "POST",
  80. body: JSON.stringify({ sessionID, secret }),
  81. }).then((x) => x.json())
  82. }
  83. }