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

Commit2a1d50d

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

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
/**
@@ -378,6 +383,10 @@ export class Commands {
378383
}
379384

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

390-
awaitvscode.commands.executeCommand(
391-
"setContext",
392-
"coder.authenticated",
393-
false,
394-
);
399+
this.contextManager.set("coder.authenticated",false);
395400
vscode.window
396401
.showInformationMessage("You've been logged out of Coder!","Login")
397402
.then((action)=>{
@@ -402,6 +407,7 @@ export class Commands {
402407

403408
// This will result in clearing the workspace list.
404409
vscode.commands.executeCommand("coder.refreshWorkspaces");
410+
this.secretsManager.triggerLoginStateChange("logout");
405411
}
406412

407413
/**

‎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 {
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 {
3436
this.logger,
3537
this.pathResolver,
3638
);
39+
this.contextManager=newContextManager();
3740
}
3841

3942
getVsCodeProposed():typeofvscode{
@@ -60,10 +63,15 @@ export class ServiceContainer {
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
@@ -57,6 +57,7 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
5757
constoutput=serviceContainer.getLogger();
5858
constmementoManager=serviceContainer.getMementoManager();
5959
constsecretsManager=serviceContainer.getSecretsManager();
60+
constcontextManager=serviceContainer.getContextManager();
6061

6162
// Try to clear this flag ASAP
6263
constisFirstConnect=awaitmementoManager.getAndClearFirstConnect();
@@ -303,18 +304,21 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
303304
constremote=newRemote(serviceContainer,commands,ctx.extensionMode);
304305

305306
ctx.subscriptions.push(
306-
secretsManager.onDidChangeSessionToken(async()=>{
307-
consttoken=awaitsecretsManager.getSessionToken();
308-
consturl=mementoManager.getUrl();
309-
if(!token){
310-
output.info("Logging out");
311-
awaitcommands.forceLogout();
312-
}elseif(url){
313-
output.info("Logging in");
307+
secretsManager.onDidChangeLoginState(async(state)=>{
308+
if(state===undefined){
309+
// Initalization - Ignore those events
310+
return;
311+
}
312+
313+
if(state==="login"){
314+
consttoken=awaitsecretsManager.getSessionToken();
315+
consturl=mementoManager.getUrl();
314316
// Should login the user directly if the URL+Token are valid
315317
awaitcommands.login({ url, token});
316318
// Resolve any pending login detection promises
317319
remote.resolveLoginDetected();
320+
}else{
321+
awaitcommands.forceLogout();
318322
}
319323
}),
320324
);
@@ -384,20 +388,12 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
384388
output.info(`Logged in to${baseUrl}; checking credentials`);
385389
client
386390
.getAuthenticatedUser()
387-
.then(async(user)=>{
391+
.then((user)=>{
388392
if(user&&user.roles){
389393
output.info("Credentials are valid");
390-
vscode.commands.executeCommand(
391-
"setContext",
392-
"coder.authenticated",
393-
true,
394-
);
394+
contextManager.set("coder.authenticated",true);
395395
if(user.roles.find((role)=>role.name==="owner")){
396-
awaitvscode.commands.executeCommand(
397-
"setContext",
398-
"coder.isOwner",
399-
true,
400-
);
396+
contextManager.set("coder.isOwner",true);
401397
}
402398

403399
// Fetch and monitor workspaces, now that we know the client is good.
@@ -416,11 +412,11 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
416412
);
417413
})
418414
.finally(()=>{
419-
vscode.commands.executeCommand("setContext","coder.loaded",true);
415+
contextManager.set("coder.loaded",true);
420416
});
421417
}else{
422418
output.info("Not currently logged in");
423-
vscode.commands.executeCommand("setContext","coder.loaded",true);
419+
contextManager.set("coder.loaded",true);
424420

425421
// Handle autologin, if not already logged in.
426422
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
/**
@@ -548,6 +551,7 @@ export class Remote {
548551
workspaceClient,
549552
this.logger,
550553
this.vscodeProposed,
554+
this.contextManager,
551555
);
552556
disposables.push(monitor);
553557
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