From e20cf5c1183c563fd62be020c46768d616df9a4d Mon Sep 17 00:00:00 2001 From: Vinicius Fortuna Date: Tue, 23 Mar 2021 23:12:22 -0400 Subject: [PATCH 1/6] Use Account ids --- src/server_manager/model/digitalocean.ts | 2 ++ src/server_manager/web_app/app.ts | 25 +++++++++++-------- src/server_manager/web_app/cloud_accounts.ts | 2 +- .../web_app/digitalocean_account.ts | 9 +++++-- .../web_app/digitalocean_server.ts | 5 ++-- src/server_manager/web_app/manual_server.ts | 7 +++--- src/server_manager/web_app/testing/models.ts | 4 +++ .../web_app/ui_components/app-root.js | 8 +++--- 8 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/server_manager/model/digitalocean.ts b/src/server_manager/model/digitalocean.ts index 79fc3cde4..650c12881 100644 --- a/src/server_manager/model/digitalocean.ts +++ b/src/server_manager/model/digitalocean.ts @@ -26,6 +26,8 @@ export enum Status { } export interface Account { + // Returns the Account's unique id. + getId(): string; // Returns a user-friendly name (email address) associated with the account. getName(): Promise; // Returns the status of the account. diff --git a/src/server_manager/web_app/app.ts b/src/server_manager/web_app/app.ts index 781fdaa70..d2387ded1 100644 --- a/src/server_manager/web_app/app.ts +++ b/src/server_manager/web_app/app.ts @@ -347,7 +347,7 @@ export class App { } const servers = await this.digitalOceanAccount.listServers(); for (const server of servers) { - this.addServer(server); + this.addServer(this.digitalOceanAccount.getId(), server); } return servers; } catch (error) { @@ -360,15 +360,15 @@ export class App { private async loadManualServers() { for (const server of await this.manualServerRepository.listServers()) { - this.addServer(server); + this.addServer(null, server); } } - private makeServerListEntry(server: server.Server): ServerListEntry { + private makeServerListEntry(accountId: string, server: server.Server): ServerListEntry { return { id: server.getId(), + accountId, name: this.makeDisplayName(server), - isManaged: isManagedServer(server), isSynced: !!server.getName(), }; } @@ -384,10 +384,10 @@ export class App { return name; } - private addServer(server: server.Server): void { + private addServer(accountId: string, server: server.Server): void { console.log('Loading server', server); this.idServerMap.set(server.getId(), server); - const serverEntry = this.makeServerListEntry(server); + const serverEntry = this.makeServerListEntry(accountId, server); this.appRoot.serverList = this.appRoot.serverList.concat([serverEntry]); if (isManagedServer(server) && !server.isInstallCompleted()) { @@ -428,7 +428,7 @@ export class App { private updateServerEntry(server: server.Server): void { this.appRoot.serverList = this.appRoot.serverList.map( - (ds) => ds.id === server.getId() ? this.makeServerListEntry(server) : ds); + (ds) => ds.id === server.getId() ? this.makeServerListEntry(ds.accountId, server) : ds); } private getServerById(serverId: string): server.Server { @@ -607,10 +607,15 @@ export class App { // Clears the DigitalOcean credentials and returns to the intro screen. private disconnectDigitalOceanAccount(): void { + if (!this.digitalOceanAccount) { + // Not connected. + return; + } + const accountId = this.digitalOceanAccount.getId(); this.cloudAccounts.disconnectDigitalOceanAccount(); this.digitalOceanAccount = null; for (const serverEntry of this.appRoot.serverList) { - if (serverEntry.isManaged) { + if (serverEntry.accountId === accountId) { this.removeServer(serverEntry.id); } } @@ -665,7 +670,7 @@ export class App { const server = await this.digitalOceanRetry(() => { return this.digitalOceanAccount.createServer(regionId, serverName); }); - this.addServer(server); + this.addServer(this.digitalOceanAccount.getId(), server); this.showServer(server); } catch (error) { console.error('Error from createDigitalOceanServer', error); @@ -1050,7 +1055,7 @@ export class App { } const manualServer = await this.manualServerRepository.addServer(serverConfig); if (await manualServer.isHealthy()) { - this.addServer(manualServer); + this.addServer(null, manualServer); this.showServer(manualServer); } else { // Remove inaccessible manual server from local storage if it was just created. diff --git a/src/server_manager/web_app/cloud_accounts.ts b/src/server_manager/web_app/cloud_accounts.ts index 6f3104914..1f1f85f4d 100644 --- a/src/server_manager/web_app/cloud_accounts.ts +++ b/src/server_manager/web_app/cloud_accounts.ts @@ -119,7 +119,7 @@ export class CloudAccounts implements accounts.CloudAccounts { } private createDigitalOceanAccount(accessToken: string): DigitalOceanAccount { - return new DigitalOceanAccount(accessToken, this.shadowboxSettings, this.isDebugMode); + return new DigitalOceanAccount('do', accessToken, this.shadowboxSettings, this.isDebugMode); } private createGcpAccount(refreshToken: string): GcpAccount { diff --git a/src/server_manager/web_app/digitalocean_account.ts b/src/server_manager/web_app/digitalocean_account.ts index a4624f16b..8670a2d22 100644 --- a/src/server_manager/web_app/digitalocean_account.ts +++ b/src/server_manager/web_app/digitalocean_account.ts @@ -36,11 +36,15 @@ export class DigitalOceanAccount implements digitalocean.Account { private servers: DigitalOceanServer[] = []; constructor( - private accessToken: string, private shadowboxSettings: ShadowboxSettings, + private id: string, private accessToken: string, private shadowboxSettings: ShadowboxSettings, private debugMode: boolean) { this.digitalOcean = new RestApiSession(accessToken); } + getId(): string { + return this.id; + } + async getName(): Promise { return (await this.digitalOcean.getAccount())?.email; } @@ -121,7 +125,8 @@ export class DigitalOceanAccount implements digitalocean.Account { // Creates a DigitalOceanServer object and adds it to the in-memory server list. private createDigitalOceanServer(digitalOcean: DigitalOceanSession, dropletInfo: DropletInfo) { - const server = new DigitalOceanServer(digitalOcean, dropletInfo); + const server = + new DigitalOceanServer(`${this.id}:${dropletInfo.id}`, digitalOcean, dropletInfo); this.servers.push(server); return server; } diff --git a/src/server_manager/web_app/digitalocean_server.ts b/src/server_manager/web_app/digitalocean_server.ts index 856a9b606..e17088c43 100644 --- a/src/server_manager/web_app/digitalocean_server.ts +++ b/src/server_manager/web_app/digitalocean_server.ts @@ -60,10 +60,11 @@ export class DigitalOceanServer extends ShadowboxServer implements server.Manage private eventQueue = new EventEmitter(); private installState: InstallState = InstallState.UNKNOWN; - constructor(private digitalOcean: DigitalOceanSession, private dropletInfo: DropletInfo) { + constructor( + id: string, private digitalOcean: DigitalOceanSession, private dropletInfo: DropletInfo) { // Consider passing a RestEndpoint object to the parent constructor, // to better encapsulate the management api address logic. - super(String(dropletInfo.id)); + super(id); console.info('DigitalOceanServer created'); this.eventQueue.once('server-active', () => console.timeEnd('activeServer')); this.pollInstallState(); diff --git a/src/server_manager/web_app/manual_server.ts b/src/server_manager/web_app/manual_server.ts index dd6a02832..fe2cf5b51 100644 --- a/src/server_manager/web_app/manual_server.ts +++ b/src/server_manager/web_app/manual_server.ts @@ -19,8 +19,9 @@ import {ShadowboxServer} from './shadowbox_server'; class ManualServer extends ShadowboxServer implements server.ManualServer { constructor( - private manualServerConfig: server.ManualServerConfig, private forgetCallback: Function) { - super(manualServerConfig.apiUrl); + id: string, private manualServerConfig: server.ManualServerConfig, + private forgetCallback: Function) { + super(id); this.setManagementApiUrl(manualServerConfig.apiUrl); // manualServerConfig.certSha256 is expected to be in hex format (install script). // Electron requires that this be decoded from hex (to unprintable binary), @@ -92,7 +93,7 @@ export class ManualServerRepository implements server.ManualServerRepository { } private createServer(config: server.ManualServerConfig) { - const server = new ManualServer(config, () => { + const server = new ManualServer(`manual:${config.apiUrl}`, config, () => { this.forgetServer(server); }); return server; diff --git a/src/server_manager/web_app/testing/models.ts b/src/server_manager/web_app/testing/models.ts index a2c040a2a..27678818d 100644 --- a/src/server_manager/web_app/testing/models.ts +++ b/src/server_manager/web_app/testing/models.ts @@ -22,6 +22,10 @@ export class FakeDigitalOceanAccount implements digitalocean.Account { constructor(private accessToken = 'fake-access-token') {} + getId(): string { + return 'account-id'; + } + async getName(): Promise { return 'fake-digitalocean-account-name'; } diff --git a/src/server_manager/web_app/ui_components/app-root.js b/src/server_manager/web_app/ui_components/app-root.js index 7375ea661..166acfa5c 100644 --- a/src/server_manager/web_app/ui_components/app-root.js +++ b/src/server_manager/web_app/ui_components/app-root.js @@ -55,8 +55,8 @@ const TOS_ACK_LOCAL_STORAGE_KEY = 'tos-ack'; * An access key to be displayed * @typedef {Object} ServerListEntry * @prop {string} id + * @prop {string|null} accountId * @prop {string} name - * @prop {boolean} isManaged * @prop {boolean} isSynced */ @@ -769,7 +769,7 @@ export class AppRoot extends mixinBehaviors } _computeHasManualServers(serverList) { - return this.serverList.filter(server => !server.isManaged).length > 0; + return this.serverList.filter(server => !server.accountId).length > 0; } _userAcceptedTosChanged(userAcceptedTos) { @@ -905,11 +905,11 @@ export class AppRoot extends mixinBehaviors } _isServerManaged(server) { - return server.isManaged; + return !!server.accountId; } _isServerManual(server) { - return !server.isManaged; + return !server.accountId; } _sortServersByName(a, b) { From 55be5a85998d94502c32203155ddc14b44d7b109 Mon Sep 17 00:00:00 2001 From: Vinicius Fortuna Date: Wed, 24 Mar 2021 17:54:39 -0400 Subject: [PATCH 2/6] Remove unused getHostId() --- src/server_manager/model/server.ts | 2 -- src/server_manager/web_app/digitalocean_server.ts | 4 ---- 2 files changed, 6 deletions(-) diff --git a/src/server_manager/model/server.ts b/src/server_manager/model/server.ts index 7f3c81841..c183593b4 100644 --- a/src/server_manager/model/server.ts +++ b/src/server_manager/model/server.ts @@ -122,8 +122,6 @@ export interface ManagedServerHost { getRegionId(): RegionId; // Deletes the server - cannot be undone. delete(): Promise; - // Returns the virtual host ID. - getHostId(): string; } export class DataAmount { diff --git a/src/server_manager/web_app/digitalocean_server.ts b/src/server_manager/web_app/digitalocean_server.ts index e17088c43..ba1eb6998 100644 --- a/src/server_manager/web_app/digitalocean_server.ts +++ b/src/server_manager/web_app/digitalocean_server.ts @@ -307,10 +307,6 @@ class DigitalOceanHost implements server.ManagedServerHost { this.deleteCallback(); }); } - - getHostId(): string { - return `${this.dropletInfo.id}`; - } } function startsWithCaseInsensitive(text: string, prefix: string) { From 7eea5ee560133bceffc2350ef1b6b441f8b21ea4 Mon Sep 17 00:00:00 2001 From: Vinicius Fortuna Date: Wed, 24 Mar 2021 21:13:56 -0400 Subject: [PATCH 3/6] Add AccountListEntry --- src/server_manager/web_app/app.ts | 7 +++- .../web_app/ui_components/app-root.js | 40 ++++++++++++------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/server_manager/web_app/app.ts b/src/server_manager/web_app/app.ts index bd1cac9f2..d18b755ad 100644 --- a/src/server_manager/web_app/app.ts +++ b/src/server_manager/web_app/app.ts @@ -340,7 +340,10 @@ export class App { } try { this.digitalOceanAccount = digitalOceanAccount; - this.appRoot.digitalOceanAccountName = await this.digitalOceanAccount.getName(); + this.appRoot.digitalOceanAccount = { + id: this.digitalOceanAccount.getId(), + name: await this.digitalOceanAccount.getName() + }; const status = await this.digitalOceanAccount.getStatus(); if (status !== digitalocean.Status.ACTIVE) { return []; @@ -619,7 +622,7 @@ export class App { this.removeServer(serverEntry.id); } } - this.appRoot.digitalOceanAccountName = ''; + this.appRoot.digitalOceanAccount = null; } // Clears the GCP credentials and returns to the intro screen. diff --git a/src/server_manager/web_app/ui_components/app-root.js b/src/server_manager/web_app/ui_components/app-root.js index deca223eb..36e684c2b 100644 --- a/src/server_manager/web_app/ui_components/app-root.js +++ b/src/server_manager/web_app/ui_components/app-root.js @@ -51,6 +51,13 @@ import {ServerView} from './outline-server-view.js'; const TOS_ACK_LOCAL_STORAGE_KEY = 'tos-ack'; +/** + * A cloud account to be displayed + * @typedef {Object} AccountListEntry + * @prop {string} id + * @prop {string} name + */ + /** * An access key to be displayed * @typedef {Object} ServerListEntry @@ -381,14 +388,14 @@ export class AppRoot extends mixinBehaviors
- +
-