|
1 |
| -import { watch, stat, FileChangeInfo } from 'node:fs/promises'; |
| 1 | +import { watch, stat } from 'node:fs/promises'; |
2 | 2 | import os from 'node:os';
|
3 | 3 | import path from 'node:path';
|
| 4 | +import * as vscode from 'vscode'; |
4 | 5 | import { HerokuCommand } from '../heroku-command';
|
5 |
| -import { herokuCommand } from '../../meta/command'; |
| 6 | +import { herokuCommand, HerokuOutputChannel } from '../../meta/command'; |
| 7 | +import { createSessionObject } from '../../utils/create-session-object'; |
| 8 | +import { TokenCommand } from './token'; |
| 9 | +import { WhoAmI } from './whoami'; |
6 | 10 |
|
7 |
| -@herokuCommand() |
| 11 | +@herokuCommand({ outputChannelId: HerokuOutputChannel.Authentication }) |
8 | 12 | /**
|
9 | 13 | * Command that creates a watcher for the .netrc file.
|
10 | 14 | */
|
11 |
| -export class WatchNetrc extends HerokuCommand<AsyncIterable<FileChangeInfo<string>>> { |
| 15 | +export class WatchNetrc extends HerokuCommand< |
| 16 | + AsyncIterable<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent> |
| 17 | +> { |
12 | 18 | public static COMMAND_ID = 'heroku:watchnetrc' as const;
|
13 | 19 |
|
14 | 20 | /**
|
@@ -50,10 +56,44 @@ export class WatchNetrc extends HerokuCommand<AsyncIterable<FileChangeInfo<strin
|
50 | 56 | * terminal to sign in or out.
|
51 | 57 | *
|
52 | 58 | * @param signal The abort signal used to stop the watcher.
|
| 59 | + * @param context The extension context used to store and retrieve secrets. |
| 60 | + * @param sessionKey The key used to read and store the session. |
53 | 61 | * @returns a Promise that resolves to an AsyncIterable which will contain file change info on each await.
|
54 | 62 | */
|
55 |
| - public async run(signal: AbortSignal): Promise<AsyncIterable<FileChangeInfo<string>>> { |
| 63 | + public async run( |
| 64 | + signal: AbortSignal, |
| 65 | + context: vscode.ExtensionContext, |
| 66 | + sessionKey: string |
| 67 | + ): Promise<AsyncIterable<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent>> { |
56 | 68 | const file = await WatchNetrc.getNetrcFileLocation();
|
57 |
| - return watch(file, { signal }); |
| 69 | + const iterator = watch(file, { signal }); |
| 70 | + const outputChannel = this.outputChannel as vscode.OutputChannel; |
| 71 | + |
| 72 | + return (async function* (): AsyncGenerator<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent> { |
| 73 | + for await (const event of iterator) { |
| 74 | + if (event.eventType !== 'change') { |
| 75 | + continue; |
| 76 | + } |
| 77 | + |
| 78 | + const accessToken = await vscode.commands.executeCommand<string>(TokenCommand.COMMAND_ID); |
| 79 | + if (!accessToken) { |
| 80 | + const sessionJson = await context.secrets.get(sessionKey); |
| 81 | + if (sessionJson) { |
| 82 | + await context.secrets.delete(sessionKey); |
| 83 | + const session = JSON.parse(sessionJson) as vscode.AuthenticationSession; |
| 84 | + await vscode.commands.executeCommand('setContext', 'heroku.authenticated', false); |
| 85 | + outputChannel.appendLine(`${session.account.label} signed out of Heroku`); |
| 86 | + yield { added: undefined, removed: [session], changed: undefined }; |
| 87 | + } |
| 88 | + } else { |
| 89 | + const whoami = await vscode.commands.executeCommand<string>(WhoAmI.COMMAND_ID); |
| 90 | + const session = createSessionObject(whoami, accessToken, []); |
| 91 | + await context.secrets.store(sessionKey, JSON.stringify(session)); |
| 92 | + await vscode.commands.executeCommand('setContext', 'heroku.authenticated', true); |
| 93 | + outputChannel.appendLine(`Logged in to Heroku as ${whoami}`); |
| 94 | + yield { added: [session], removed: undefined, changed: undefined }; |
| 95 | + } |
| 96 | + } |
| 97 | + })(); |
58 | 98 | }
|
59 | 99 | }
|
0 commit comments