Skip to content

Commit f73eaee

Browse files
feat: begin impl of coder inbox
Connect to Coder Inbox on /api/v2/notifications/watch to listen for notifications. Currently limit this to only show notifications for OOM/OOD notifications.
1 parent bbcd5fd commit f73eaee

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

src/inbox.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { Api } from "coder/site/src/api/api"
2+
import * as vscode from "vscode"
3+
import { WebSocket } from "ws"
4+
import { errToStr } from "./api-helper"
5+
import { Storage } from "./storage"
6+
7+
type InboxMessage = {
8+
unread_count: number
9+
notification: {
10+
id: string
11+
user_id: string
12+
template_id: string
13+
targets: string[]
14+
title: string
15+
content: string
16+
actions: {
17+
[key: string]: string
18+
}
19+
read_at: string
20+
created_at: string
21+
}
22+
}
23+
24+
const TemplateWorkspaceOutOfMemory = "a9d027b4-ac49-4fb1-9f6d-45af15f64e7a"
25+
const TemplateWorkspaceOutOfDisk = "f047f6a3-5713-40f7-85aa-0394cce9fa3a"
26+
27+
export class Inbox implements vscode.Disposable {
28+
private disposed = false
29+
private socket: WebSocket
30+
31+
constructor(
32+
private readonly restClient: Api,
33+
private readonly storage: Storage,
34+
) {
35+
// const url = this.restClient.getAxiosInstance().defaults.baseURL
36+
const token = this.restClient.getAxiosInstance().defaults.headers.common["Coder-Session-Token"] as
37+
| string
38+
| undefined
39+
// const inboxUrl = new URL(`${url}/api/v2/notifications/watch`);
40+
const inboxUrl = new URL(`ws://localhost:8080`)
41+
42+
this.storage.writeToCoderOutputChannel("Listening to Coder Inbox")
43+
44+
// We're gonna connect over WebSocket so replace the scheme.
45+
if (inboxUrl.protocol === "https") {
46+
inboxUrl.protocol = "wss"
47+
} else if (inboxUrl.protocol === "http") {
48+
inboxUrl.protocol = "ws"
49+
}
50+
51+
this.socket = new WebSocket(inboxUrl, {
52+
headers: {
53+
"Coder-Session-Token": token,
54+
},
55+
})
56+
57+
this.socket.on("error", (error) => {
58+
this.notifyError(error)
59+
})
60+
61+
this.socket.on("message", (data) => {
62+
try {
63+
const inboxMessage = JSON.parse(data.toString()) as InboxMessage
64+
65+
if (
66+
inboxMessage.notification.template_id === TemplateWorkspaceOutOfDisk ||
67+
inboxMessage.notification.template_id === TemplateWorkspaceOutOfMemory
68+
) {
69+
vscode.window.showWarningMessage(inboxMessage.notification.title)
70+
}
71+
} catch (error) {
72+
this.notifyError(error)
73+
}
74+
})
75+
}
76+
77+
dispose() {
78+
if (!this.disposed) {
79+
this.storage.writeToCoderOutputChannel("No longer listening to Coder Inbox")
80+
this.socket.close()
81+
this.disposed = true
82+
}
83+
}
84+
85+
private notifyError(error: unknown) {
86+
const message = errToStr(error, "Got empty error while monitoring Coder Inbox")
87+
this.storage.writeToCoderOutputChannel(message)
88+
}
89+
}

src/remote.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import * as cli from "./cliManager"
1515
import { Commands } from "./commands"
1616
import { featureSetForVersion, FeatureSet } from "./featureSet"
1717
import { getHeaderCommand } from "./headers"
18+
import { Inbox } from "./inbox"
1819
import { SSHConfig, SSHValues, mergeSSHConfigValues } from "./sshConfig"
1920
import { computeSSHProperties, sshSupportsSetEnv } from "./sshSupport"
2021
import { Storage } from "./storage"
@@ -403,6 +404,10 @@ export class Remote {
403404
disposables.push(monitor)
404405
disposables.push(monitor.onChange.event((w) => (this.commands.workspace = w)))
405406

407+
// Watch coder inbox for messages
408+
const inbox = new Inbox(workspaceRestClient, this.storage)
409+
disposables.push(inbox)
410+
406411
// Wait for the agent to connect.
407412
if (agent.status === "connecting") {
408413
this.storage.writeToCoderOutputChannel(`Waiting for ${workspaceName}/${agent.name}...`)

0 commit comments

Comments
 (0)