From 5547c2baba219af17a6fc574d1d5d8eaabe48742 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Tue, 22 Feb 2022 09:00:07 -0800 Subject: [PATCH] Add AzureAccount service (#18502) --- .eslintrc.json | 3 ++ extensions/azurecore/src/azurecore.d.ts | 6 +++ .../common/azureAccountService.ts | 17 +++++++ .../api/browser/extensionHost.contribution.ts | 1 + .../api/browser/mainThreadAzureAccount.ts | 37 +++++++++++++++ .../api/common/extHostAzureAccount.ts | 22 +++++++++ .../api/common/sqlExtHost.api.impl.ts | 3 ++ .../api/common/sqlExtHost.protocol.ts | 11 +++++ .../browser/azureAccountService.ts | 45 +++++++++++++++++++ src/typings/refs.d.ts | 6 +++ src/vs/workbench/workbench.desktop.main.ts | 3 ++ 11 files changed, 154 insertions(+) create mode 100644 src/sql/platform/azureAccount/common/azureAccountService.ts create mode 100644 src/sql/workbench/api/browser/mainThreadAzureAccount.ts create mode 100644 src/sql/workbench/api/common/extHostAzureAccount.ts create mode 100644 src/sql/workbench/services/azureAccount/browser/azureAccountService.ts create mode 100644 src/typings/refs.d.ts diff --git a/.eslintrc.json b/.eslintrc.json index 5e9f43601c..07b395312c 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -212,6 +212,7 @@ "restrictions": [ "vs/nls", "azdata", + "azurecore", "**/{vs,sql}/base/common/**", "**/{vs,sql}/base/parts/*/common/**", "**/{vs,sql}/platform/*/common/**" @@ -472,6 +473,7 @@ "restrictions": [ "vscode", "azdata", + "azurecore", "vs/nls", "**/{vs,sql}/base/common/**", "**/{vs,sql}/platform/*/common/**", @@ -577,6 +579,7 @@ "vs/nls", "vs/css!./**/*", "azdata", + "azurecore", "vscode", "**/{vs,sql}/base/**/{common,browser,worker}/**", "**/{vs,sql}/platform/**/{common,browser}/**", diff --git a/extensions/azurecore/src/azurecore.d.ts b/extensions/azurecore/src/azurecore.d.ts index 30620a4049..0cd1c32ae6 100644 --- a/extensions/azurecore/src/azurecore.d.ts +++ b/extensions/azurecore/src/azurecore.d.ts @@ -263,6 +263,12 @@ declare module 'azurecore' { } export interface IExtension { + /** + * Gets the list of subscriptions for the specified AzureAccount + * @param account The account to get the subscriptions for + * @param ignoreErrors If true any errors are not thrown and instead collected and returned as part of the result + * @param selectedOnly Whether to only list subscriptions the user has selected to filter to for this account + */ getSubscriptions(account?: AzureAccount, ignoreErrors?: boolean, selectedOnly?: boolean): Promise; getResourceGroups(account?: AzureAccount, subscription?: azureResource.AzureResourceSubscription, ignoreErrors?: boolean): Promise; getLocations(account?: AzureAccount, subscription?: azureResource.AzureResourceSubscription, ignoreErrors?: boolean): Promise; diff --git a/src/sql/platform/azureAccount/common/azureAccountService.ts b/src/sql/platform/azureAccount/common/azureAccountService.ts new file mode 100644 index 0000000000..83472bf244 --- /dev/null +++ b/src/sql/platform/azureAccount/common/azureAccountService.ts @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import type * as azurecore from 'azurecore'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const SERVICE_ID = 'azureAccountService'; + +export const IAzureAccountService = createDecorator(SERVICE_ID); + +export interface IAzureAccountService { + _serviceBrand: undefined; + getSubscriptions(account: azurecore.AzureAccount): Promise; +} + diff --git a/src/sql/workbench/api/browser/extensionHost.contribution.ts b/src/sql/workbench/api/browser/extensionHost.contribution.ts index fa7be72064..1ebb9e593a 100644 --- a/src/sql/workbench/api/browser/extensionHost.contribution.ts +++ b/src/sql/workbench/api/browser/extensionHost.contribution.ts @@ -3,6 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import './mainThreadAzureAccount'; import './mainThreadAccountManagement'; import './mainThreadBackgroundTaskManagement'; import './mainThreadConnectionManagement'; diff --git a/src/sql/workbench/api/browser/mainThreadAzureAccount.ts b/src/sql/workbench/api/browser/mainThreadAzureAccount.ts new file mode 100644 index 0000000000..ce6e677588 --- /dev/null +++ b/src/sql/workbench/api/browser/mainThreadAzureAccount.ts @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import type * as azurecore from 'azurecore'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { + ExtHostAzureAccountShape, + MainThreadAzureAccountShape, + SqlExtHostContext, + SqlMainContext +} from 'sql/workbench/api/common/sqlExtHost.protocol'; +import { IExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; +import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; +import { IAzureAccountService } from 'sql/platform/azureAccount/common/azureAccountService'; +import { AzureAccountService } from 'sql/workbench/services/azureAccount/browser/azureAccountService'; + +@extHostNamedCustomer(SqlMainContext.MainThreadAzureAccount) +export class MainThreadAzureAccount extends Disposable implements MainThreadAzureAccountShape { + private _proxy: ExtHostAzureAccountShape; + public _serviceBrand: undefined; + + constructor( + extHostContext: IExtHostContext, + @IAzureAccountService azureAccountService: IAzureAccountService + ) { + super(); + this._proxy = extHostContext.getProxy(SqlExtHostContext.ExtHostAzureAccount); + (azureAccountService as AzureAccountService).registerProxy(this); + } + + public async getSubscriptions(account: azurecore.AzureAccount, ignoreErrors?: boolean, selectedOnly?: boolean): Promise { + return this._proxy.$getSubscriptions(account, ignoreErrors, selectedOnly); + } + +} diff --git a/src/sql/workbench/api/common/extHostAzureAccount.ts b/src/sql/workbench/api/common/extHostAzureAccount.ts new file mode 100644 index 0000000000..c217d2c86a --- /dev/null +++ b/src/sql/workbench/api/common/extHostAzureAccount.ts @@ -0,0 +1,22 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as azurecore from 'azurecore'; +import { ExtHostAzureAccountShape } from 'sql/workbench/api/common/sqlExtHost.protocol'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; + +export class ExtHostAzureAccount extends ExtHostAzureAccountShape { + + constructor(@IExtHostExtensionService private _extHostExtensionService: IExtHostExtensionService,) { + super(); + } + + public override $getSubscriptions(account: azurecore.AzureAccount, ignoreErrors?: boolean, selectedOnly?: boolean): Thenable { + const api = this._extHostExtensionService.getExtensionExports(new ExtensionIdentifier(azurecore.extension.name)) as azurecore.IExtension; + return api.getSubscriptions(account, ignoreErrors, selectedOnly); + } +} + diff --git a/src/sql/workbench/api/common/sqlExtHost.api.impl.ts b/src/sql/workbench/api/common/sqlExtHost.api.impl.ts index b086857612..df62fac4eb 100644 --- a/src/sql/workbench/api/common/sqlExtHost.api.impl.ts +++ b/src/sql/workbench/api/common/sqlExtHost.api.impl.ts @@ -37,6 +37,8 @@ import { ExtHostWorkspace } from 'sql/workbench/api/common/extHostWorkspace'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { URI } from 'vs/base/common/uri'; import { ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry'; +import { ExtHostAzureAccount } from 'sql/workbench/api/common/extHostAzureAccount'; +import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; export interface IAzdataExtensionApiFactory { (extension: IExtensionDescription): typeof azdata; @@ -77,6 +79,7 @@ export function createAdsApiFactory(accessor: ServicesAccessor): IAdsExtensionAp // Addressable instances const extHostAccountManagement = rpcProtocol.set(SqlExtHostContext.ExtHostAccountManagement, new ExtHostAccountManagement(rpcProtocol)); + rpcProtocol.set(SqlExtHostContext.ExtHostAzureAccount, new ExtHostAzureAccount(accessor.get(IExtHostExtensionService))); const extHostConnectionManagement = rpcProtocol.set(SqlExtHostContext.ExtHostConnectionManagement, new ExtHostConnectionManagement(rpcProtocol)); const extHostCredentialManagement = rpcProtocol.set(SqlExtHostContext.ExtHostCredentialManagement, new ExtHostCredentialManagement(rpcProtocol)); const extHostDataProvider = rpcProtocol.set(SqlExtHostContext.ExtHostDataProtocol, new ExtHostDataProtocol(rpcProtocol, uriTransformer)); diff --git a/src/sql/workbench/api/common/sqlExtHost.protocol.ts b/src/sql/workbench/api/common/sqlExtHost.protocol.ts index 996aef6136..227b800e68 100644 --- a/src/sql/workbench/api/common/sqlExtHost.protocol.ts +++ b/src/sql/workbench/api/common/sqlExtHost.protocol.ts @@ -13,6 +13,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import type * as azdata from 'azdata'; import type * as vscode from 'vscode'; +import type * as azurecore from 'azurecore'; import { ITreeComponentItem } from 'sql/workbench/common/views'; import { ITaskHandlerDescription } from 'sql/workbench/services/tasks/common/tasks'; @@ -30,6 +31,10 @@ import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; import { TreeDataTransferDTO } from 'vs/workbench/api/common/shared/treeDataTransfer'; import { ITelemetryEventProperties } from 'sql/platform/telemetry/common/telemetry'; +export abstract class ExtHostAzureAccountShape { + public $getSubscriptions(account: azurecore.AzureAccount, ignoreErrors?: boolean, selectedOnly?: boolean): Thenable { throw ni(); } +} + export abstract class ExtHostAccountManagementShape { $autoOAuthCancelled(handle: number): Thenable { throw ni(); } $clear(handle: number, accountKey: azdata.AccountKey): Thenable { throw ni(); } @@ -603,6 +608,10 @@ export interface MainThreadAccountManagementShape extends IDisposable { $getAccountsForProvider(providerId: string): Thenable; } +export interface MainThreadAzureAccountShape extends IDisposable { + +} + export interface MainThreadResourceProviderShape extends IDisposable { $registerResourceProvider(providerMetadata: azdata.ResourceProviderMetadata, handle: number): Thenable; $unregisterResourceProvider(handle: number): Thenable; @@ -688,6 +697,7 @@ function ni() { return new Error('Not implemented'); } export const SqlMainContext = { // SQL entries MainThreadAccountManagement: createMainId('MainThreadAccountManagement'), + MainThreadAzureAccount: createMainId('MainThreadAzureAccount'), MainThreadConnectionManagement: createMainId('MainThreadConnectionManagement'), MainThreadCredentialManagement: createMainId('MainThreadCredentialManagement'), MainThreadDataProtocol: createMainId('MainThreadDataProtocol'), @@ -709,6 +719,7 @@ export const SqlMainContext = { export const SqlExtHostContext = { ExtHostAccountManagement: createExtId('ExtHostAccountManagement'), + ExtHostAzureAccount: createExtId('ExtHostAzureAccount'), ExtHostConnectionManagement: createExtId('ExtHostConnectionManagement'), ExtHostCredentialManagement: createExtId('ExtHostCredentialManagement'), ExtHostDataProtocol: createExtId('ExtHostDataProtocol'), diff --git a/src/sql/workbench/services/azureAccount/browser/azureAccountService.ts b/src/sql/workbench/services/azureAccount/browser/azureAccountService.ts new file mode 100644 index 0000000000..549742f625 --- /dev/null +++ b/src/sql/workbench/services/azureAccount/browser/azureAccountService.ts @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import type * as azurecore from 'azurecore'; +import { IAzureAccountService } from 'sql/platform/azureAccount/common/azureAccountService'; +import { MainThreadAzureAccount } from 'sql/workbench/api/browser/mainThreadAzureAccount'; + +/** + * Service that provides access to the azurecore extension capabilities (such as getting subscriptions + * for an Azure account) + */ +export class AzureAccountService implements IAzureAccountService { + + public _serviceBrand: undefined; + private _proxy: MainThreadAzureAccount; + + /** + * Internal use only, do not call! This is called once on startup by the proxy object used + * to communicate with the extension host once it's been created. + * @param proxy The proxy to use to communicate with the azurecore extension + */ + public registerProxy(proxy: MainThreadAzureAccount) { + this._proxy = proxy; + } + + /** + * Gets the list of subscriptions for the specified AzureAccount + * @param account The account to get the subscriptions for + * @param ignoreErrors If true any errors are not thrown and instead collected and returned as part of the result + * @param selectedOnly Whether to only list subscriptions the user has selected to filter to for this account + */ + public getSubscriptions(account: azurecore.AzureAccount, ignoreErrors?: boolean, selectedOnly?: boolean): Promise { + this.checkProxy(); + return this._proxy.getSubscriptions(account, ignoreErrors, selectedOnly); + } + + private checkProxy(): void { + if (!this._proxy) { + throw new Error('Azure Account proxy not initialized'); + } + } +} + diff --git a/src/typings/refs.d.ts b/src/typings/refs.d.ts new file mode 100644 index 0000000000..386b867974 --- /dev/null +++ b/src/typings/refs.d.ts @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/// diff --git a/src/vs/workbench/workbench.desktop.main.ts b/src/vs/workbench/workbench.desktop.main.ts index 33d3f3a03f..cee00168a5 100644 --- a/src/vs/workbench/workbench.desktop.main.ts +++ b/src/vs/workbench/workbench.desktop.main.ts @@ -84,10 +84,13 @@ import { IClipboardService as sqlIClipboardService } from 'sql/platform/clipboar import { ClipboardService as sqlClipboardService } from 'sql/platform/clipboard/electron-browser/clipboardService'; import { IQueryHistoryService } from 'sql/workbench/services/queryHistory/common/queryHistoryService'; import { QueryHistoryService } from 'sql/workbench/services/queryHistory/common/queryHistoryServiceImpl'; +import { IAzureAccountService } from 'sql/platform/azureAccount/common/azureAccountService'; +import { AzureAccountService } from 'sql/workbench/services/azureAccount/browser/azureAccountService'; registerSingleton(ISqlOAuthService, SqlOAuthService); registerSingleton(sqlIClipboardService, sqlClipboardService); registerSingleton(IQueryHistoryService, QueryHistoryService); +registerSingleton(IAzureAccountService, AzureAccountService); // {{SQL CARBON EDIT}} - End // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!