Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfe96eb5

Browse files
committed
Introduce ContextManager to hold context state globally + Rely on secrets to propagate authentication events between windows
1 parent27569d2 commitfe96eb5

File tree

7 files changed

+99
-45
lines changed

7 files changed

+99
-45
lines changed

‎src/commands.ts‎

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { CoderApi } from "./api/coderApi";
1212
import{needToken}from"./api/utils";
1313
import{typeCliManager}from"./core/cliManager";
1414
import{typeServiceContainer}from"./core/container";
15+
import{typeContextManager}from"./core/contextManager";
1516
import{typeMementoManager}from"./core/mementoManager";
1617
import{typePathResolver}from"./core/pathResolver";
1718
import{typeSecretsManager}from"./core/secretsManager";
@@ -32,6 +33,7 @@ export class Commands {
3233
privatereadonlymementoManager:MementoManager;
3334
privatereadonlysecretsManager:SecretsManager;
3435
privatereadonlycliManager:CliManager;
36+
privatereadonlycontextManager:ContextManager;
3537
// These will only be populated when actively connected to a workspace and are
3638
// used in commands. Because commands can be executed by the user, it is not
3739
// possible to pass in arguments, so we have to store the current workspace
@@ -53,6 +55,7 @@ export class Commands {
5355
this.mementoManager=serviceContainer.getMementoManager();
5456
this.secretsManager=serviceContainer.getSecretsManager();
5557
this.cliManager=serviceContainer.getCliManager();
58+
this.contextManager=serviceContainer.getContextManager();
5659
}
5760

5861
/**
@@ -189,6 +192,11 @@ export class Commands {
189192
label?:string;
190193
autoLogin?:boolean;
191194
}):Promise<void>{
195+
if(this.contextManager.get("coder.authenticated")){
196+
return;
197+
}
198+
this.logger.info("Logging in");
199+
192200
consturl=awaitthis.maybeAskUrl(args?.url);
193201
if(!url){
194202
return;// The user aborted.
@@ -219,13 +227,9 @@ export class Commands {
219227
awaitthis.secretsManager.setSessionToken(res.token);
220228

221229
// These contexts control various menu items and the sidebar.
222-
awaitvscode.commands.executeCommand(
223-
"setContext",
224-
"coder.authenticated",
225-
true,
226-
);
230+
this.contextManager.set("coder.authenticated",true);
227231
if(res.user.roles.find((role)=>role.name==="owner")){
228-
awaitvscode.commands.executeCommand("setContext","coder.isOwner",true);
232+
this.contextManager.set("coder.isOwner",true);
229233
}
230234

231235
vscode.window
@@ -245,6 +249,7 @@ export class Commands {
245249

246250
// Fetch workspaces for the new deployment.
247251
vscode.commands.executeCommand("coder.refreshWorkspaces");
252+
this.secretsManager.triggerLoginStateChange("login");
248253
}
249254

250255
/**
@@ -376,6 +381,10 @@ export class Commands {
376381
}
377382

378383
publicasyncforceLogout():Promise<void>{
384+
if(!this.contextManager.get("coder.authenticated")){
385+
return;
386+
}
387+
this.logger.info("Logging out");
379388
// Clear from the REST client. An empty url will indicate to other parts of
380389
// the code that we are logged out.
381390
this.restClient.setHost("");
@@ -385,11 +394,7 @@ export class Commands {
385394
awaitthis.mementoManager.setUrl(undefined);
386395
awaitthis.secretsManager.setSessionToken(undefined);
387396

388-
awaitvscode.commands.executeCommand(
389-
"setContext",
390-
"coder.authenticated",
391-
false,
392-
);
397+
this.contextManager.set("coder.authenticated",false);
393398
vscode.window
394399
.showInformationMessage("You've been logged out of Coder!","Login")
395400
.then((action)=>{
@@ -400,6 +405,7 @@ export class Commands {
400405

401406
// This will result in clearing the workspace list.
402407
vscode.commands.executeCommand("coder.refreshWorkspaces");
408+
this.secretsManager.triggerLoginStateChange("logout");
403409
}
404410

405411
/**

‎src/core/container.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as vscode from "vscode";
33
import{typeLogger}from"../logging/logger";
44

55
import{CliManager}from"./cliManager";
6+
import{ContextManager}from"./contextManager";
67
import{MementoManager}from"./mementoManager";
78
import{PathResolver}from"./pathResolver";
89
import{SecretsManager}from"./secretsManager";
@@ -17,6 +18,7 @@ export class ServiceContainer implements vscode.Disposable {
1718
privatereadonlymementoManager:MementoManager;
1819
privatereadonlysecretsManager:SecretsManager;
1920
privatereadonlycliManager:CliManager;
21+
privatereadonlycontextManager:ContextManager;
2022

2123
constructor(
2224
context:vscode.ExtensionContext,
@@ -34,6 +36,7 @@ export class ServiceContainer implements vscode.Disposable {
3436
this.logger,
3537
this.pathResolver,
3638
);
39+
this.contextManager=newContextManager();
3740
}
3841

3942
getVsCodeProposed():typeofvscode{
@@ -60,10 +63,15 @@ export class ServiceContainer implements vscode.Disposable {
6063
returnthis.cliManager;
6164
}
6265

66+
getContextManager():ContextManager{
67+
returnthis.contextManager;
68+
}
69+
6370
/**
6471
* Dispose of all services and clean up resources.
6572
*/
6673
dispose():void{
74+
this.contextManager.dispose();
6775
this.logger.dispose();
6876
}
6977
}

