SUPPORT-8662: use synchronous request-reply; fix file manager
This commit is contained in:
parent
755e0e8789
commit
25798eeb40
5 changed files with 48 additions and 91 deletions
|
|
@ -30,3 +30,6 @@ S3_ACCESS_KEY=rlTdTvkmSXu9FsLhfecw
|
||||||
S3_SECRET_KEY=NUmY0wwRIEyAd98GCKd1cOgJWvLQYAcMMul5Ulu0
|
S3_SECRET_KEY=NUmY0wwRIEyAd98GCKd1cOgJWvLQYAcMMul5Ulu0
|
||||||
S3_BUCKET_NAME=default-out-bucket
|
S3_BUCKET_NAME=default-out-bucket
|
||||||
S3_PATH_STYLE_ACCESS_ENABLED=true
|
S3_PATH_STYLE_ACCESS_ENABLED=true
|
||||||
|
|
||||||
|
WEBDAV_USERNAME=test
|
||||||
|
WEBDAV_PASSWORD=test
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
package ru.micord.ervu.av.response;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author r.latypov
|
|
||||||
*/
|
|
||||||
public record AvFileSendResponse(String id, String location, Error error, String status) {
|
|
||||||
public static final String STATUS_ERROR = "error";
|
|
||||||
|
|
||||||
public record Error(String code, String message) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,12 +6,17 @@ import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.auth.AuthScope;
|
||||||
|
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||||
|
import org.apache.http.client.CredentialsProvider;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
import org.apache.http.client.methods.HttpDelete;
|
import org.apache.http.client.methods.HttpDelete;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
import org.apache.http.client.methods.HttpGet;
|
||||||
import org.apache.http.conn.HttpHostConnectException;
|
import org.apache.http.conn.HttpHostConnectException;
|
||||||
|
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
import org.apache.http.impl.client.HttpClients;
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.retry.annotation.Backoff;
|
import org.springframework.retry.annotation.Backoff;
|
||||||
import org.springframework.retry.annotation.Retryable;
|
import org.springframework.retry.annotation.Retryable;
|
||||||
|
|
@ -20,12 +25,19 @@ import ru.micord.ervu.av.exception.FileUploadException;
|
||||||
import ru.micord.ervu.av.exception.InvalidHttpFileUrlException;
|
import ru.micord.ervu.av.exception.InvalidHttpFileUrlException;
|
||||||
import ru.micord.ervu.av.exception.RetryableException;
|
import ru.micord.ervu.av.exception.RetryableException;
|
||||||
|
|
||||||
|
import static org.springframework.util.StringUtils.hasText;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author gulnaz
|
* @author gulnaz
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class FileManager {
|
public class FileManager {
|
||||||
|
|
||||||
|
@Value("${webdav.username}")
|
||||||
|
private String username;
|
||||||
|
@Value("${webdav.password}")
|
||||||
|
private String password;
|
||||||
|
|
||||||
@Retryable(retryFor = {InvalidHttpFileUrlException.class},
|
@Retryable(retryFor = {InvalidHttpFileUrlException.class},
|
||||||
maxAttemptsExpression = "${av.retry.max.attempts.count}",
|
maxAttemptsExpression = "${av.retry.max.attempts.count}",
|
||||||
backoff = @Backoff(delayExpression = "${av.retry.delay.milliseconds}"))
|
backoff = @Backoff(delayExpression = "${av.retry.delay.milliseconds}"))
|
||||||
|
|
@ -34,7 +46,7 @@ public class FileManager {
|
||||||
File file = filePath.toFile();
|
File file = filePath.toFile();
|
||||||
HttpGet request = new HttpGet(fileUrl);
|
HttpGet request = new HttpGet(fileUrl);
|
||||||
|
|
||||||
try (CloseableHttpClient client = HttpClients.createDefault();
|
try (CloseableHttpClient client = getClientBuilder().build();
|
||||||
CloseableHttpResponse response = client.execute(request)) {
|
CloseableHttpResponse response = client.execute(request)) {
|
||||||
|
|
||||||
int statusCode = response.getStatusLine().getStatusCode();
|
int statusCode = response.getStatusLine().getStatusCode();
|
||||||
|
|
@ -67,7 +79,7 @@ public class FileManager {
|
||||||
maxAttemptsExpression = "${av.retry.max.attempts.count}",
|
maxAttemptsExpression = "${av.retry.max.attempts.count}",
|
||||||
backoff = @Backoff(delayExpression = "${av.retry.delay.milliseconds}"))
|
backoff = @Backoff(delayExpression = "${av.retry.delay.milliseconds}"))
|
||||||
public void deleteFile(String fileUrl) throws FileUploadException {
|
public void deleteFile(String fileUrl) throws FileUploadException {
|
||||||
try (CloseableHttpClient client = HttpClients.createDefault()) {
|
try (CloseableHttpClient client = getClientBuilder().build()) {
|
||||||
HttpDelete delete = new HttpDelete(fileUrl);
|
HttpDelete delete = new HttpDelete(fileUrl);
|
||||||
|
|
||||||
try (CloseableHttpResponse response = client.execute(delete)) {
|
try (CloseableHttpResponse response = client.execute(delete)) {
|
||||||
|
|
@ -83,4 +95,18 @@ public class FileManager {
|
||||||
throw new FileUploadException(e);
|
throw new FileUploadException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HttpClientBuilder getClientBuilder() {
|
||||||
|
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
|
||||||
|
|
||||||
|
if (hasText(username) && hasText(password)) {
|
||||||
|
CredentialsProvider provider = new BasicCredentialsProvider();
|
||||||
|
provider.setCredentials(
|
||||||
|
AuthScope.ANY,
|
||||||
|
new UsernamePasswordCredentials(username, password)
|
||||||
|
);
|
||||||
|
httpClientBuilder.setDefaultCredentialsProvider(provider);
|
||||||
|
}
|
||||||
|
return httpClientBuilder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,16 @@ package ru.micord.ervu.av.service;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonSyntaxException;
|
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.client.ClientProtocolException;
|
import org.apache.http.client.ClientProtocolException;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
import org.apache.http.client.methods.HttpGet;
|
|
||||||
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.client.utils.URIBuilder;
|
||||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||||
import org.apache.http.entity.mime.content.FileBody;
|
import org.apache.http.entity.mime.content.FileBody;
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
|
@ -24,7 +24,6 @@ import org.springframework.retry.annotation.Retryable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import ru.micord.ervu.av.exception.FileUploadException;
|
import ru.micord.ervu.av.exception.FileUploadException;
|
||||||
import ru.micord.ervu.av.exception.RetryableException;
|
import ru.micord.ervu.av.exception.RetryableException;
|
||||||
import ru.micord.ervu.av.response.AvFileSendResponse;
|
|
||||||
import ru.micord.ervu.av.response.AvResponse;
|
import ru.micord.ervu.av.response.AvResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -35,8 +34,6 @@ public class ReceiveScanReportRetryable {
|
||||||
|
|
||||||
@Value("${av.rest.address}")
|
@Value("${av.rest.address}")
|
||||||
private String avRestAddress;
|
private String avRestAddress;
|
||||||
@Value("${av.first.timeout.milliseconds:1000}")
|
|
||||||
private Long avFirstTimeoutMilliseconds;
|
|
||||||
|
|
||||||
@Retryable(retryFor = {RetryableException.class},
|
@Retryable(retryFor = {RetryableException.class},
|
||||||
maxAttemptsExpression = "${av.retry.max.attempts.count}",
|
maxAttemptsExpression = "${av.retry.max.attempts.count}",
|
||||||
|
|
@ -45,7 +42,10 @@ public class ReceiveScanReportRetryable {
|
||||||
File file = filePath.toFile();
|
File file = filePath.toFile();
|
||||||
|
|
||||||
try (CloseableHttpClient client = HttpClients.createDefault()) {
|
try (CloseableHttpClient client = HttpClients.createDefault()) {
|
||||||
HttpPost post = new HttpPost(avRestAddress);
|
URI uri = new URIBuilder(avRestAddress)
|
||||||
|
.addParameter("wait", "1")
|
||||||
|
.build();
|
||||||
|
HttpPost post = new HttpPost(uri);
|
||||||
HttpEntity entity = MultipartEntityBuilder.create()
|
HttpEntity entity = MultipartEntityBuilder.create()
|
||||||
.addPart("file", new FileBody(file))
|
.addPart("file", new FileBody(file))
|
||||||
.build();
|
.build();
|
||||||
|
|
@ -54,84 +54,21 @@ public class ReceiveScanReportRetryable {
|
||||||
try (CloseableHttpResponse postResponse = client.execute(post)) {
|
try (CloseableHttpResponse postResponse = client.execute(post)) {
|
||||||
int postStatusCode = postResponse.getStatusLine().getStatusCode();
|
int postStatusCode = postResponse.getStatusLine().getStatusCode();
|
||||||
String postResponseJson = EntityUtils.toString(postResponse.getEntity());
|
String postResponseJson = EntityUtils.toString(postResponse.getEntity());
|
||||||
AvFileSendResponse avFileSendResponse;
|
|
||||||
|
|
||||||
try {
|
if (postStatusCode == HttpStatus.OK.value()) {
|
||||||
avFileSendResponse = new Gson().fromJson(postResponseJson, AvFileSendResponse.class);
|
return new Gson().fromJson(postResponseJson, AvResponse.class);
|
||||||
}
|
}
|
||||||
catch (JsonSyntaxException e) {
|
else {
|
||||||
throw new FileUploadException("error json: " + postResponseJson, e);
|
throw new FileUploadException(
|
||||||
|
"http status code " + postStatusCode + " for " + post.getURI()
|
||||||
|
+ " get request.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (postStatusCode != HttpStatus.CREATED.value()) {
|
|
||||||
StringBuilder stringBuilder = new StringBuilder(
|
|
||||||
"http status code " + postStatusCode + " for " + avRestAddress + " post request.");
|
|
||||||
String status = avFileSendResponse.status();
|
|
||||||
|
|
||||||
if (status != null) {
|
|
||||||
stringBuilder.append(" Status: ").append(status).append(".");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (avFileSendResponse.error() != null) {
|
|
||||||
stringBuilder.append(" Error code: ")
|
|
||||||
.append(avFileSendResponse.error().code())
|
|
||||||
.append(". Error message: ")
|
|
||||||
.append(avFileSendResponse.error().message())
|
|
||||||
.append(". ");
|
|
||||||
}
|
|
||||||
throw new FileUploadException(stringBuilder.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
String id = avFileSendResponse.id();
|
|
||||||
String reportRequestUri = avRestAddress + "/" + id;
|
|
||||||
HttpGet get = new HttpGet(reportRequestUri);
|
|
||||||
|
|
||||||
// waiting for timeout time before first request
|
|
||||||
try {
|
|
||||||
TimeUnit.MILLISECONDS.sleep(avFirstTimeoutMilliseconds);
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
throw new FileUploadException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return receiveScanReport(client, get);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ClientProtocolException e) {
|
catch (ClientProtocolException e) {
|
||||||
throw new RetryableException("Failed to check file");
|
throw new RetryableException("Failed to check file");
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException | URISyntaxException e) {
|
||||||
// непредусмотренная ошибка доступа через http-клиент
|
|
||||||
throw new FileUploadException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private AvResponse receiveScanReport(CloseableHttpClient client, HttpGet get)
|
|
||||||
throws RetryableException, FileUploadException {
|
|
||||||
|
|
||||||
try (CloseableHttpResponse getResponse = client.execute(get)) {
|
|
||||||
int getStatusCode = getResponse.getStatusLine().getStatusCode();
|
|
||||||
|
|
||||||
if (getStatusCode == HttpStatus.OK.value()) {
|
|
||||||
String getResponseJson = EntityUtils.toString(getResponse.getEntity());
|
|
||||||
AvResponse avResponse = new Gson().fromJson(getResponseJson, AvResponse.class);
|
|
||||||
|
|
||||||
if (avResponse.completed() == null) {
|
|
||||||
throw new RetryableException("Failed to complete file scan");
|
|
||||||
}
|
|
||||||
return avResponse;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new FileUploadException("http status code " + getStatusCode + " for " + get.getURI()
|
|
||||||
+ " get request.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ClientProtocolException e) {
|
|
||||||
// непредусмотренная ошибка доступа через http-клиент
|
|
||||||
throw new RetryableException("Failed to receive scan report");
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
// непредусмотренная ошибка доступа через http-клиент
|
|
||||||
throw new FileUploadException(e);
|
throw new FileUploadException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,8 @@ s3.out.secret_key=${S3_SECRET_KEY}
|
||||||
s3.out.bucket_name=${S3_OUT_BUCKET_NAME}
|
s3.out.bucket_name=${S3_OUT_BUCKET_NAME}
|
||||||
s3.out.path.style.access.enabled=${S3_OUT_PATH_STYLE_ACCESS_ENABLED}
|
s3.out.path.style.access.enabled=${S3_OUT_PATH_STYLE_ACCESS_ENABLED}
|
||||||
#
|
#
|
||||||
|
webdav.username=${WEBDAV_USERNAME}
|
||||||
|
webdav.password=${WEBDAV_PASSWORD}
|
||||||
|
|
||||||
# endpoints management
|
# endpoints management
|
||||||
management.endpoints.web.exposure.include = health, info, metrics
|
management.endpoints.web.exposure.include = health, info, metrics
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue