Skip to content

Commit 93e5f1a

Browse files
authored
Add support for connections to multiple deployments (#292)
1 parent 9437ad2 commit 93e5f1a

File tree

8 files changed

+494
-169
lines changed

8 files changed

+494
-169
lines changed

src/commands.ts

+33-9
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import * as vscode from "vscode"
55
import { makeCoderSdk } from "./api"
66
import { extractAgents } from "./api-helper"
77
import { CertificateError } from "./error"
8-
import { Remote } from "./remote"
98
import { Storage } from "./storage"
9+
import { AuthorityPrefix, toSafeHost } from "./util"
1010
import { OpenableTreeItem } from "./workspacesProvider"
1111

1212
export class Commands {
@@ -153,10 +153,13 @@ export class Commands {
153153
this.restClient.setHost(url)
154154
this.restClient.setSessionToken(token)
155155

156-
// Store these to be used in later sessions and in the cli.
156+
// Store these to be used in later sessions.
157157
await this.storage.setURL(url)
158158
await this.storage.setSessionToken(token)
159159

160+
// Store on disk to be used by the cli.
161+
await this.storage.configureCli(toSafeHost(url), url, token)
162+
160163
await vscode.commands.executeCommand("setContext", "coder.authenticated", true)
161164
if (user.roles.find((role) => role.name === "owner")) {
162165
await vscode.commands.executeCommand("setContext", "coder.isOwner", true)
@@ -197,6 +200,12 @@ export class Commands {
197200
* Log out from the currently logged-in deployment.
198201
*/
199202
public async logout(): Promise<void> {
203+
const url = this.storage.getUrl()
204+
if (!url) {
205+
// Sanity check; command should not be available if no url.
206+
throw new Error("You are not logged in")
207+
}
208+
200209
// Clear from the REST client. An empty url will indicate to other parts of
201210
// the code that we are logged out.
202211
this.restClient.setHost("")
@@ -206,6 +215,9 @@ export class Commands {
206215
await this.storage.setURL(undefined)
207216
await this.storage.setSessionToken(undefined)
208217

218+
// Clear from disk.
219+
await this.storage.configureCli(toSafeHost(url), undefined, undefined)
220+
209221
await vscode.commands.executeCommand("setContext", "coder.authenticated", false)
210222
vscode.window.showInformationMessage("You've been logged out of Coder!", "Login").then((action) => {
211223
if (action === "Login") {
@@ -272,13 +284,19 @@ export class Commands {
272284
/**
273285
* Open a workspace or agent that is showing in the sidebar.
274286
*
275-
* This essentially just builds the host name and passes it to the VS Code
276-
* Remote SSH extension, so it is not necessary to be logged in, although then
277-
* the sidebar would not have any workspaces in it anyway.
287+
* This builds the host name and passes it to the VS Code Remote SSH
288+
* extension.
289+
290+
* Throw if not logged into a deployment.
278291
*/
279292
public async openFromSidebar(treeItem: OpenableTreeItem) {
280293
if (treeItem) {
294+
const baseUrl = this.restClient.getAxiosInstance().defaults.baseURL
295+
if (!baseUrl) {
296+
throw new Error("You are not logged in")
297+
}
281298
await openWorkspace(
299+
baseUrl,
282300
treeItem.workspaceOwner,
283301
treeItem.workspaceName,
284302
treeItem.workspaceAgent,
@@ -291,7 +309,7 @@ export class Commands {
291309
/**
292310
* Open a workspace belonging to the currently logged-in deployment.
293311
*
294-
* This must only be called if logged into a deployment.
312+
* Throw if not logged into a deployment.
295313
*/
296314
public async open(...args: unknown[]): Promise<void> {
297315
let workspaceOwner: string
@@ -300,6 +318,11 @@ export class Commands {
300318
let folderPath: string | undefined
301319
let openRecent: boolean | undefined
302320

321+
const baseUrl = this.restClient.getAxiosInstance().defaults.baseURL
322+
if (!baseUrl) {
323+
throw new Error("You are not logged in")
324+
}
325+
303326
if (args.length === 0) {
304327
const quickPick = vscode.window.createQuickPick()
305328
quickPick.value = "owner:me "
@@ -411,7 +434,7 @@ export class Commands {
411434
openRecent = args[4] as boolean | undefined
412435
}
413436

414-
await openWorkspace(workspaceOwner, workspaceName, workspaceAgent, folderPath, openRecent)
437+
await openWorkspace(baseUrl, workspaceOwner, workspaceName, workspaceAgent, folderPath, openRecent)
415438
}
416439

417440
/**
@@ -439,9 +462,10 @@ export class Commands {
439462

440463
/**
441464
* Given a workspace, build the host name, find a directory to open, and pass
442-
* both to the Remote SSH plugin.
465+
* both to the Remote SSH plugin in the form of a remote authority URI.
443466
*/
444467
async function openWorkspace(
468+
baseUrl: string,
445469
workspaceOwner: string,
446470
workspaceName: string,
447471
workspaceAgent: string | undefined,
@@ -450,7 +474,7 @@ async function openWorkspace(
450474
) {
451475
// A workspace can have multiple agents, but that's handled
452476
// when opening a workspace unless explicitly specified.
453-
let remoteAuthority = `ssh-remote+${Remote.Prefix}${workspaceOwner}--${workspaceName}`
477+
let remoteAuthority = `ssh-remote+${AuthorityPrefix}.${toSafeHost(baseUrl)}--${workspaceOwner}--${workspaceName}`
454478
if (workspaceAgent) {
455479
remoteAuthority += `--${workspaceAgent}`
456480
}

src/extension.ts

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { Commands } from "./commands"
88
import { CertificateError, getErrorDetail } from "./error"
99
import { Remote } from "./remote"
1010
import { Storage } from "./storage"
11+
import { toSafeHost } from "./util"
1112
import { WorkspaceQuery, WorkspaceProvider } from "./workspacesProvider"
1213

1314
export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
@@ -108,6 +109,7 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
108109
// hit enter and move on.
109110
const url = await commands.maybeAskUrl(params.get("url"), storage.getUrl())
110111
if (url) {
112+
restClient.setHost(url)
111113
await storage.setURL(url)
112114
} else {
113115
throw new Error("url must be provided or specified as a query parameter")
@@ -117,9 +119,13 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
117119
// prompted to sign in again, so we do not need to ensure it is set.
118120
const token = params.get("token")
119121
if (token) {
122+
restClient.setSessionToken(token)
120123
await storage.setSessionToken(token)
121124
}
122125

126+
// Store on disk to be used by the cli.
127+
await storage.configureCli(toSafeHost(url), url, token)
128+
123129
vscode.commands.executeCommand("coder.open", owner, workspace, agent, folder, openRecent)
124130
}
125131
},

0 commit comments

Comments
 (0)