Skip to content

Commit 4954f9a

Browse files
sheche@microsoft.comsheche@microsoft.com
sheche@microsoft.com
authored and
sheche@microsoft.com
committed
better handle user status
1 parent fb64789 commit 4954f9a

File tree

6 files changed

+139
-103
lines changed

6 files changed

+139
-103
lines changed

src/commands/session.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
"use strict";
22

33
import * as vscode from "vscode";
4+
import { leetCodeManager } from "../leetCodeManager";
45
import { IQuickItemEx, leetCodeBinaryPath } from "../shared";
56
import * as cp from "../utils/cpUtils";
67
import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils";
7-
import { getSignedInAccount } from "./user";
88

99
export async function getSessionList(): Promise<ISession[]> {
10-
const signInStatus = await getSignedInAccount();
10+
const signInStatus = leetCodeManager.getUser();
1111
if (!signInStatus) {
1212
return [];
1313
}

src/commands/user.ts

-87
This file was deleted.

src/extension.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,15 @@
22

33
import * as vscode from "vscode";
44
import * as session from "./commands/session";
5-
import * as user from "./commands/user";
65
import { leetcodeChannel } from "./leetCodeChannel";
6+
import { leetCodeManager } from "./leetCodeManager";
77
import { leetCodeStatusBarItem } from "./leetCodeStatusBarItem";
88

99
export function activate(context: vscode.ExtensionContext) {
10-
const terminal: vscode.Terminal = vscode.window.createTerminal("LeetCode");
10+
leetCodeManager.getLoginStatus();
1111
context.subscriptions.push(
12-
terminal,
13-
vscode.commands.registerCommand("leetcode.signin", () => user.signIn()),
14-
vscode.commands.registerCommand("leetcode.signout", () => user.signOut()),
12+
vscode.commands.registerCommand("leetcode.signin", () => leetCodeManager.signIn()),
13+
vscode.commands.registerCommand("leetcode.signout", () => leetCodeManager.signOut()),
1514
vscode.commands.registerCommand("leetcode.selectSessions", () => session.selectSession()),
1615
);
1716
}

src/leetCodeManager.ts

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
"use strict";
2+
3+
import * as cp from "child_process";
4+
import { EventEmitter } from "events";
5+
import * as vscode from "vscode";
6+
import { leetcodeChannel } from "./leetCodeChannel";
7+
import { UserStatus } from "./shared";
8+
import { leetCodeBinaryPath } from "./shared";
9+
import { executeCommand } from "./utils/cpUtils";
10+
import { DialogType, promptForOpenOutputChannel } from "./utils/uiUtils";
11+
12+
export interface ILeetCodeManager extends EventEmitter {
13+
getLoginStatus(): void;
14+
getStatus(): UserStatus;
15+
getUser(): string | undefined;
16+
signIn(): void;
17+
signOut(): void;
18+
}
19+
20+
class LeetCodeManager extends EventEmitter implements ILeetCodeManager {
21+
private currentUser: string | undefined;
22+
private userStatus: UserStatus;
23+
24+
constructor() {
25+
super();
26+
this.currentUser = undefined;
27+
this.userStatus = UserStatus.SignedOut;
28+
}
29+
30+
public async getLoginStatus(): Promise<void> {
31+
try {
32+
const result = await executeCommand("node", [leetCodeBinaryPath, "user"]);
33+
this.currentUser = result.slice("You are now login as".length).trim();
34+
this.userStatus = UserStatus.SignedIn;
35+
} catch (error) {
36+
this.currentUser = undefined;
37+
this.userStatus = UserStatus.SignedOut;
38+
} finally {
39+
this.emit("statusChanged");
40+
}
41+
}
42+
43+
public async signIn(): Promise<void> {
44+
try {
45+
const userName: string | undefined = await new Promise(async (resolve: (res: string | undefined) => void, reject: (e: Error) => void): Promise<void> => {
46+
let result: string = "";
47+
const childProc: cp.ChildProcess = cp.spawn("node", [leetCodeBinaryPath, "user", "-l"]);
48+
childProc.stdout.on("data", (data: string | Buffer) => {
49+
data = data.toString();
50+
result = result.concat(data);
51+
leetcodeChannel.append(data);
52+
});
53+
54+
childProc.stderr.on("data", (data: string | Buffer) => leetcodeChannel.append(data.toString()));
55+
56+
childProc.on("error", reject);
57+
const name: string | undefined = await vscode.window.showInputBox({
58+
prompt: "Enter user name.",
59+
validateInput: (s: string) => s.trim() ? undefined : "User name must not be empty",
60+
});
61+
if (!name) {
62+
childProc.kill();
63+
resolve(undefined);
64+
}
65+
childProc.stdin.write(`${name}\n`);
66+
const pwd: string | undefined = await vscode.window.showInputBox({
67+
prompt: "Enter user name.",
68+
password: true,
69+
validateInput: (s: string) => s ? undefined : "Password must not be empty",
70+
});
71+
if (!pwd) {
72+
childProc.kill();
73+
resolve(undefined);
74+
}
75+
childProc.stdin.write(`${pwd}\n`);
76+
childProc.stdin.end();
77+
childProc.on("close", () => {
78+
const match: RegExpMatchArray | null = result.match(/(?:.*) Successfully login as (.*)/i);
79+
if (match && match[1]) {
80+
resolve(match[1]);
81+
} else {
82+
reject(new Error("Failed to sigin in."));
83+
}
84+
});
85+
});
86+
if (userName) {
87+
vscode.window.showInformationMessage("Successfully signed in.");
88+
this.currentUser = userName;
89+
this.userStatus = UserStatus.SignedIn;
90+
this.emit("statusChanged");
91+
}
92+
} catch (error) {
93+
promptForOpenOutputChannel("Failed to sign in. Please open the output channel for details", DialogType.error);
94+
}
95+
96+
}
97+
98+
public async signOut(): Promise<void> {
99+
try {
100+
await executeCommand("node", [leetCodeBinaryPath, "user", "-L"]);
101+
vscode.window.showInformationMessage("Successfully signed out.");
102+
this.currentUser = undefined;
103+
this.userStatus = UserStatus.SignedOut;
104+
this.emit("statusChanged");
105+
} catch (error) {
106+
promptForOpenOutputChannel("Failed to sign out. Please open the output channel for details", DialogType.error);
107+
}
108+
}
109+
110+
public getStatus(): UserStatus {
111+
return this.userStatus;
112+
}
113+
114+
public getUser(): string | undefined {
115+
return this.currentUser;
116+
}
117+
}
118+
119+
export const leetCodeManager: ILeetCodeManager = new LeetCodeManager();

src/leetCodeStatusBarItem.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
"use strict";
22

33
import * as vscode from "vscode";
4+
import { leetCodeManager } from "./leetCodeManager";
5+
import { UserStatus } from "./shared";
46

57
export interface ILeetCodeStatusBarItem {
6-
updateStatusBar(status: LeetCodeStatus, user?: string): void;
8+
updateStatusBar(status: UserStatus, user?: string): void;
79
dispose(): void;
810
}
911

@@ -13,15 +15,18 @@ class LeetCodeStatusBarItem implements ILeetCodeStatusBarItem {
1315
constructor() {
1416
this.statusBarItem = vscode.window.createStatusBarItem();
1517
this.statusBarItem.command = "leetcode.selectSessions";
18+
leetCodeManager.on("statusChanged", () => {
19+
leetCodeStatusBarItem.updateStatusBar(leetCodeManager.getStatus(), leetCodeManager.getUser());
20+
});
1621
}
1722

18-
public updateStatusBar(status: LeetCodeStatus, user?: string): void {
23+
public updateStatusBar(status: UserStatus, user?: string): void {
1924
switch (status) {
20-
case LeetCodeStatus.SignedIn:
25+
case UserStatus.SignedIn:
2126
this.statusBarItem.text = `LeetCode: ${user}`;
2227
this.statusBarItem.show();
2328
break;
24-
case LeetCodeStatus.SignedOut:
29+
case UserStatus.SignedOut:
2530
default:
2631
this.statusBarItem.hide();
2732
break;
@@ -33,9 +38,4 @@ class LeetCodeStatusBarItem implements ILeetCodeStatusBarItem {
3338
}
3439
}
3540

36-
export enum LeetCodeStatus {
37-
SignedIn = 1,
38-
SignedOut = 2,
39-
}
40-
4141
export const leetCodeStatusBarItem: ILeetCodeStatusBarItem = new LeetCodeStatusBarItem();

src/shared.ts

+5
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,8 @@ export const leetCodeBinaryPath: string = path.join(__dirname, "..", "..", "node
88
export interface IQuickItemEx<T> extends vscode.QuickPickItem {
99
value: T;
1010
}
11+
12+
export enum UserStatus {
13+
SignedIn = 1,
14+
SignedOut = 2,
15+
}

0 commit comments

Comments
 (0)