mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-16 10:58:30 -05:00
Fix file browser cancel/connetion issues (#528)
* clean bindingqueue after cancel * fileborwser fixes * code cleanup * re-initialize filetree whenever filter is changed * fix test issues * address pr comments
This commit is contained in:
@@ -42,4 +42,14 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser.Contracts
|
|||||||
RequestType<FileBrowserCloseParams, FileBrowserCloseResponse> Type =
|
RequestType<FileBrowserCloseParams, FileBrowserCloseResponse> Type =
|
||||||
RequestType<FileBrowserCloseParams, FileBrowserCloseResponse>.Create("filebrowser/close");
|
RequestType<FileBrowserCloseParams, FileBrowserCloseResponse>.Create("filebrowser/close");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Notification for close completion
|
||||||
|
/// </summary>
|
||||||
|
public class FileBrowserClosedNotification
|
||||||
|
{
|
||||||
|
public static readonly
|
||||||
|
EventType<FileBrowserCloseResponse> Type =
|
||||||
|
EventType<FileBrowserCloseResponse>.Create("filebrowser/closecomplete");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
public abstract class FileBrowserBase
|
public abstract class FileBrowserBase
|
||||||
{
|
{
|
||||||
private Enumerator enumerator = null;
|
private Enumerator enumerator = null;
|
||||||
protected SqlConnection sqlConnection = null;
|
protected ServerConnection connection = null;
|
||||||
|
|
||||||
protected Enumerator Enumerator
|
protected Enumerator Enumerator
|
||||||
{
|
{
|
||||||
@@ -49,7 +49,7 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
/// Returns the PathSeparator values of the Server.
|
/// Returns the PathSeparator values of the Server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>PathSeparator</returns>
|
/// <returns>PathSeparator</returns>
|
||||||
internal static char GetPathSeparator(Enumerator enumerator, SqlConnection connection)
|
internal static char GetPathSeparator(Enumerator enumerator, ServerConnection connection)
|
||||||
{
|
{
|
||||||
var req = new Request();
|
var req = new Request();
|
||||||
req.Urn = "Server";
|
req.Urn = "Server";
|
||||||
@@ -78,7 +78,7 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
/// <param name="enumerator"></param>
|
/// <param name="enumerator"></param>
|
||||||
/// <param name="connection"></param>
|
/// <param name="connection"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal static IEnumerable<FileInfo> EnumerateDrives(Enumerator enumerator, SqlConnection connection)
|
internal static IEnumerable<FileInfo> EnumerateDrives(Enumerator enumerator, ServerConnection connection)
|
||||||
{
|
{
|
||||||
// if not supplied, server name will be obtained from urn
|
// if not supplied, server name will be obtained from urn
|
||||||
Request req = new Request();
|
Request req = new Request();
|
||||||
@@ -145,7 +145,7 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
/// <param name="connection"></param>
|
/// <param name="connection"></param>
|
||||||
/// <param name="path"></param>
|
/// <param name="path"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal static IEnumerable<FileInfo> EnumerateFilesInFolder(Enumerator enumerator, SqlConnection connection, string path)
|
internal static IEnumerable<FileInfo> EnumerateFilesInFolder(Enumerator enumerator, ServerConnection connection, string path)
|
||||||
{
|
{
|
||||||
var request = new Request
|
var request = new Request
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data.SqlClient;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using Microsoft.SqlServer.Management.Common;
|
||||||
using Microsoft.SqlTools.ServiceLayer.FileBrowser.Contracts;
|
using Microsoft.SqlTools.ServiceLayer.FileBrowser.Contracts;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
||||||
@@ -30,21 +30,13 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="FileBrowser"/> class.
|
/// Initializes a new instance of the <see cref="FileBrowser"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FileBrowserOperation()
|
/// <param name="connection">The connection object</param>
|
||||||
|
/// <param name="fileFilters">The file extension filters</param>
|
||||||
|
public FileBrowserOperation(ServerConnection connection, string expandPath, string[] fileFilters = null)
|
||||||
{
|
{
|
||||||
this.fileTree = new FileTree();
|
|
||||||
this.cancelSource = new CancellationTokenSource();
|
this.cancelSource = new CancellationTokenSource();
|
||||||
this.cancelToken = cancelSource.Token;
|
this.cancelToken = cancelSource.Token;
|
||||||
}
|
this.connection = connection;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="FileBrowser"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="connectionInfo">The connection info</param>
|
|
||||||
/// <param name="fileFilters">The file extension filters</param>
|
|
||||||
public FileBrowserOperation(SqlConnection connectionInfo, string expandPath, string[] fileFilters = null): this()
|
|
||||||
{
|
|
||||||
this.sqlConnection = connectionInfo;
|
|
||||||
this.Initialize(expandPath, fileFilters);
|
this.Initialize(expandPath, fileFilters);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,14 +68,6 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SqlConnection SqlConnection
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return this.sqlConnection;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsCancellationRequested
|
public bool IsCancellationRequested
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -100,6 +84,7 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
|
|
||||||
public void Initialize(string expandPath, string[] fileFilters)
|
public void Initialize(string expandPath, string[] fileFilters)
|
||||||
{
|
{
|
||||||
|
this.fileTree = new FileTree();
|
||||||
this.expandPath = expandPath;
|
this.expandPath = expandPath;
|
||||||
if (fileFilters == null)
|
if (fileFilters == null)
|
||||||
{
|
{
|
||||||
@@ -113,9 +98,9 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (this.sqlConnection != null)
|
if (this.connection != null)
|
||||||
{
|
{
|
||||||
this.sqlConnection.Close();
|
this.connection.Disconnect();
|
||||||
}
|
}
|
||||||
this.cancelSource.Dispose();
|
this.cancelSource.Dispose();
|
||||||
}
|
}
|
||||||
@@ -123,7 +108,7 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
public void PopulateFileTree()
|
public void PopulateFileTree()
|
||||||
{
|
{
|
||||||
this.fileTreeCreated = false;
|
this.fileTreeCreated = false;
|
||||||
this.PathSeparator = GetPathSeparator(this.Enumerator, this.sqlConnection);
|
this.PathSeparator = GetPathSeparator(this.Enumerator, this.connection);
|
||||||
PopulateDrives();
|
PopulateDrives();
|
||||||
ExpandSelectedNode(this.expandPath);
|
ExpandSelectedNode(this.expandPath);
|
||||||
this.fileTreeCreated = true;
|
this.fileTreeCreated = true;
|
||||||
@@ -191,7 +176,7 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
bool first = true;
|
bool first = true;
|
||||||
if (!cancelToken.IsCancellationRequested)
|
if (!cancelToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
foreach (var fileInfo in EnumerateDrives(Enumerator, sqlConnection))
|
foreach (var fileInfo in EnumerateDrives(Enumerator, connection))
|
||||||
{
|
{
|
||||||
if (cancelToken.IsCancellationRequested)
|
if (cancelToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -221,7 +206,7 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
public List<FileTreeNode> GetChildren(string filePath)
|
public List<FileTreeNode> GetChildren(string filePath)
|
||||||
{
|
{
|
||||||
List<FileTreeNode> children = new List<FileTreeNode>();
|
List<FileTreeNode> children = new List<FileTreeNode>();
|
||||||
foreach (var file in EnumerateFilesInFolder(Enumerator, sqlConnection, filePath))
|
foreach (var file in EnumerateFilesInFolder(Enumerator, connection, filePath))
|
||||||
{
|
{
|
||||||
bool isFile = !string.IsNullOrEmpty(file.fileName);
|
bool isFile = !string.IsNullOrEmpty(file.fileName);
|
||||||
FileTreeNode treeNode = new FileTreeNode();
|
FileTreeNode treeNode = new FileTreeNode();
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using Microsoft.SqlTools.ServiceLayer.FileBrowser.Contracts;
|
|||||||
using Microsoft.SqlTools.ServiceLayer.Hosting;
|
using Microsoft.SqlTools.ServiceLayer.Hosting;
|
||||||
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
using Microsoft.SqlTools.ServiceLayer.LanguageServices;
|
||||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||||
|
using Microsoft.SqlTools.Utility;
|
||||||
|
|
||||||
namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
||||||
{
|
{
|
||||||
@@ -28,8 +29,8 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
private readonly ConcurrentDictionary<string, FileBrowserOperation> ownerToFileBrowserMap = new ConcurrentDictionary<string, FileBrowserOperation>();
|
private readonly ConcurrentDictionary<string, FileBrowserOperation> ownerToFileBrowserMap = new ConcurrentDictionary<string, FileBrowserOperation>();
|
||||||
private readonly ConcurrentDictionary<string, ValidatePathsCallback> validatePathsCallbackMap = new ConcurrentDictionary<string, ValidatePathsCallback>();
|
private readonly ConcurrentDictionary<string, ValidatePathsCallback> validatePathsCallbackMap = new ConcurrentDictionary<string, ValidatePathsCallback>();
|
||||||
private ConnectionService connectionService;
|
private ConnectionService connectionService;
|
||||||
private ConnectedBindingQueue expandNodeQueue = new ConnectedBindingQueue(needsMetadata: false);
|
private ConnectedBindingQueue fileBrowserQueue = new ConnectedBindingQueue(needsMetadata: false);
|
||||||
private static int DefaultExpandTimeout = 120000;
|
private static int DefaultTimeout = 120000;
|
||||||
private string serviceName = "FileBrowser";
|
private string serviceName = "FileBrowser";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -45,7 +46,7 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
if (connectionService == null)
|
if (connectionService == null)
|
||||||
{
|
{
|
||||||
connectionService = ConnectionService.Instance;
|
connectionService = ConnectionService.Instance;
|
||||||
connectionService.RegisterConnectedQueue(this.serviceName, this.expandNodeQueue);
|
connectionService.RegisterConnectedQueue(this.serviceName, this.fileBrowserQueue);
|
||||||
}
|
}
|
||||||
return connectionService;
|
return connectionService;
|
||||||
}
|
}
|
||||||
@@ -94,8 +95,9 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
.ContinueWithOnFaulted(null);
|
.ContinueWithOnFaulted(null);
|
||||||
await requestContext.SendResult(true);
|
await requestContext.SendResult(true);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
Logger.Write(LogLevel.Error, "Unexpected exception while handling file browser open request: " + ex.Message);
|
||||||
await requestContext.SendResult(false);
|
await requestContext.SendResult(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,8 +110,9 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
.ContinueWithOnFaulted(null);
|
.ContinueWithOnFaulted(null);
|
||||||
await requestContext.SendResult(true);
|
await requestContext.SendResult(true);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
Logger.Write(LogLevel.Error, "Unexpected exception while handling file browser expand request: " + ex.Message);
|
||||||
await requestContext.SendResult(false);
|
await requestContext.SendResult(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,8 +125,9 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
.ContinueWithOnFaulted(null);
|
.ContinueWithOnFaulted(null);
|
||||||
await requestContext.SendResult(true);
|
await requestContext.SendResult(true);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
Logger.Write(LogLevel.Error, "Unexpected exception while handling file browser validate request: " + ex.Message);
|
||||||
await requestContext.SendResult(false);
|
await requestContext.SendResult(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,90 +136,139 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
FileBrowserCloseParams fileBrowserParams,
|
FileBrowserCloseParams fileBrowserParams,
|
||||||
RequestContext<FileBrowserCloseResponse> requestContext)
|
RequestContext<FileBrowserCloseResponse> requestContext)
|
||||||
{
|
{
|
||||||
FileBrowserCloseResponse response = new FileBrowserCloseResponse();
|
try
|
||||||
FileBrowserOperation removedOperation;
|
|
||||||
response.Succeeded = ownerToFileBrowserMap.TryRemove(fileBrowserParams.OwnerUri, out removedOperation);
|
|
||||||
|
|
||||||
if (removedOperation != null && this.expandNodeQueue != null)
|
|
||||||
{
|
{
|
||||||
bool hasPendingQueueItems = this.expandNodeQueue.HasPendingQueueItems;
|
var task = Task.Run(() => RunFileBrowserCloseTask(fileBrowserParams, requestContext))
|
||||||
if (removedOperation.FileTreeCreated && !hasPendingQueueItems)
|
.ContinueWithOnFaulted(null);
|
||||||
{
|
await requestContext.SendResult(new FileBrowserCloseResponse() { Succeeded = true });
|
||||||
removedOperation.Dispose();
|
}
|
||||||
this.expandNodeQueue.CloseConnections(removedOperation.SqlConnection.DataSource, removedOperation.SqlConnection.Database, DefaultExpandTimeout);
|
catch (Exception ex)
|
||||||
}
|
{
|
||||||
else if (!removedOperation.FileTreeCreated)
|
Logger.Write(LogLevel.Error, "Unexpected exception while handling file browser close request: " + ex.Message);
|
||||||
{
|
await requestContext.SendResult(new FileBrowserCloseResponse() { Message = ex.Message });
|
||||||
removedOperation.Cancel();
|
|
||||||
}
|
|
||||||
else if (hasPendingQueueItems)
|
|
||||||
{
|
|
||||||
this.expandNodeQueue.StopQueueProcessor(DefaultExpandTimeout);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await requestContext.SendResult(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
this.expandNodeQueue.Dispose();
|
this.fileBrowserQueue.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task RunFileBrowserCloseTask(FileBrowserCloseParams fileBrowserParams, RequestContext<FileBrowserCloseResponse> requestContext)
|
||||||
|
{
|
||||||
|
FileBrowserCloseResponse result = new FileBrowserCloseResponse();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FileBrowserOperation operation = null;
|
||||||
|
ConnectionInfo connInfo;
|
||||||
|
ownerToFileBrowserMap.TryGetValue(fileBrowserParams.OwnerUri, out operation);
|
||||||
|
this.ConnectionServiceInstance.TryFindConnection(fileBrowserParams.OwnerUri, out connInfo);
|
||||||
|
|
||||||
|
if (operation != null && connInfo != null)
|
||||||
|
{
|
||||||
|
if (!operation.FileTreeCreated)
|
||||||
|
{
|
||||||
|
operation.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear queued items
|
||||||
|
this.fileBrowserQueue.ClearQueuedItems();
|
||||||
|
|
||||||
|
// Queue operation to clean up resources
|
||||||
|
QueueItem queueItem = fileBrowserQueue.QueueBindingOperation(
|
||||||
|
key: fileBrowserQueue.AddConnectionContext(connInfo, this.serviceName),
|
||||||
|
bindingTimeout: DefaultTimeout,
|
||||||
|
waitForLockTimeout: DefaultTimeout,
|
||||||
|
bindOperation: (bindingContext, cancelToken) =>
|
||||||
|
{
|
||||||
|
FileBrowserOperation removedOperation = null;
|
||||||
|
ownerToFileBrowserMap.TryRemove(fileBrowserParams.OwnerUri, out removedOperation);
|
||||||
|
if (removedOperation != null)
|
||||||
|
{
|
||||||
|
removedOperation.Dispose();
|
||||||
|
}
|
||||||
|
result.Succeeded = true;
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
queueItem.ItemProcessed.WaitOne();
|
||||||
|
if (queueItem.GetResultAsT<FileBrowserCloseResponse>() != null)
|
||||||
|
{
|
||||||
|
result = queueItem.GetResultAsT<FileBrowserCloseResponse>();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fileBrowserQueue.CloseConnections(connInfo.ConnectionDetails.ServerName, connInfo.ConnectionDetails.DatabaseName, DefaultTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.Write(LogLevel.Error, "Unexpected exception while closing file browser: " + ex.Message);
|
||||||
|
result.Message = ex.Message;
|
||||||
|
}
|
||||||
|
|
||||||
|
await requestContext.SendEvent(FileBrowserClosedNotification.Type, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task RunFileBrowserOpenTask(FileBrowserOpenParams fileBrowserParams, RequestContext<bool> requestContext)
|
internal async Task RunFileBrowserOpenTask(FileBrowserOpenParams fileBrowserParams, RequestContext<bool> requestContext)
|
||||||
{
|
{
|
||||||
FileBrowserOpenedParams result = new FileBrowserOpenedParams();
|
FileBrowserOpenedParams result = new FileBrowserOpenedParams();
|
||||||
SqlConnection conn = null;
|
|
||||||
FileBrowserOperation browser = null;
|
FileBrowserOperation browser = null;
|
||||||
bool isCancelRequested = false;
|
bool isCancelRequested = false;
|
||||||
|
|
||||||
if (this.expandNodeQueue.IsCancelRequested)
|
|
||||||
{
|
|
||||||
this.expandNodeQueue.StartQueueProcessor();
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!fileBrowserParams.ChangeFilter)
|
ConnectionInfo connInfo;
|
||||||
|
this.ConnectionServiceInstance.TryFindConnection(fileBrowserParams.OwnerUri, out connInfo);
|
||||||
|
if (connInfo != null)
|
||||||
{
|
{
|
||||||
ConnectionInfo connInfo;
|
QueueItem queueItem = fileBrowserQueue.QueueBindingOperation(
|
||||||
this.ConnectionServiceInstance.TryFindConnection(fileBrowserParams.OwnerUri, out connInfo);
|
key: fileBrowserQueue.AddConnectionContext(connInfo, this.serviceName),
|
||||||
if (connInfo != null)
|
bindingTimeout: DefaultTimeout,
|
||||||
{
|
waitForLockTimeout: DefaultTimeout,
|
||||||
// Open new connection for each Open request
|
bindOperation: (bindingContext, cancelToken) =>
|
||||||
conn = ConnectionService.OpenSqlConnection(connInfo, this.serviceName);
|
{
|
||||||
browser = new FileBrowserOperation(conn, fileBrowserParams.ExpandPath, fileBrowserParams.FileFilters);
|
if (!fileBrowserParams.ChangeFilter)
|
||||||
}
|
{
|
||||||
}
|
browser = new FileBrowserOperation(bindingContext.ServerConnection, fileBrowserParams.ExpandPath, fileBrowserParams.FileFilters);
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
ownerToFileBrowserMap.TryGetValue(fileBrowserParams.OwnerUri, out browser);
|
{
|
||||||
if (browser != null)
|
ownerToFileBrowserMap.TryGetValue(fileBrowserParams.OwnerUri, out browser);
|
||||||
{
|
if (browser != null)
|
||||||
browser.Initialize(fileBrowserParams.ExpandPath, fileBrowserParams.FileFilters);
|
{
|
||||||
}
|
browser.Initialize(fileBrowserParams.ExpandPath, fileBrowserParams.FileFilters);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (browser != null)
|
if (browser != null)
|
||||||
{
|
{
|
||||||
ownerToFileBrowserMap.AddOrUpdate(fileBrowserParams.OwnerUri, browser, (key, value) => browser);
|
ownerToFileBrowserMap.AddOrUpdate(fileBrowserParams.OwnerUri, browser, (key, value) => browser);
|
||||||
|
|
||||||
// Create file browser tree
|
// Create file browser tree
|
||||||
browser.PopulateFileTree();
|
browser.PopulateFileTree();
|
||||||
|
|
||||||
// Check if cancel was requested
|
if (browser.IsCancellationRequested)
|
||||||
if (browser.IsCancellationRequested)
|
{
|
||||||
|
isCancelRequested = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.OwnerUri = fileBrowserParams.OwnerUri;
|
||||||
|
result.FileTree = browser.FileTree;
|
||||||
|
result.Succeeded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
queueItem.ItemProcessed.WaitOne();
|
||||||
|
|
||||||
|
if (queueItem.GetResultAsT<FileBrowserOpenedParams>() != null)
|
||||||
{
|
{
|
||||||
browser.Dispose();
|
result = queueItem.GetResultAsT<FileBrowserOpenedParams>();
|
||||||
isCancelRequested = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result.OwnerUri = fileBrowserParams.OwnerUri;
|
|
||||||
result.FileTree = browser.FileTree;
|
|
||||||
result.Succeeded = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,32 +288,29 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
FileBrowserExpandedParams result = new FileBrowserExpandedParams();
|
FileBrowserExpandedParams result = new FileBrowserExpandedParams();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
FileBrowserOperation operation;
|
FileBrowserOperation operation = null;
|
||||||
ConnectionInfo connInfo;
|
ConnectionInfo connInfo;
|
||||||
result.Succeeded = ownerToFileBrowserMap.TryGetValue(fileBrowserParams.OwnerUri, out operation);
|
ownerToFileBrowserMap.TryGetValue(fileBrowserParams.OwnerUri, out operation);
|
||||||
this.ConnectionServiceInstance.TryFindConnection(fileBrowserParams.OwnerUri, out connInfo);
|
this.ConnectionServiceInstance.TryFindConnection(fileBrowserParams.OwnerUri, out connInfo);
|
||||||
|
|
||||||
if (result.Succeeded && operation != null && connInfo != null)
|
if (operation != null && connInfo != null)
|
||||||
{
|
{
|
||||||
QueueItem queueItem = expandNodeQueue.QueueBindingOperation(
|
QueueItem queueItem = fileBrowserQueue.QueueBindingOperation(
|
||||||
key: expandNodeQueue.AddConnectionContext(connInfo, this.serviceName),
|
key: fileBrowserQueue.AddConnectionContext(connInfo, this.serviceName),
|
||||||
bindingTimeout: DefaultExpandTimeout,
|
bindingTimeout: DefaultTimeout,
|
||||||
waitForLockTimeout: DefaultExpandTimeout,
|
waitForLockTimeout: DefaultTimeout,
|
||||||
bindOperation: (bindingContext, cancelToken) =>
|
bindOperation: (bindingContext, cancelToken) =>
|
||||||
{
|
{
|
||||||
result.ExpandPath = fileBrowserParams.ExpandPath;
|
result.ExpandPath = fileBrowserParams.ExpandPath;
|
||||||
result.Children = operation.GetChildren(fileBrowserParams.ExpandPath).ToArray();
|
result.Children = operation.GetChildren(fileBrowserParams.ExpandPath).ToArray();
|
||||||
result.OwnerUri = fileBrowserParams.OwnerUri;
|
result.OwnerUri = fileBrowserParams.OwnerUri;
|
||||||
|
result.Succeeded = true;
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
queueItem.ItemProcessed.WaitOne();
|
queueItem.ItemProcessed.WaitOne();
|
||||||
|
|
||||||
if (this.expandNodeQueue.IsCancelRequested)
|
if (queueItem.GetResultAsT<FileBrowserExpandedParams>() != null)
|
||||||
{
|
|
||||||
this.expandNodeQueue.CloseConnections(operation.SqlConnection.DataSource, operation.SqlConnection.Database, DefaultExpandTimeout);
|
|
||||||
}
|
|
||||||
else if (queueItem.GetResultAsT<FileBrowserExpandedParams>() != null)
|
|
||||||
{
|
{
|
||||||
result = queueItem.GetResultAsT<FileBrowserExpandedParams>();
|
result = queueItem.GetResultAsT<FileBrowserExpandedParams>();
|
||||||
}
|
}
|
||||||
@@ -268,7 +318,6 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
result.Succeeded = false;
|
|
||||||
result.Message = ex.Message;
|
result.Message = ex.Message;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,22 +331,36 @@ namespace Microsoft.SqlTools.ServiceLayer.FileBrowser
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
ValidatePathsCallback callback;
|
ValidatePathsCallback callback;
|
||||||
|
ConnectionInfo connInfo;
|
||||||
|
this.ConnectionServiceInstance.TryFindConnection(fileBrowserParams.OwnerUri, out connInfo);
|
||||||
if (validatePathsCallbackMap.TryGetValue(fileBrowserParams.ServiceType, out callback)
|
if (validatePathsCallbackMap.TryGetValue(fileBrowserParams.ServiceType, out callback)
|
||||||
&& callback != null
|
&& callback != null
|
||||||
|
&& connInfo != null
|
||||||
&& fileBrowserParams.SelectedFiles != null
|
&& fileBrowserParams.SelectedFiles != null
|
||||||
&& fileBrowserParams.SelectedFiles.Length > 0)
|
&& fileBrowserParams.SelectedFiles.Length > 0)
|
||||||
{
|
{
|
||||||
string errorMessage;
|
QueueItem queueItem = fileBrowserQueue.QueueBindingOperation(
|
||||||
result.Succeeded = callback(new FileBrowserValidateEventArgs
|
key: fileBrowserQueue.AddConnectionContext(connInfo, this.serviceName),
|
||||||
{
|
bindingTimeout: DefaultTimeout,
|
||||||
ServiceType = fileBrowserParams.ServiceType,
|
waitForLockTimeout: DefaultTimeout,
|
||||||
OwnerUri = fileBrowserParams.OwnerUri,
|
bindOperation: (bindingContext, cancelToken) =>
|
||||||
FilePaths = fileBrowserParams.SelectedFiles
|
{
|
||||||
}, out errorMessage);
|
string errorMessage;
|
||||||
|
result.Succeeded = callback(new FileBrowserValidateEventArgs
|
||||||
|
{
|
||||||
|
ServiceType = fileBrowserParams.ServiceType,
|
||||||
|
OwnerUri = fileBrowserParams.OwnerUri,
|
||||||
|
FilePaths = fileBrowserParams.SelectedFiles
|
||||||
|
}, out errorMessage);
|
||||||
|
result.Message = errorMessage;
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(errorMessage))
|
queueItem.ItemProcessed.WaitOne();
|
||||||
|
|
||||||
|
if (queueItem.GetResultAsT<FileBrowserValidatedParams>() != null)
|
||||||
{
|
{
|
||||||
result.Message = errorMessage;
|
result = queueItem.GetResultAsT<FileBrowserValidatedParams>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -388,6 +388,20 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clear queued items
|
||||||
|
/// </summary>
|
||||||
|
public void ClearQueuedItems()
|
||||||
|
{
|
||||||
|
lock (this.bindingQueueLock)
|
||||||
|
{
|
||||||
|
if (this.bindingQueue.Count > 0)
|
||||||
|
{
|
||||||
|
this.bindingQueue.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (this.processQueueCancelToken != null)
|
if (this.processQueueCancelToken != null)
|
||||||
|
|||||||
@@ -76,6 +76,6 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the database compatibility level
|
/// Gets or sets the database compatibility level
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DatabaseCompatibilityLevel DatabaseCompatibilityLevel { get; }
|
DatabaseCompatibilityLevel DatabaseCompatibilityLevel { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,9 +91,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.FileBrowser
|
|||||||
};
|
};
|
||||||
|
|
||||||
await service.HandleFileBrowserCloseRequest(inputParams, requestContext.Object);
|
await service.HandleFileBrowserCloseRequest(inputParams, requestContext.Object);
|
||||||
|
requestContext.Verify(x => x.SendResult(It.Is<FileBrowserCloseResponse>(p => p.Succeeded == true)));
|
||||||
// Result should return false since it's trying to close a filebrowser that was never opened
|
|
||||||
requestContext.Verify(x => x.SendResult(It.Is<FileBrowserCloseResponse>(p => p.Succeeded == false)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.FileBrowser
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void FilterFilesTest()
|
public void FilterFilesTest()
|
||||||
{
|
{
|
||||||
FileBrowserOperation operation = new FileBrowserOperation();
|
FileBrowserOperation operation = new FileBrowserOperation(null, "", null);
|
||||||
string[] supportedFilePaths = new string[] {"te\\s/t1.txt", "te!s.t2.bak" };
|
string[] supportedFilePaths = new string[] {"te\\s/t1.txt", "te!s.t2.bak" };
|
||||||
string[] unsupportedFilePaths = new string[] { "te.s*/t3.jpg", "t_est4.trn" };
|
string[] unsupportedFilePaths = new string[] { "te.s*/t3.jpg", "t_est4.trn" };
|
||||||
string[] filters = new string[] { "*.txt", "*.bak"};
|
string[] filters = new string[] { "*.txt", "*.bak"};
|
||||||
@@ -47,7 +47,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.FileBrowser
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void ExpandNodeShouldThrowExceptionForInvalidPath()
|
public void ExpandNodeShouldThrowExceptionForInvalidPath()
|
||||||
{
|
{
|
||||||
FileBrowserOperation operation = new FileBrowserOperation();
|
FileBrowserOperation operation = new FileBrowserOperation(null, "", null);
|
||||||
Exception exception = null;
|
Exception exception = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|||||||
Reference in New Issue
Block a user