public Task <HttpResponseMessage> ExportFilesystem(StudioTasksController.ExportData smugglerOptionsJson) { var result = GetEmptyMessage(); var taskId = smugglerOptionsJson.ProgressTaskId; var requestString = smugglerOptionsJson.DownloadOptions; SmugglerFilesOptions smugglerOptions; using (var jsonReader = new RavenJsonTextReader(new StringReader(requestString))) { var serializer = JsonExtensions.CreateDefaultJsonSerializer(); smugglerOptions = (SmugglerFilesOptions)serializer.Deserialize(jsonReader, typeof(SmugglerFilesOptions)); } var fileName = string.IsNullOrEmpty(smugglerOptions.NoneDefualtFileName) || (smugglerOptions.NoneDefualtFileName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) ? $"Dump of {FileSystemName}, {DateTime.Now.ToString("yyyy-MM-dd HH-mm", CultureInfo.InvariantCulture)}" : smugglerOptions.NoneDefualtFileName; //create PushStreamContent object that will be called when the output stream will be ready. result.Content = new PushStreamContent(async(outputStream, content, arg3) => { var status = new DataDumperOperationStatus(); var tcs = new TaskCompletionSource <object>(); var sp = Stopwatch.StartNew(); try { FileSystem.Tasks.AddTask(tcs.Task, status, new TaskActions.PendingTaskDescription { StartTime = SystemTime.UtcNow, TaskType = TaskActions.PendingTaskType.ExportFileSystem, Payload = "Exporting file system, file name: " + fileName }, taskId, smugglerOptions.CancelToken, skipStatusCheck: true); var dataDumper = new FilesystemDataDumper(FileSystem, smugglerOptions); dataDumper.Progress += s => status.MarkProgress(s); await dataDumper.ExportData( new SmugglerExportOptions <FilesConnectionStringOptions> { ToStream = outputStream }).ConfigureAwait(false); const string message = "Completed export"; status.MarkCompleted(message, sp.Elapsed); } catch (OperationCanceledException e) { status.MarkCanceled(e.Message); } catch (Exception e) { status.ExceptionDetails = e.ToString(); status.MarkFaulted(e.ToString()); throw; } finally { tcs.SetResult("Completed"); outputStream.Close(); } }); result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = fileName + ".ravenfsdump" }; return(new CompletedTask <HttpResponseMessage>(result)); }
public async Task <HttpResponseMessage> ImportFilesystem(int batchSize, bool stripReplicationInformation, bool shouldDisableVersioningBundle) { if (!Request.Content.IsMimeMultipartContent()) { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } string tempPath = FileSystem.Configuration.TempPath; var fullTempPath = tempPath + Constants.TempUploadsDirectoryName; if (File.Exists(fullTempPath)) { File.Delete(fullTempPath); } if (Directory.Exists(fullTempPath) == false) { Directory.CreateDirectory(fullTempPath); } var streamProvider = new MultipartFileStreamProvider(fullTempPath); await Request.Content.ReadAsMultipartAsync(streamProvider).ConfigureAwait(false); var uploadedFilePath = streamProvider.FileData[0].LocalFileName; string fileName = null; var fileContent = streamProvider.Contents.SingleOrDefault(); if (fileContent != null) { fileName = fileContent.Headers.ContentDisposition.FileName.Replace("\"", string.Empty); } var status = new DataDumperOperationStatus(); var cts = new CancellationTokenSource(); var task = Task.Run(async() => { try { var dataDumper = new FilesystemDataDumper(FileSystem); dataDumper.Progress += s => status.MarkProgress(s); var smugglerOptions = dataDumper.Options; smugglerOptions.BatchSize = batchSize; smugglerOptions.ShouldDisableVersioningBundle = shouldDisableVersioningBundle; smugglerOptions.StripReplicationInformation = stripReplicationInformation; smugglerOptions.CancelToken = cts; await dataDumper.ImportData(new SmugglerImportOptions <FilesConnectionStringOptions> { FromFile = uploadedFilePath }).ConfigureAwait(false); } catch (Exception e) { if (cts.Token.IsCancellationRequested) { status.MarkCanceled("Task was cancelled"); cts.Token.ThrowIfCancellationRequested(); //needed for displaying the task status as canceled and not faulted } if (e is InvalidDataException) { status.ExceptionDetails = e.Message; } else if (e is OperationVetoedException && e.Message.Contains(VersioningTriggerActions.CreationOfHistoricalRevisionIsNotAllowed)) { status.ExceptionDetails = "You are trying to import historical documents while the versioning bundle is enabled. " + "You should disable versioning during such import. Please mark the checkbox 'Disable versioning bundle during import' at Import File System"; } else { status.ExceptionDetails = e.ToString(); } status.MarkFaulted(status.ExceptionDetails); throw; } finally { status.MarkCompleted(); File.Delete(uploadedFilePath); } }, cts.Token); long id; FileSystem.Tasks.AddTask(task, status, new TaskActions.PendingTaskDescription { StartTime = SystemTime.UtcNow, TaskType = TaskActions.PendingTaskType.ImportFileSystem, Payload = fileName }, out id, cts); return(GetMessageWithObject(new { OperationId = id }, HttpStatusCode.Accepted)); }
public async Task <HttpResponseMessage> ImportDatabase(int batchSize, bool includeExpiredDocuments, bool stripReplicationInformation, bool shouldDisableVersioningBundle, ItemType operateOnTypes, string filtersPipeDelimited, string transformScript) { if (!Request.Content.IsMimeMultipartContent()) { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } var tempPath = Database.Configuration.TempPath; var fullTempPath = tempPath + Constants.TempUploadsDirectoryName; if (File.Exists(fullTempPath)) { File.Delete(fullTempPath); } if (Directory.Exists(fullTempPath) == false) { Directory.CreateDirectory(fullTempPath); } var streamProvider = new MultipartFileStreamProvider(fullTempPath); await Request.Content.ReadAsMultipartAsync(streamProvider).ConfigureAwait(false); var uploadedFilePath = streamProvider.FileData[0].LocalFileName; string fileName = null; var fileContent = streamProvider.Contents.SingleOrDefault(); if (fileContent != null) { fileName = fileContent.Headers.ContentDisposition.FileName.Replace("\"", string.Empty); } var status = new DataDumperOperationStatus(); var cts = new CancellationTokenSource(); var user = CurrentOperationContext.User.Value; if (user == null) { user = RequestContext.Principal; } var requestDisposables = CurrentOperationContext.RequestDisposables.Value; var headers = CurrentOperationContext.Headers.Value; var task = Task.Run(async() => { try { CurrentOperationContext.User.Value = user; CurrentOperationContext.RequestDisposables.Value = requestDisposables; CurrentOperationContext.Headers.Value = headers; using (var fileStream = File.Open(uploadedFilePath, FileMode.Open, FileAccess.Read)) { var dataDumper = new DatabaseDataDumper(Database); dataDumper.Progress += s => status.MarkProgress(s); var smugglerOptions = dataDumper.Options; smugglerOptions.BatchSize = batchSize; smugglerOptions.ShouldExcludeExpired = !includeExpiredDocuments; smugglerOptions.StripReplicationInformation = stripReplicationInformation; smugglerOptions.ShouldDisableVersioningBundle = shouldDisableVersioningBundle; smugglerOptions.OperateOnTypes = operateOnTypes; smugglerOptions.TransformScript = transformScript; smugglerOptions.CancelToken = cts; // Filters are passed in without the aid of the model binder. Instead, we pass in a list of FilterSettings using a string like this: pathHere;;;valueHere;;;true|||againPathHere;;;anotherValue;;;false // Why? Because I don't see a way to pass a list of a values to a WebAPI method that accepts a file upload, outside of passing in a simple string value and parsing it ourselves. if (filtersPipeDelimited != null) { smugglerOptions.Filters.AddRange(filtersPipeDelimited .Split(new[] { "|||" }, StringSplitOptions.RemoveEmptyEntries) .Select(f => f.Split(new[] { ";;;" }, StringSplitOptions.RemoveEmptyEntries)) .Select(o => new FilterSetting { Path = o[0], Values = new List <string> { o[1] }, ShouldMatch = bool.Parse(o[2]) })); } await dataDumper.ImportData(new SmugglerImportOptions <RavenConnectionStringOptions> { FromStream = fileStream }).ConfigureAwait(false); } // use the last status which contains info about amount of doc/indexes imported status.MarkCompleted(status.State.Value <string>("Progress")); } catch (Exception e) { if (cts.Token.IsCancellationRequested) { status.MarkCanceled("Task was cancelled"); cts.Token.ThrowIfCancellationRequested(); //needed for displaying the task status as canceled and not faulted } if (e is InvalidDataException) { status.ExceptionDetails = e.Message; } else if (e is JsonReaderException) { status.ExceptionDetails = "Failed to load JSON Data. Please make sure you are importing .ravendbdump file, exported by smuggler (aka database export). If you are importing a .ravendbdump file then the file may be corrupted"; } else if (e is OperationVetoedException && e.Message.Contains(VersioningPutTrigger.CreationOfHistoricalRevisionIsNotAllowed)) { status.ExceptionDetails = "You are trying to import historical documents while the versioning bundle is enabled. " + "The versioning bundle is enabled. You should disable versioning during import. " + "Please mark the checkbox 'Disable versioning bundle during import' at Import Database: Advanced settings before importing"; } else { status.ExceptionDetails = e.ToString(); } status.MarkFaulted(e.ToString()); throw; } finally { File.Delete(uploadedFilePath); } }, cts.Token); long id; Database.Tasks.AddTask(task, status, new TaskActions.PendingTaskDescription { StartTime = SystemTime.UtcNow, TaskType = TaskActions.PendingTaskType.ExportDatabase, Description = fileName }, out id, cts); return(GetMessageWithObject(new { OperationId = id }, HttpStatusCode.Accepted)); }