mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-20 01:25:37 -05:00
* add more folders to strictire compile, add more strict compile options * update ci * remove unnecessary assertion
242 lines
10 KiB
TypeScript
242 lines
10 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import { ConnectionManagementInfo } from 'sql/platform/connection/common/connectionManagementInfo';
|
|
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
|
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
|
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
|
import { StopWatch } from 'vs/base/common/stopwatch';
|
|
import { ILogService } from 'vs/platform/log/common/log';
|
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
|
import { join } from 'vs/base/common/path';
|
|
import * as Utils from 'sql/platform/connection/common/utils';
|
|
import * as azdata from 'azdata';
|
|
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
|
import { startsWith } from 'vs/base/common/strings';
|
|
import { values } from 'vs/base/common/collections';
|
|
import { firstIndex, find } from 'vs/base/common/arrays';
|
|
|
|
export class ConnectionStatusManager {
|
|
|
|
private _connections: { [id: string]: ConnectionManagementInfo };
|
|
|
|
constructor(
|
|
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService,
|
|
@ILogService private _logService: ILogService,
|
|
@IEnvironmentService private _environmentService: IEnvironmentService,
|
|
@INotificationService private _notificationService: INotificationService) {
|
|
this._connections = {};
|
|
}
|
|
|
|
public findConnection(uri: string): ConnectionManagementInfo | undefined {
|
|
if (uri in this._connections) {
|
|
return this._connections[uri];
|
|
} else {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
public findConnectionByProfileId(profileId: string): ConnectionManagementInfo | undefined {
|
|
return find(values(this._connections), connection => connection.connectionProfile.id === profileId);
|
|
}
|
|
|
|
public findConnectionProfile(connectionProfile: IConnectionProfile): ConnectionManagementInfo | undefined {
|
|
let id = Utils.generateUri(connectionProfile);
|
|
return this.findConnection(id);
|
|
}
|
|
|
|
public hasConnection(id: string): Boolean {
|
|
return !!this.findConnection(id);
|
|
}
|
|
|
|
public deleteConnection(id: string): void {
|
|
let info = this.findConnection(id);
|
|
if (info) {
|
|
for (let key in this._connections) {
|
|
if (this._connections[key].connectionId === info.connectionId) {
|
|
if (this._connections[key].connecting) {
|
|
this._logService.info(`Deleting connection ${id} (connecting)`);
|
|
this._connections[key].deleted = true;
|
|
} else {
|
|
this._logService.info(`Deleting connection ${id}`);
|
|
delete this._connections[key];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public getConnectionProfile(id: string): ConnectionProfile | undefined {
|
|
let connectionInfoForId = this.findConnection(id);
|
|
return connectionInfoForId ? connectionInfoForId.connectionProfile : undefined;
|
|
}
|
|
|
|
public addConnection(connection: IConnectionProfile, id: string): ConnectionManagementInfo {
|
|
this._logService.info(`Adding connection ${id}`);
|
|
// Always create a copy and save that in the list
|
|
let connectionProfile = new ConnectionProfile(this._capabilitiesService, connection);
|
|
let connectionInfo: ConnectionManagementInfo = {
|
|
providerId: connection.providerName,
|
|
extensionTimer: StopWatch.create(),
|
|
intelliSenseTimer: StopWatch.create(),
|
|
connectionProfile: connectionProfile,
|
|
connecting: true,
|
|
serviceTimer: StopWatch.create(),
|
|
ownerUri: id
|
|
};
|
|
this._connections[id] = connectionInfo;
|
|
this._logService.info(`Successfully added connection ${id}`);
|
|
return connectionInfo;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param uri Remove connection from list of active connections
|
|
*/
|
|
public removeConnection(uri: string) {
|
|
this._logService.info(`Removing connection ${uri}`);
|
|
delete this._connections[uri];
|
|
}
|
|
|
|
/**
|
|
* Call after a connection is saved to settings. It's only for default url connections
|
|
* which their id is generated from connection options. The group id is used in the generated id.
|
|
* when the connection is stored, the group id get assigned to the profile and it can change the id
|
|
* So for those kind of connections, we need to add the new id and the connection
|
|
*/
|
|
public updateConnectionProfile(connection: IConnectionProfile, id: string): string {
|
|
let newId: string = id;
|
|
let connectionInfo: ConnectionManagementInfo = this._connections[id];
|
|
if (connectionInfo && connection) {
|
|
if (this.isDefaultTypeUri(id)) {
|
|
connectionInfo.connectionProfile.groupId = connection.groupId;
|
|
newId = Utils.generateUri(connection);
|
|
if (newId !== id) {
|
|
this.deleteConnection(id);
|
|
this._logService.info(`Adding connection (update) ${newId} (old=${id})`);
|
|
this._connections[newId] = connectionInfo;
|
|
}
|
|
}
|
|
connectionInfo.connectionProfile.id = connection.id;
|
|
}
|
|
return newId;
|
|
}
|
|
|
|
public onConnectionComplete(summary: azdata.ConnectionInfoSummary): ConnectionManagementInfo {
|
|
let connection = this._connections[summary.ownerUri];
|
|
if (!connection) {
|
|
this._logService.error(`OnConnectionComplete but no connection found '${summary.ownerUri}' Connections = [${Object.keys(this._connections)}]`);
|
|
this._notificationService.notify({
|
|
severity: Severity.Error,
|
|
message: `An unexpected error occurred while connecting. Please [file an issue](command:workbench.action.openIssueReporter) with the title 'Unexpected Error Occurred while Connecting' and include the log file [${join(this._environmentService.logsPath, 'renderer1.log')}](command:workbench.action.openLogsFolder)`
|
|
});
|
|
// Bail out at this point - there's nothing else we can do since this is an unexpected state.
|
|
throw new Error('Unexpected error occurred while connecting.');
|
|
}
|
|
connection.serviceTimer.stop();
|
|
connection.connecting = false;
|
|
connection.connectionId = summary.connectionId;
|
|
connection.serverInfo = summary.serverInfo;
|
|
return connection;
|
|
}
|
|
|
|
/**
|
|
* Updates database name after connection is complete
|
|
* @param summary connection summary
|
|
*/
|
|
public updateDatabaseName(summary: azdata.ConnectionInfoSummary): void {
|
|
let connection = this._connections[summary.ownerUri];
|
|
|
|
//Check if the existing connection database name is different the one in the summary
|
|
if (connection.connectionProfile.databaseName !== summary.connectionSummary.databaseName) {
|
|
//Add the ownerUri with database name to the map if not already exists
|
|
connection.connectionProfile.databaseName = summary.connectionSummary.databaseName;
|
|
let prefix = Utils.getUriPrefix(summary.ownerUri);
|
|
let ownerUriWithDbName = Utils.generateUriWithPrefix(connection.connectionProfile, prefix);
|
|
if (!(ownerUriWithDbName in this._connections)) {
|
|
this._logService.info(`Adding connection with DB name ${ownerUriWithDbName}`);
|
|
this._connections[ownerUriWithDbName] = connection;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Tries to find an existing connection that's mapped with the given ownerUri
|
|
* The purpose for this method is to find the connection given the ownerUri and find the original uri assigned to it. most of the times should be the same.
|
|
* Only if the db name in the original uri is different when connection is complete, we need to use the original uri
|
|
* Returns the generated ownerUri for the connection profile if not existing connection found
|
|
* @param ownerUri connection owner uri to find an existing connection
|
|
* @param purpose purpose for the connection
|
|
*/
|
|
public getOriginalOwnerUri(ownerUri: string): string {
|
|
let ownerUriToReturn: string = ownerUri;
|
|
|
|
let connectionStatusInfo = this.findConnection(ownerUriToReturn);
|
|
if (connectionStatusInfo && connectionStatusInfo.ownerUri) {
|
|
//The ownerUri in the connection status is the one service knows about so use that
|
|
//To call the service for any operation
|
|
ownerUriToReturn = connectionStatusInfo.ownerUri;
|
|
}
|
|
return ownerUriToReturn;
|
|
}
|
|
|
|
public onConnectionChanged(changedConnInfo: azdata.ChangedConnectionInfo): IConnectionProfile | undefined {
|
|
let connection = this._connections[changedConnInfo.connectionUri];
|
|
if (connection && connection.connectionProfile) {
|
|
connection.connectionProfile.serverName = changedConnInfo.connection.serverName;
|
|
connection.connectionProfile.databaseName = changedConnInfo.connection.databaseName;
|
|
connection.connectionProfile.userName = changedConnInfo.connection.userName;
|
|
return connection.connectionProfile;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
private isSharedSession(fileUri: string): boolean {
|
|
return !!(fileUri && startsWith(fileUri, 'vsls:'));
|
|
}
|
|
|
|
public isConnected(id: string): boolean {
|
|
if (this.isSharedSession(id)) {
|
|
return true;
|
|
}
|
|
return !!(id in this._connections && this._connections[id].connectionId && !!this._connections[id].connectionId);
|
|
}
|
|
|
|
public isConnecting(id: string): boolean {
|
|
return (id in this._connections && this._connections[id].connecting);
|
|
}
|
|
|
|
public isDefaultTypeUri(uri: string): boolean {
|
|
return !!(uri && startsWith(uri, Utils.uriPrefixes.default));
|
|
}
|
|
|
|
public getProviderIdFromUri(ownerUri: string): string {
|
|
let providerId: string = '';
|
|
let connection = this.findConnection(ownerUri);
|
|
if (connection) {
|
|
providerId = connection.connectionProfile.providerName;
|
|
}
|
|
if (!providerId && this.isDefaultTypeUri(ownerUri)) {
|
|
let optionsKey = ownerUri.replace(Utils.uriPrefixes.default, '');
|
|
providerId = ConnectionProfile.getProviderFromOptionsKey(optionsKey);
|
|
}
|
|
return providerId;
|
|
}
|
|
|
|
/**
|
|
* Get a list of the active connection profiles managed by the status manager
|
|
*/
|
|
public getActiveConnectionProfiles(providers?: string[]): ConnectionProfile[] {
|
|
let profiles = values(this._connections).map((connectionInfo: ConnectionManagementInfo) => connectionInfo.connectionProfile);
|
|
// Remove duplicate profiles that may be listed multiple times under different URIs by filtering for profiles that don't have the same ID as an earlier profile in the list
|
|
profiles = profiles.filter((profile, index) => firstIndex(profiles, otherProfile => otherProfile.id === profile.id) === index);
|
|
|
|
if (providers) {
|
|
profiles = profiles.filter(f => find(providers, x => x === f.providerName));
|
|
}
|
|
return profiles;
|
|
}
|
|
}
|