// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // using System; using System.Composition; using Microsoft.Kusto.ServiceLayer.Connection; using Microsoft.Kusto.ServiceLayer.Connection.Contracts; using Microsoft.Kusto.ServiceLayer.DataSource; namespace Microsoft.Kusto.ServiceLayer.LanguageServices { /// /// ConnectedBindingQueue class for processing online binding requests /// [Export(typeof(IConnectedBindingQueue))] public class ConnectedBindingQueue : BindingQueue, IConnectedBindingQueue { internal const int DefaultBindingTimeout = 500; private readonly IDataSourceFactory _dataSourceFactory; [ImportingConstructor] public ConnectedBindingQueue(IDataSourceFactory dataSourceFactory) { _dataSourceFactory = dataSourceFactory; } /// /// Generate a unique key based on the ConnectionInfo object /// /// internal static string GetConnectionContextKey(ConnectionDetails details) { string key = string.Format("{0}_{1}_{2}_{3}", details.ServerName ?? "NULL", details.DatabaseName ?? "NULL", details.UserName ?? "NULL", details.AuthenticationType ?? "NULL" ); if (!string.IsNullOrEmpty(details.DatabaseDisplayName)) { key += "_" + details.DatabaseDisplayName; } if (!string.IsNullOrEmpty(details.GroupId)) { key += "_" + details.GroupId; } return Uri.EscapeUriString(key); } public void RemoveBindingContext(ConnectionInfo connInfo) { string connectionKey = GetConnectionContextKey(connInfo.ConnectionDetails); if (BindingContextExists(connectionKey)) { RemoveBindingContext(connectionKey); } } /// /// Use a ConnectionInfo item to create a connected binding context /// /// Connection info used to create binding context /// /// /// Overwrite existing context public string AddConnectionContext(ConnectionInfo connInfo, bool needMetadata, string featureName = null, bool overwrite = false) { if (connInfo == null) { return string.Empty; } // lookup the current binding contextna string connectionKey = GetConnectionContextKey(connInfo.ConnectionDetails); if (BindingContextExists(connectionKey)) { if (overwrite) { RemoveBindingContext(connectionKey); } else { // no need to populate the context again since the context already exists return connectionKey; } } IBindingContext bindingContext = GetOrCreateBindingContext(connectionKey); if (bindingContext.BindingLock.WaitOne()) { try { bindingContext.BindingLock.Reset(); string connectionString = ConnectionService.BuildConnectionString(connInfo.ConnectionDetails); bindingContext.DataSource = _dataSourceFactory.Create(DataSourceType.Kusto, connectionString, connInfo.ConnectionDetails.AzureAccountToken); bindingContext.BindingTimeout = DefaultBindingTimeout; bindingContext.IsConnected = true; } catch (Exception) { bindingContext.IsConnected = false; } finally { bindingContext.BindingLock.Set(); } } return connectionKey; } } }