‎src/core/contextManager.ts‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import*asvscodefrom"vscode";
2+
3+
constCONTEXT_DEFAULTS={
4+
"coder.authenticated":false,
5+
"coder.isOwner":false,
6+
"coder.loaded":false,
7+
"coder.workspace.updatable":false,
8+
}asconst;
9+
10+
typeCoderContext=keyoftypeofCONTEXT_DEFAULTS;
11+
12+
exportclassContextManagerimplementsvscode.Disposable{
13+
privatereadonlycontext=newMap<CoderContext,boolean>();
14+
15+
publicconstructor(){
16+
(Object.keys(CONTEXT_DEFAULTS)asCoderContext[]).forEach((key)=>{
17+
this.set(key,CONTEXT_DEFAULTS[key]);
18+
});
19+
}
20+
21+
publicset(key:CoderContext,value:boolean):void{
22+
this.context.set(key,value);
23+
vscode.commands.executeCommand("setContext",key,value);
24+
}
25+
26+
publicget(key:CoderContext):boolean{
27+
returnthis.context.get(key)??CONTEXT_DEFAULTS[key];
28+
}
29+
30+
publicdispose(){
31+
this.context.clear();
32+
}
33+
}

‎src/core/secretsManager.ts‎

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@ import type { SecretStorage, Disposable } from "vscode";
22

33
constSESSION_TOKEN_KEY="sessionToken";
44

