refactory
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
package ru.di9.mirror.core.service;
|
||||
|
||||
import io.minio.MinioClient;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import ru.di9.mirror.core.domain.ItemRecord2;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class MinioServiceIntTest {
|
||||
static final String url = "http://dev.di9.ru:9000";
|
||||
static final String accessKey = "mirror";
|
||||
static final String secretKey = "mirror123";
|
||||
static final String bucket = "mirror";
|
||||
static MinioClient minioClient;
|
||||
MinioService minioService;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
minioClient = MinioClient.builder()
|
||||
.endpoint(url)
|
||||
.credentials(accessKey, secretKey)
|
||||
.build();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
minioService = new MinioService(minioClient, bucket);
|
||||
}
|
||||
|
||||
@Test
|
||||
void list() {
|
||||
List<ItemRecord2> list = minioService.list("/local/ghast/ghast-tools/");
|
||||
|
||||
assertNotNull(list);
|
||||
assertFalse(list.isEmpty());
|
||||
|
||||
assertTrue(list.stream()
|
||||
.anyMatch(itemRecord2 -> itemRecord2.name().equals("maven-metadata.xml")
|
||||
&& !itemRecord2.isDir()
|
||||
&& itemRecord2.size() == 320));
|
||||
assertTrue(list.stream()
|
||||
.anyMatch(itemRecord2 -> itemRecord2.name().equals("1.13")
|
||||
&& itemRecord2.isDir()
|
||||
&& itemRecord2.size() == 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void notExists() {
|
||||
Optional<InputStream> optional = minioService.get("/not/exists/path/to/object");
|
||||
|
||||
assertNotNull(optional);
|
||||
assertTrue(optional.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void exists() {
|
||||
Optional<InputStream> optional = minioService.get("/local/ghast/ghast-tools/maven-metadata.xml");
|
||||
|
||||
assertNotNull(optional);
|
||||
assertTrue(optional.isPresent());
|
||||
}
|
||||
}
|
||||
16
mirror-core/src/main/java/ru/di9/mirror/core/Utils.java
Normal file
16
mirror-core/src/main/java/ru/di9/mirror/core/Utils.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package ru.di9.mirror.core;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class Utils {
|
||||
|
||||
public static boolean isEmptyString(String string) {
|
||||
return string == null || string.isEmpty() || string.isBlank();
|
||||
}
|
||||
|
||||
public static boolean isNotEmptyString(String string) {
|
||||
return !isEmptyString(string);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package ru.di9.mirror.core.domain;
|
||||
|
||||
import io.minio.Result;
|
||||
import io.minio.messages.Item;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
public record ItemRecord2(Result<Item> itemResult, String prefix) {
|
||||
|
||||
@SneakyThrows
|
||||
public boolean isDir() {
|
||||
return itemResult.get().isDir();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public String name() {
|
||||
String objectName = itemResult.get().objectName();
|
||||
if (isDir()) {
|
||||
return objectName.substring(prefix.length() - 1, objectName.length() - 1);
|
||||
} else {
|
||||
return objectName.substring(prefix.length() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public long size() {
|
||||
return itemResult.get().size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package ru.di9.mirror.core.domain;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public record MavenHandlerGetFileResponse(String name, InputStream inputStream) {
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package ru.di9.mirror.core.domain;
|
||||
|
||||
public enum PathType {
|
||||
FILE, DIRECTORY
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package ru.di9.mirror.core.domain;
|
||||
|
||||
public record WalkerResult(PathType type) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package ru.di9.mirror.core.handler;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import ru.di9.mirror.core.domain.ItemRecord2;
|
||||
import ru.di9.mirror.core.service.MinioService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class IndexOfHandler {
|
||||
|
||||
private final MinioService minioService;
|
||||
|
||||
public List<ItemRecord2> walker(String path) {
|
||||
return minioService.list("/local/" + path);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package ru.di9.mirror.core.handler;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import ru.di9.mirror.core.domain.MavenHandlerGetFileResponse;
|
||||
import ru.di9.mirror.core.service.ExternalMavenService;
|
||||
import ru.di9.mirror.core.service.MinioService;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class MavenHandler {
|
||||
|
||||
private final MinioService minioService;
|
||||
private final List<ExternalMavenService> externalMavenServices;
|
||||
|
||||
public Optional<MavenHandlerGetFileResponse> getFile(String path) {
|
||||
final String fileName = path.substring(path.lastIndexOf("/") + 1);
|
||||
|
||||
Optional<InputStream> optionalInputStream = minioService.get("/local/" + path);
|
||||
if (optionalInputStream.isPresent()) {
|
||||
return optionalInputStream
|
||||
.map(inputStream -> new MavenHandlerGetFileResponse(fileName, inputStream));
|
||||
} else {
|
||||
for (ExternalMavenService externalMavenService : externalMavenServices) {
|
||||
final String nameForStore = "/" + externalMavenService.getId() + "/" + path;
|
||||
|
||||
optionalInputStream = minioService.get(nameForStore);
|
||||
if (optionalInputStream.isPresent()) {
|
||||
return optionalInputStream
|
||||
.map(inputStream -> new MavenHandlerGetFileResponse(fileName, inputStream));
|
||||
} else {
|
||||
optionalInputStream = externalMavenService.getFile(path);
|
||||
if (optionalInputStream.isPresent()) {
|
||||
minioService.put(nameForStore, optionalInputStream.get());
|
||||
return minioService.get(nameForStore)
|
||||
.map(inputStream -> new MavenHandlerGetFileResponse(fileName, inputStream));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public void putFile(String path, InputStream inputStream) {
|
||||
minioService.put("/local/" + path, inputStream);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package ru.di9.mirror.core.service;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.ToString;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
@SuppressWarnings("ClassCanBeRecord")
|
||||
@ToString(of = {"id", "url"})
|
||||
public class ExternalMavenService {
|
||||
|
||||
@Getter
|
||||
private final String id;
|
||||
private final String url;
|
||||
private final OkHttpClient okHttpClient;
|
||||
|
||||
public ExternalMavenService(String id, String url, OkHttpClient okHttpClient) {
|
||||
this.id = id;
|
||||
this.okHttpClient = okHttpClient;
|
||||
|
||||
if (!url.endsWith("/")) {
|
||||
this.url = url + "/";
|
||||
} else {
|
||||
this.url = url;
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public Optional<InputStream> getFile(String path) {
|
||||
if (path.startsWith("/")) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(url + path)
|
||||
.build();
|
||||
|
||||
Response response = okHttpClient.newCall(request).execute();
|
||||
if (!response.isSuccessful()) {
|
||||
if (response.code() == 404) {
|
||||
return Optional.empty();
|
||||
}
|
||||
throw new IOException("Unexpected code " + response);
|
||||
}
|
||||
|
||||
return Optional.ofNullable(response.body()).map(ResponseBody::byteStream);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package ru.di9.mirror.core.service;
|
||||
|
||||
import io.minio.*;
|
||||
import io.minio.errors.*;
|
||||
import io.minio.messages.Item;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import ru.di9.mirror.core.domain.ItemRecord2;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class MinioService {
|
||||
private static final long UNKNOWN_SIZE = -1L;
|
||||
private static final long PART_SIZE = (5 * 1024 * 1024); // 5 MB
|
||||
|
||||
private final MinioClient minioClient;
|
||||
private final String bucket;
|
||||
|
||||
@SneakyThrows
|
||||
public void put(String name, InputStream inputStream) {
|
||||
minioClient.putObject(PutObjectArgs.builder()
|
||||
.bucket(bucket)
|
||||
.object(name)
|
||||
.stream(inputStream, UNKNOWN_SIZE, PART_SIZE)
|
||||
.build());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public Optional<InputStream> get(String name) {
|
||||
try {
|
||||
return Optional.of(minioClient.getObject(GetObjectArgs.builder()
|
||||
.bucket(bucket)
|
||||
.object(name)
|
||||
.build()));
|
||||
} catch (ErrorResponseException e) {
|
||||
if (e.errorResponse().code().equalsIgnoreCase("NoSuchKey")) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<ItemRecord2> list(String prefix) {
|
||||
if (!prefix.endsWith("/")) {
|
||||
prefix = prefix + "/";
|
||||
}
|
||||
|
||||
Iterable<Result<Item>> results = minioClient.listObjects(ListObjectsArgs.builder()
|
||||
.bucket(bucket)
|
||||
.prefix(prefix)
|
||||
.build());
|
||||
|
||||
List<ItemRecord2> list = new ArrayList<>();
|
||||
for (Result<Item> result : results) {
|
||||
list.add(new ItemRecord2(result, prefix));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package ru.di9.mirror.core.service;
|
||||
|
||||
import io.minio.ListObjectsArgs;
|
||||
import io.minio.MinioClient;
|
||||
import io.minio.Result;
|
||||
import io.minio.messages.Item;
|
||||
import lombok.SneakyThrows;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import ru.di9.mirror.core.domain.ItemRecord2;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class MinioServiceTest {
|
||||
static final String bucket = "mirror";
|
||||
static MinioClient mockMinioClient;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
mockMinioClient = mock(MinioClient.class);
|
||||
|
||||
Iterable<Result<Item>> listObjects = List.of(
|
||||
mockResult("ghast/ghast-tools/maven-metadata.xml", 320, false),
|
||||
mockResult("ghast/ghast-tools/1.13/", 0, true)
|
||||
);
|
||||
when(mockMinioClient.listObjects(any(ListObjectsArgs.class))).thenReturn(listObjects);
|
||||
}
|
||||
|
||||
@Test
|
||||
void list() {
|
||||
MinioService minioService = new MinioService(mockMinioClient, bucket);
|
||||
List<ItemRecord2> list = minioService.list("/ghast/ghast-tools/");
|
||||
|
||||
assertNotNull(list);
|
||||
assertFalse(list.isEmpty());
|
||||
|
||||
assertTrue(list.stream()
|
||||
.anyMatch(itemRecord2 -> itemRecord2.name().equals("maven-metadata.xml")
|
||||
&& !itemRecord2.isDir()
|
||||
&& itemRecord2.size() == 320));
|
||||
assertTrue(list.stream()
|
||||
.anyMatch(itemRecord2 -> itemRecord2.name().equals("1.13")
|
||||
&& itemRecord2.isDir()
|
||||
&& itemRecord2.size() == 0));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SneakyThrows
|
||||
private static Result<Item> mockResult(String name, long size, boolean isDir) {
|
||||
Item item = mock(Item.class);
|
||||
when(item.objectName()).thenReturn(name);
|
||||
when(item.size()).thenReturn(size);
|
||||
when(item.isDir()).thenReturn(isDir);
|
||||
|
||||
Result<Item> result = mock(Result.class);
|
||||
when(result.get()).thenReturn(item);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user