mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
CB-6089 write file stream directly to http response (#3301)
* CB-6089 write file stream directly to http response * CB-6089 write file stream directly to http response * CB-6089 write file stream directly to http response * CB-6089 write file stream directly to http response * CB-6089 write file stream directly to http response * CB-6089 remove deprecated method * CB-6089 change ParquetExporter buffer size * CB-6089 remove extra async * CB-6089 add info text --------- Co-authored-by: naumov <iamemptyhuh@gmail.com> Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com> Co-authored-by: Ainur <59531286+yagudin10@users.noreply.github.com>
This commit is contained in:
co-authored by
naumov
Evgenia
Ainur
parent
e87e3397e2
commit
655613ccf1
+1
-1
@@ -73,6 +73,6 @@ extend type Query {
|
||||
parameters: DataTransferParameters!
|
||||
): AsyncTaskInfo!
|
||||
|
||||
dataTransferRemoveDataFile(dataFileId: String!): Boolean
|
||||
dataTransferRemoveDataFile(dataFileId: String!): Boolean @deprecated(reason: "25.0.1")
|
||||
|
||||
}
|
||||
|
||||
+18
@@ -24,11 +24,15 @@ import io.cloudbeaver.service.DBWService;
|
||||
import io.cloudbeaver.service.data.transfer.impl.WebDataTransferDefaultExportSettings;
|
||||
import io.cloudbeaver.service.data.transfer.impl.WebDataTransferParameters;
|
||||
import io.cloudbeaver.service.data.transfer.impl.WebDataTransferStreamProcessor;
|
||||
import io.cloudbeaver.service.data.transfer.impl.WebDataTransferTaskConfig;
|
||||
import io.cloudbeaver.service.sql.WebSQLContextInfo;
|
||||
import io.cloudbeaver.service.sql.WebSQLProcessor;
|
||||
import io.cloudbeaver.service.sql.WebSQLResultsInfo;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
@@ -62,8 +66,22 @@ public interface DBWServiceDataTransfer extends DBWService {
|
||||
String resultsId,
|
||||
WebDataTransferParameters parameters) throws DBWebException;
|
||||
|
||||
/**
|
||||
* It's deprecated because now we use streaming file to response directly, and we don't need to clean up any files
|
||||
* after data transfer.
|
||||
*/
|
||||
@WebAction
|
||||
@Deprecated
|
||||
Boolean dataTransferRemoveDataFile(WebSession session, String dataFileId) throws DBWebException;
|
||||
|
||||
WebDataTransferDefaultExportSettings defaultExportSettings();
|
||||
|
||||
/**
|
||||
* Usefully for exporting directly to http response and avoid to create temp files.
|
||||
*/
|
||||
void exportDataTransferToStream(
|
||||
@NotNull DBRProgressMonitor monitor,
|
||||
@NotNull WebDataTransferTaskConfig taskConfig,
|
||||
@NotNull OutputStream outputStream
|
||||
) throws DBException;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,10 +21,10 @@ import io.cloudbeaver.service.DBWBindingContext;
|
||||
import io.cloudbeaver.service.DBWServiceBindingServlet;
|
||||
import io.cloudbeaver.service.DBWServletContext;
|
||||
import io.cloudbeaver.service.WebServiceBindingBase;
|
||||
import io.cloudbeaver.service.data.transfer.impl.WebDataTransferImportServlet;
|
||||
import io.cloudbeaver.service.data.transfer.impl.WebDataTransferParameters;
|
||||
import io.cloudbeaver.service.data.transfer.impl.WebDataTransferServlet;
|
||||
import io.cloudbeaver.service.data.transfer.impl.WebServiceDataTransfer;
|
||||
import io.cloudbeaver.service.data.transfer.impl.WebDataTransferImportServlet;
|
||||
import io.cloudbeaver.service.sql.WebServiceBindingSQL;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
|
||||
|
||||
+1
-16
@@ -28,13 +28,8 @@ import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.tools.transfer.registry.DataTransferProcessorDescriptor;
|
||||
import org.jkiss.dbeaver.tools.transfer.registry.DataTransferRegistry;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
import org.jkiss.utils.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
||||
public class WebDataTransferServlet extends WebServiceServletBase {
|
||||
|
||||
@@ -73,20 +68,10 @@ public class WebDataTransferServlet extends WebServiceServletBase {
|
||||
fileName = taskInfo.getDataFileId();
|
||||
}
|
||||
fileName = WebDataTransferUtils.normalizeFileName(fileName, taskInfo.getParameters().getOutputSettings());
|
||||
Path dataFile = taskInfo.getDataFile();
|
||||
session.addInfoMessage("Download data ...");
|
||||
response.setHeader("Content-Type", processor.getContentType());
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
|
||||
response.setHeader("Content-Length", String.valueOf(Files.size(dataFile)));
|
||||
|
||||
try (InputStream is = Files.newInputStream(dataFile)) {
|
||||
IOUtils.copyStream(is, response.getOutputStream());
|
||||
}
|
||||
|
||||
// TODO: cleanup export files ASAP?
|
||||
if (false) {
|
||||
dtConfig.removeTask(taskInfo);
|
||||
}
|
||||
dtManager.exportDataTransferToStream(session.getProgressMonitor(), taskInfo, response.getOutputStream());
|
||||
}
|
||||
|
||||
}
|
||||
+1
-9
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,16 +36,8 @@ public class WebDataTransferSessionConfig {
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTask(WebDataTransferTaskConfig taskConfig) {
|
||||
synchronized (tasks) {
|
||||
tasks.remove(taskConfig.getDataFileId());
|
||||
taskConfig.deleteFile();
|
||||
}
|
||||
}
|
||||
|
||||
public WebDataTransferSessionConfig deleteExportFiles() {
|
||||
synchronized (tasks) {
|
||||
tasks.values().forEach(WebDataTransferTaskConfig::deleteFile);
|
||||
tasks.clear();
|
||||
}
|
||||
return this;
|
||||
|
||||
+22
-21
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,31 +16,36 @@
|
||||
*/
|
||||
package io.cloudbeaver.service.data.transfer.impl;
|
||||
|
||||
import io.cloudbeaver.service.sql.WebSQLResultsInfo;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import org.jkiss.dbeaver.model.struct.DBSDataContainer;
|
||||
|
||||
public class WebDataTransferTaskConfig {
|
||||
|
||||
private static final Log log = Log.getLog(WebDataTransferTaskConfig.class);
|
||||
|
||||
private Path dataFile;
|
||||
private String fileNameKey;
|
||||
private WebDataTransferParameters parameters;
|
||||
private String exportFileName;
|
||||
private DBSDataContainer dataContainer;
|
||||
private WebSQLResultsInfo resultsInfo;
|
||||
|
||||
public WebDataTransferTaskConfig(Path dataFile, WebDataTransferParameters parameters) {
|
||||
this.dataFile = dataFile;
|
||||
public WebDataTransferTaskConfig(
|
||||
String fileNameKey,
|
||||
WebDataTransferParameters parameters,
|
||||
String exportFileName,
|
||||
DBSDataContainer dataContainer,
|
||||
WebSQLResultsInfo webSQLResultsInfo
|
||||
) {
|
||||
this.fileNameKey = fileNameKey;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public Path getDataFile() {
|
||||
return dataFile;
|
||||
this.exportFileName = exportFileName;
|
||||
this.dataContainer = dataContainer;
|
||||
this.resultsInfo = webSQLResultsInfo;
|
||||
}
|
||||
|
||||
public String getDataFileId() {
|
||||
return dataFile.getFileName().toString();
|
||||
return fileNameKey;
|
||||
}
|
||||
|
||||
public WebDataTransferParameters getParameters() {
|
||||
@@ -51,15 +56,11 @@ public class WebDataTransferTaskConfig {
|
||||
return exportFileName;
|
||||
}
|
||||
|
||||
public void setExportFileName(String exportFileName) {
|
||||
this.exportFileName = exportFileName;
|
||||
public DBSDataContainer getDataContainer() {
|
||||
return dataContainer;
|
||||
}
|
||||
|
||||
public void deleteFile() {
|
||||
try {
|
||||
Files.delete(dataFile);
|
||||
} catch (IOException e) {
|
||||
log.error("Error deleting export file " + dataFile.toAbsolutePath(), e);
|
||||
}
|
||||
public WebSQLResultsInfo getResultsInfo() {
|
||||
return resultsInfo;
|
||||
}
|
||||
}
|
||||
+89
-127
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2010-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,7 +20,6 @@ import io.cloudbeaver.DBWebException;
|
||||
import io.cloudbeaver.model.WebAsyncTaskInfo;
|
||||
import io.cloudbeaver.model.session.WebAsyncTaskProcessor;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.server.CBApplication;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import io.cloudbeaver.service.data.transfer.DBWServiceDataTransfer;
|
||||
import io.cloudbeaver.service.sql.WebSQLContextInfo;
|
||||
@@ -30,14 +29,9 @@ import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.exec.DBCException;
|
||||
import org.jkiss.dbeaver.model.exec.DBCResultSet;
|
||||
import org.jkiss.dbeaver.model.exec.DBCSession;
|
||||
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
|
||||
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
|
||||
import org.jkiss.dbeaver.model.runtime.VoidProgressMonitor;
|
||||
import org.jkiss.dbeaver.model.sql.DBQuotaException;
|
||||
import org.jkiss.dbeaver.model.sql.DBSQLException;
|
||||
import org.jkiss.dbeaver.model.struct.DBSDataContainer;
|
||||
import org.jkiss.dbeaver.model.struct.DBSDataManipulator;
|
||||
import org.jkiss.dbeaver.model.struct.DBSEntity;
|
||||
@@ -51,13 +45,11 @@ import org.jkiss.dbeaver.tools.transfer.stream.*;
|
||||
import org.jkiss.dbeaver.utils.ContentUtils;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.sql.BatchUpdateException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -66,8 +58,6 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class WebServiceDataTransfer implements DBWServiceDataTransfer {
|
||||
|
||||
public static final String QUOTA_PROP_FILE_LIMIT = "dataExportFileSizeLimit";
|
||||
|
||||
private static final Log log = Log.getLog(WebServiceDataTransfer.class);
|
||||
|
||||
private final Path dataExportFolder;
|
||||
@@ -145,79 +135,66 @@ public class WebServiceDataTransfer implements DBWServiceDataTransfer {
|
||||
return asyncExportFromDataContainer(sqlContext.getProcessor(), parameters, results.getDataContainer(), results);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean dataTransferRemoveDataFile(WebSession webSession, String dataFileId) throws DBWebException {
|
||||
WebDataTransferSessionConfig dtConfig = WebDataTransferUtils.getSessionDataTransferConfig(webSession);
|
||||
WebDataTransferTaskConfig taskInfo = dtConfig.getTask(dataFileId);
|
||||
if (taskInfo == null) {
|
||||
throw new DBWebException("Session task '" + dataFileId + "' not found");
|
||||
}
|
||||
Path dataFile = taskInfo.getDataFile();
|
||||
if (dataFile != null) {
|
||||
try {
|
||||
Files.delete(dataFile);
|
||||
} catch (IOException e) {
|
||||
log.warn("Error deleting data file '" + dataFile.toAbsolutePath() + "'", e);
|
||||
}
|
||||
}
|
||||
dtConfig.removeTask(taskInfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebDataTransferDefaultExportSettings defaultExportSettings() {
|
||||
return new WebDataTransferDefaultExportSettings();
|
||||
}
|
||||
|
||||
private WebAsyncTaskInfo asyncExportFromDataContainer(WebSQLProcessor sqlProcessor, WebDataTransferParameters parameters, DBSDataContainer dataContainer,
|
||||
@Nullable WebSQLResultsInfo resultsInfo) {
|
||||
@Override
|
||||
@Deprecated
|
||||
public Boolean dataTransferRemoveDataFile(WebSession webSession, String dataFileId) throws DBWebException {
|
||||
//deprecated
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exportDataTransferToStream(
|
||||
@NotNull DBRProgressMonitor monitor,
|
||||
@NotNull WebDataTransferTaskConfig taskConfig,
|
||||
@NotNull OutputStream outputStream
|
||||
) throws DBException {
|
||||
|
||||
WebDataTransferParameters parameters = taskConfig.getParameters();
|
||||
DBSDataContainer dataContainer = taskConfig.getDataContainer();
|
||||
WebSQLResultsInfo resultsInfo = taskConfig.getResultsInfo();
|
||||
DataTransferProcessorDescriptor processor = DataTransferRegistry.getInstance().getProcessor(parameters.getProcessorId());
|
||||
|
||||
try {
|
||||
exportData(monitor, processor, dataContainer, parameters, resultsInfo, outputStream);
|
||||
} catch (Exception e) {
|
||||
throw new DBException("Error exporting data", e);
|
||||
}
|
||||
}
|
||||
|
||||
private WebAsyncTaskInfo asyncExportFromDataContainer(
|
||||
@NotNull WebSQLProcessor sqlProcessor,
|
||||
@NotNull WebDataTransferParameters parameters,
|
||||
@NotNull DBSDataContainer dataContainer,
|
||||
@Nullable WebSQLResultsInfo resultsInfo
|
||||
) {
|
||||
sqlProcessor.getWebSession().addInfoMessage("Export data");
|
||||
DataTransferProcessorDescriptor processor = DataTransferRegistry.getInstance().getProcessor(parameters.getProcessorId());
|
||||
WebAsyncTaskProcessor<String> runnable = new WebAsyncTaskProcessor<String>() {
|
||||
@Override
|
||||
public void run(DBRProgressMonitor monitor) throws InvocationTargetException {
|
||||
monitor.beginTask("Export data", 1);
|
||||
try {
|
||||
monitor.subTask("Export data using " + processor.getName());
|
||||
Path exportFile = dataExportFolder.resolve(
|
||||
makeUniqueFileName(sqlProcessor, processor, parameters.getProcessorProperties()));
|
||||
try {
|
||||
exportData(monitor, processor, dataContainer, parameters, resultsInfo, exportFile);
|
||||
} catch (Exception e) {
|
||||
if (Files.exists(exportFile)) {
|
||||
try {
|
||||
Files.delete(exportFile);
|
||||
} catch (IOException ex) {
|
||||
log.error("Error deleting export file " + exportFile.toAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
if (e instanceof DBException) {
|
||||
throw e;
|
||||
}
|
||||
throw new DBException("Error exporting data", e);
|
||||
}
|
||||
var outputSettings = parameters.getOutputSettings();
|
||||
Path finallyExportFile = outputSettings.isCompress()
|
||||
? exportFile.resolveSibling(WebDataTransferUtils.normalizeFileName(
|
||||
exportFile.getFileName().toString(), outputSettings))
|
||||
: exportFile;
|
||||
WebDataTransferTaskConfig taskConfig = new WebDataTransferTaskConfig(finallyExportFile, parameters);
|
||||
String exportFileName = CommonUtils.isEmpty(outputSettings.getFileName()) ?
|
||||
CommonUtils.escapeFileName(CommonUtils.truncateString(dataContainer.getName(), 32)) :
|
||||
outputSettings.getFileName();
|
||||
taskConfig.setExportFileName(exportFileName);
|
||||
WebDataTransferUtils.getSessionDataTransferConfig(sqlProcessor.getWebSession()).addTask(taskConfig);
|
||||
String uniqueFileName = makeUniqueFileName(sqlProcessor, processor, parameters.getProcessorProperties());
|
||||
var outputSettings = parameters.getOutputSettings();
|
||||
String fileNameKey = WebDataTransferUtils.normalizeFileName(uniqueFileName, outputSettings);
|
||||
String exportFileName = CommonUtils.isEmpty(outputSettings.getFileName())
|
||||
? CommonUtils.escapeFileName(CommonUtils.truncateString(dataContainer.getName(), 32))
|
||||
: outputSettings.getFileName();
|
||||
WebDataTransferTaskConfig taskConfig = new WebDataTransferTaskConfig(
|
||||
fileNameKey, parameters, exportFileName, dataContainer, resultsInfo);
|
||||
|
||||
result = finallyExportFile.getFileName().toString();
|
||||
} catch (Throwable e) {
|
||||
throw new InvocationTargetException(e);
|
||||
} finally {
|
||||
monitor.done();
|
||||
WebDataTransferUtils.getSessionDataTransferConfig(sqlProcessor.getWebSession())
|
||||
.addTask(taskConfig);
|
||||
|
||||
//fixme fake task for keeping api
|
||||
return sqlProcessor.getWebSession().createAndRunAsyncTask(
|
||||
"Data export", new WebAsyncTaskProcessor<>() {
|
||||
@Override
|
||||
public void run(DBRProgressMonitor monitor) throws InvocationTargetException {
|
||||
result = fileNameKey;
|
||||
}
|
||||
}
|
||||
};
|
||||
return sqlProcessor.getWebSession().createAndRunAsyncTask("Data export", runnable);
|
||||
);
|
||||
}
|
||||
|
||||
public WebAsyncTaskInfo asyncImportDataContainer(@NotNull String processorId,
|
||||
@@ -263,34 +240,50 @@ public class WebServiceDataTransfer implements DBWServiceDataTransfer {
|
||||
DBSDataContainer dataContainer,
|
||||
WebDataTransferParameters parameters,
|
||||
WebSQLResultsInfo resultsInfo,
|
||||
Path exportFile) throws DBException, IOException
|
||||
{
|
||||
OutputStream outputStream
|
||||
) throws DBException, IOException {
|
||||
IDataTransferProcessor processorInstance = processor.getInstance();
|
||||
if (!(processorInstance instanceof IStreamDataExporter)) {
|
||||
if (!(processorInstance instanceof IStreamDataExporter exporter)) {
|
||||
throw new DBException("Invalid processor. " + IStreamDataExporter.class.getSimpleName() + " expected");
|
||||
}
|
||||
IStreamDataExporter exporter = (IStreamDataExporter) processorInstance;
|
||||
|
||||
Number fileSizeLimit = CBApplication.getInstance().getAppConfiguration().getResourceQuota(QUOTA_PROP_FILE_LIMIT);
|
||||
Map<String, Object> processorProperties = parameters.getProcessorProperties();
|
||||
if (processorProperties == null) processorProperties = Collections.emptyMap();
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
for (DBPPropertyDescriptor prop : processor.getProperties()) {
|
||||
Object propValue = processorProperties.get(CommonUtils.toString(prop.getId()));
|
||||
properties.put(prop.getId(), propValue != null ? propValue : prop.getDefaultValue());
|
||||
}
|
||||
// Remove extension property (we specify file name directly)
|
||||
properties.remove(StreamConsumerSettings.PROP_FILE_EXTENSION);
|
||||
|
||||
StreamTransferConsumer consumer = new StreamTransferConsumer() {
|
||||
@Override
|
||||
public void fetchRow(@NotNull DBCSession session, @NotNull DBCResultSet resultSet) throws DBCException {
|
||||
super.fetchRow(session, resultSet);
|
||||
if (fileSizeLimit != null && getBytesWritten() > fileSizeLimit.longValue()) {
|
||||
throw new DBQuotaException(
|
||||
"Data export quota exceeded \n Please increase the resourceQuotas parameter in configuration",
|
||||
QUOTA_PROP_FILE_LIMIT, fileSizeLimit.longValue(), getBytesWritten()
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
DatabaseProducerSettings producerSettings = new DatabaseProducerSettings();
|
||||
producerSettings.setExtractType(DatabaseProducerSettings.ExtractType.SINGLE_QUERY);
|
||||
producerSettings.setQueryRowCount(false);
|
||||
producerSettings.setOpenNewConnections(CommonUtils.getOption(parameters.getDbProducerSettings(), "openNewConnection"));
|
||||
StreamTransferConsumer consumer = new StreamTransferConsumer();
|
||||
StreamConsumerSettings settings = makeStreamConsumerSettings(parameters);
|
||||
DatabaseTransferProducer producer = new DatabaseTransferProducer(
|
||||
dataContainer,
|
||||
parameters.getFilter() == null ? null : parameters.getFilter().makeDataFilter(resultsInfo));
|
||||
|
||||
consumer.initTransfer(
|
||||
dataContainer,
|
||||
settings,
|
||||
new IDataTransferConsumer.TransferParameters(processor.isBinaryFormat(), processor.isHTMLFormat(), outputStream),
|
||||
exporter,
|
||||
properties,
|
||||
producer.getProject());
|
||||
|
||||
producer.transferData(monitor, consumer, null, producerSettings, null);
|
||||
|
||||
consumer.finishTransfer(monitor, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StreamConsumerSettings makeStreamConsumerSettings(@NotNull WebDataTransferParameters parameters) {
|
||||
StreamConsumerSettings settings = new StreamConsumerSettings();
|
||||
|
||||
settings.setOutputFolder(exportFile.getParent().toAbsolutePath().toString());
|
||||
settings.setOutputFilePattern(exportFile.getFileName().toString());
|
||||
|
||||
WebDataTransferOutputSettings outputSettings = parameters.getOutputSettings();
|
||||
settings.setOutputEncodingBOM(outputSettings.isInsertBom());
|
||||
settings.setCompressResults(outputSettings.isCompress());
|
||||
@@ -300,38 +293,7 @@ public class WebServiceDataTransfer implements DBWServiceDataTransfer {
|
||||
if (!CommonUtils.isEmpty(outputSettings.getTimestampPattern())) {
|
||||
settings.setOutputTimestampPattern(outputSettings.getTimestampPattern());
|
||||
}
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
|
||||
Map<String, Object> processorProperties = parameters.getProcessorProperties();
|
||||
if (processorProperties == null) processorProperties = Collections.emptyMap();
|
||||
for (DBPPropertyDescriptor prop : processor.getProperties()) {
|
||||
Object propValue = processorProperties.get(CommonUtils.toString(prop.getId()));
|
||||
properties.put(prop.getId(), propValue != null ? propValue : prop.getDefaultValue());
|
||||
}
|
||||
// Remove extension property (we specify file name directly)
|
||||
properties.remove(StreamConsumerSettings.PROP_FILE_EXTENSION);
|
||||
|
||||
|
||||
DatabaseTransferProducer producer = new DatabaseTransferProducer(
|
||||
dataContainer,
|
||||
parameters.getFilter() == null ? null : parameters.getFilter().makeDataFilter(resultsInfo));
|
||||
DatabaseProducerSettings producerSettings = new DatabaseProducerSettings();
|
||||
producerSettings.setExtractType(DatabaseProducerSettings.ExtractType.SINGLE_QUERY);
|
||||
producerSettings.setQueryRowCount(false);
|
||||
producerSettings.setOpenNewConnections(CommonUtils.getOption(parameters.getDbProducerSettings(), "openNewConnection"));
|
||||
|
||||
consumer.initTransfer(
|
||||
dataContainer,
|
||||
settings,
|
||||
new IDataTransferConsumer.TransferParameters(processor.isBinaryFormat(), processor.isHTMLFormat()),
|
||||
exporter,
|
||||
properties,
|
||||
producer.getProject());
|
||||
|
||||
producer.transferData(monitor, consumer, null, producerSettings, null);
|
||||
|
||||
consumer.finishTransfer(monitor, false);
|
||||
return settings;
|
||||
}
|
||||
|
||||
private void importData(
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
query removeDataTransferFile(
|
||||
$dataFileId: String!
|
||||
) {
|
||||
result: dataTransferRemoveDataFile(dataFileId: $dataFileId)
|
||||
}
|
||||
@@ -36,7 +36,7 @@ export class DataExportProcessService {
|
||||
private readonly notificationService: NotificationService,
|
||||
) {}
|
||||
|
||||
async cancel(exportId: string): Promise<void> {
|
||||
cancel(exportId: string): void {
|
||||
const process = this.exportProcesses.get(exportId);
|
||||
if (!process) {
|
||||
return;
|
||||
@@ -44,21 +44,14 @@ export class DataExportProcessService {
|
||||
process.process.cancel();
|
||||
}
|
||||
|
||||
async delete(exportId: string): Promise<void> {
|
||||
delete(exportId: string): void {
|
||||
const process = this.exportProcesses.get(exportId);
|
||||
|
||||
if (!process) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const dataFileId = process.process.getPayload();
|
||||
if (dataFileId) {
|
||||
await this.graphQLService.sdk.removeDataTransferFile({ dataFileId });
|
||||
}
|
||||
} catch (exception: any) {
|
||||
this.notificationService.logException(exception, 'Error occurred while deleting file');
|
||||
} finally {
|
||||
this.exportProcesses.remove(exportId);
|
||||
}
|
||||
|
||||
this.exportProcesses.remove(exportId);
|
||||
}
|
||||
|
||||
download(exportId: string): void {
|
||||
|
||||
@@ -24,10 +24,6 @@ export class DataExportService {
|
||||
await this.dataExportProcessService.cancel(exportId);
|
||||
}
|
||||
|
||||
async delete(exportId: string): Promise<void> {
|
||||
await this.dataExportProcessService.delete(exportId);
|
||||
}
|
||||
|
||||
download(exportId: string): void {
|
||||
this.dataExportProcessService.download(exportId);
|
||||
}
|
||||
|
||||
+4
-1
@@ -14,8 +14,11 @@
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.sourceName {
|
||||
.subText {
|
||||
composes: theme-typography--body2 from global;
|
||||
}
|
||||
|
||||
.sourceName {
|
||||
padding-top: 16px;
|
||||
max-height: 50px;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
SnackbarFooter,
|
||||
SnackbarStatus,
|
||||
SnackbarWrapper,
|
||||
Text,
|
||||
useErrorDetails,
|
||||
useS,
|
||||
useTranslate,
|
||||
@@ -37,14 +38,16 @@ export const ExportNotification = observer<Props>(function ExportNotification({
|
||||
const errorDetails = useErrorDetails(state.task?.process.getRejectionReason() ?? null);
|
||||
|
||||
const { title, status, message } = state.status;
|
||||
const isReadyToDownload = status === ENotificationType.Info && !!state.downloadUrl;
|
||||
|
||||
return (
|
||||
<SnackbarWrapper persistent={status === ENotificationType.Loading} onClose={state.delete}>
|
||||
<SnackbarStatus status={status} />
|
||||
<SnackbarContent>
|
||||
<SnackbarBody title={translate(title)}>
|
||||
{isReadyToDownload && <Text className={s(style, { subText: true })}>{translate('plugin_data_export_download_process_info')}</Text>}
|
||||
{message && <div className={s(style, { message: true })}>{message}</div>}
|
||||
<div className={s(style, { sourceName: true })}>
|
||||
<div className={s(style, { subText: true, sourceName: true })}>
|
||||
{state.sourceName}
|
||||
{state.task?.context.query && (
|
||||
<pre className={s(style, { pre: true })} title={state.task.context.query}>
|
||||
@@ -54,7 +57,7 @@ export const ExportNotification = observer<Props>(function ExportNotification({
|
||||
</div>
|
||||
</SnackbarBody>
|
||||
<SnackbarFooter timestamp={notification.timestamp}>
|
||||
{status === ENotificationType.Info && state.downloadUrl && (
|
||||
{isReadyToDownload && (
|
||||
<>
|
||||
<Button type="button" mod={['outlined']} onClick={state.delete}>
|
||||
{translate('ui_processing_cancel')}
|
||||
|
||||
@@ -18,4 +18,5 @@ export default [
|
||||
|
||||
['data_transfer_output_settings', 'Output'],
|
||||
['data_transfer_output_settings_compress', 'Compression'],
|
||||
['plugin_data_export_download_process_info', 'The download process may take some time to start'],
|
||||
];
|
||||
|
||||
@@ -24,4 +24,5 @@ export default [
|
||||
['data_transfer_dialog_select_processor_fail', 'Échec de la sélection du processeur'],
|
||||
['data_transfer_output_settings', 'Sortie'],
|
||||
['data_transfer_output_settings_compress', 'Compression'],
|
||||
['plugin_data_export_download_process_info', 'The download process may take some time to start'],
|
||||
];
|
||||
|
||||
@@ -15,4 +15,5 @@ export default [
|
||||
['data_transfer_dialog_select_processor_fail', 'Failed to select processor'],
|
||||
|
||||
['data_transfer_output_settings_compress', 'Compression'],
|
||||
['plugin_data_export_download_process_info', 'The download process may take some time to start'],
|
||||
];
|
||||
|
||||
@@ -16,4 +16,5 @@ export default [
|
||||
['data_transfer_dialog_select_processor_fail', 'Не удалось выбрать обработчик данных'],
|
||||
|
||||
['data_transfer_output_settings_compress', 'Сжатие'],
|
||||
['plugin_data_export_download_process_info', 'Начало загрузки может занять некоторое время'],
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user