5+
constLOGIN_STATE_KEY="loginState";
6+
7+
typeAuthAction="login"|"logout";
58
exportclassSecretsManager{
6-
constructor(privatereadonlysecrets:SecretStorage){}
9+
constructor(privatereadonlysecrets:SecretStorage){
10+
voidthis.secrets.delete(LOGIN_STATE_KEY);
11+
}
712

813
/**
914
* Set or unset the last used token.
@@ -29,13 +34,17 @@ export class SecretsManager {
2934
}
3035
}
3136

32-
/**
33-
* Subscribe to changes to the session token which can be used to indicate user login status.
34-
*/
35-
publiconDidChangeSessionToken(listener:()=>Promise<void>):Disposable{
36-
returnthis.secrets.onDidChange((e)=>{
37-
if(e.key===SESSION_TOKEN_KEY){
38-
listener();
37+
publictriggerLoginStateChange(action:AuthAction):void{
38+
this.secrets.store(LOGIN_STATE_KEY,action);
39+
}
40+
41+
publiconDidChangeLoginState(
42+
listener:(state?:AuthAction)=>Promise<void>,
43+
):Disposable{
44+
returnthis.secrets.onDidChange(async(e)=>{
45+
if(e.key===LOGIN_STATE_KEY){
46+
conststate=awaitthis.secrets.get(LOGIN_STATE_KEY);
47+
listener(stateasAuthAction|undefined);
3948
}
4049
});
4150
}

‎src/extension.ts‎

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
6262
constoutput=serviceContainer.getLogger();
6363
constmementoManager=serviceContainer.getMementoManager();
6464
constsecretsManager=serviceContainer.getSecretsManager();
65+
constcontextManager=serviceContainer.getContextManager();
6566

6667
// Try to clear this flag ASAP
6768
constisFirstConnect=awaitmementoManager.getAndClearFirstConnect();
@@ -331,18 +332,21 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
331332
constremote=newRemote(serviceContainer,commands,ctx.extensionMode);
332333

333334
ctx.subscriptions.push(
334-
secretsManager.onDidChangeSessionToken(async()=>{
335-
consttoken=awaitsecretsManager.getSessionToken();
336-
consturl=mementoManager.getUrl();
337-
if(!token){
338-
output.info("Logging out");
339-
awaitcommands.forceLogout();
340-
}elseif(url){
341-
output.info("Logging in");
335+
secretsManager.onDidChangeLoginState(async(state)=>{
336+
if(state===undefined){
337+
// Initalization - Ignore those events
338+
return;
339+
}
340+
341+
if(state==="login"){
342+
consttoken=awaitsecretsManager.getSessionToken();
343+
consturl=mementoManager.getUrl();
342344
// Should login the user directly if the URL+Token are valid
343345
awaitcommands.login({ url, token});
344346
// Resolve any pending login detection promises
345347
remote.resolveLoginDetected();
348+
}else{
349+
awaitcommands.forceLogout();
346350
}
347351
}),
348352
);
@@ -413,20 +417,12 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
413417
output.info(`Logged in to${baseUrl}; checking credentials`);
414418
client
415419
.getAuthenticatedUser()
416-
.then(async(user)=>{
420+
.then((user)=>{
417421
if(user&&user.roles){
418422
output.info("Credentials are valid");
419-
vscode.commands.executeCommand(
420-
"setContext",
421-
"coder.authenticated",
422-
true,
423-
);
423+
contextManager.set("coder.authenticated",true);
424424
if(user.roles.find((role)=>role.name==="owner")){
425-
awaitvscode.commands.executeCommand(
426-
"setContext",
427-
"coder.isOwner",
428-
true,
429-
);
425+
contextManager.set("coder.isOwner",true);
430426
}
431427

432428
// Fetch and monitor workspaces, now that we know the client is good.
@@ -445,11 +441,11 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
445441
);
446442
})
447443
.finally(()=>{
448-
vscode.commands.executeCommand("setContext","coder.loaded",true);
444+
contextManager.set("coder.loaded",true);
449445
});
450446
}else{
451447
output.info("Not currently logged in");
452-
vscode.commands.executeCommand("setContext","coder.loaded",true);
448+
contextManager.set("coder.loaded",true);
453449

454450
// Handle autologin, if not already logged in.
455451
constcfg=vscode.workspace.getConfiguration();

‎src/remote/remote.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { type Commands } from "../commands";
3030
import{typeCliManager}from"../core/cliManager";
3131
import*ascliUtilsfrom"../core/cliUtils";
3232
import{typeServiceContainer}from"../core/container";
33+
import{typeContextManager}from"../core/contextManager";
3334
import{typePathResolver}from"../core/pathResolver";
3435
import{featureSetForVersion,typeFeatureSet}from"../featureSet";
3536
import{getGlobalFlags}from"../globalFlags";
@@ -58,6 +59,7 @@ export class Remote {
5859
privatereadonlylogger:Logger;
5960
privatereadonlypathResolver:PathResolver;
6061
privatereadonlycliManager:CliManager;
62+
privatereadonlycontextManager:ContextManager;
6163

6264
// Used to race between the login dialog and the logging in from a different window
6365
privateloginDetectedResolver:(()=>void)|undefined;
@@ -73,6 +75,7 @@ export class Remote {
7375
this.logger=serviceContainer.getLogger();
7476
this.pathResolver=serviceContainer.getPathResolver();
7577
this.cliManager=serviceContainer.getCliManager();
78+
this.contextManager=serviceContainer.getContextManager();
7679
}
7780

7881
/**
@@ -545,6 +548,7 @@ export class Remote {
545548
workspaceClient,
546549
this.logger,
547550
this.vscodeProposed,
551+
this.contextManager,
548552
);
549553
disposables.push(monitor);
550554
disposables.push(

‎src/workspace/workspaceMonitor.ts‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as vscode from "vscode";
77

88
import{createWorkspaceIdentifier,errToStr}from"../api/api-helper";
99
import{typeCoderApi}from"../api/coderApi";
10+
import{typeContextManager}from"../core/contextManager";
1011
import{typeLogger}from"../logging/logger";
1112
import{typeOneWayWebSocket}from"../websocket/oneWayWebSocket";
1213

@@ -41,6 +42,7 @@ export class WorkspaceMonitor implements vscode.Disposable {
4142
privatereadonlylogger:Logger,
4243
// We use the proposed API to get access to useCustom in dialogs.
4344
privatereadonlyvscodeProposed:typeofvscode,
45+
privatereadonlycontextManager:ContextManager,
4446
){
4547
this.name=createWorkspaceIdentifier(workspace);
4648
constsocket=this.client.watchWorkspace(workspace);
@@ -217,11 +219,7 @@ export class WorkspaceMonitor implements vscode.Disposable {
217219
}
218220

219221
privateupdateContext(workspace:Workspace){
220-
vscode.commands.executeCommand(
221-
"setContext",
222-
"coder.workspace.updatable",
223-
workspace.outdated,
224-
);
222+
this.contextManager.set("coder.workspace.updatable",workspace.outdated);
225223
}
226224

227225
privateupdateStatusBar(workspace:Workspace){

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp