package jnpf.dmsService.search.file;
|
|
import feign.Response;
|
import jnpf.dmsEntity.permission.entity.DmsFileVersionEntity;
|
import jnpf.dmsEntity.preview.model.DmsFilePreviewTicket;
|
import jnpf.dmsEntity.storage.entity.DmsFileObjectEntity;
|
import jnpf.dmsMapper.DmsFileObjectMapper;
|
import jnpf.dmsMapper.DmsFileVersionMapper;
|
import jnpf.dmsService.DmsFilePreviewTicketIssuer;
|
import jnpf.dmsService.file.DmsFileContentApi;
|
import jnpf.dmsService.search.DmsSearchIndexTask;
|
import jnpf.dmsService.search.DmsSearchProperties;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.io.OutputStream;
|
import java.nio.file.Files;
|
import java.nio.file.Path;
|
import java.util.Locale;
|
|
@Service
|
@RequiredArgsConstructor
|
public class DmsSearchFileSourceService {
|
private static final long TICKET_TTL_SECONDS = 300L;
|
|
private final DmsFileVersionMapper fileVersionMapper;
|
private final DmsFileObjectMapper fileObjectMapper;
|
private final DmsFilePreviewTicketIssuer ticketIssuer;
|
private final DmsFileContentApi fileApi;
|
private final DmsSearchProperties properties;
|
|
public DmsTemporarySearchFile fetch(DmsSearchIndexTask task) throws IOException {
|
DmsFileVersionEntity version = fileVersionMapper.selectByTenantAndId(
|
task.getTenantId(), task.getFileVersionId());
|
DmsFileObjectEntity object = fileObjectMapper.selectByTenantAndFileVersionId(
|
task.getTenantId(), task.getFileVersionId());
|
if (version == null || object == null) {
|
throw new IOException("文件版本或存储对象不存在");
|
}
|
String ticket = ticketIssuer.issue(ticket(task, version, object), TICKET_TTL_SECONDS);
|
Response response = fileApi.stream(version.getId(), ticket);
|
if (response == null || response.status() < 200 || response.status() >= 300
|
|| response.body() == null) {
|
if (response != null) {
|
response.close();
|
}
|
throw new IOException("文件服务读取失败");
|
}
|
Path target = Files.createTempFile("dms-search-", suffix(version.getFileName()));
|
try {
|
copy(response, target);
|
return new DmsTemporarySearchFile(target, version.getFileName(), version.getMimeType());
|
} catch (IOException exception) {
|
Files.deleteIfExists(target);
|
throw exception;
|
}
|
}
|
|
private void copy(Response response, Path target) throws IOException {
|
long copied = 0;
|
byte[] buffer = new byte[64 * 1024];
|
try (Response ignored = response;
|
InputStream input = response.body().asInputStream();
|
OutputStream output = Files.newOutputStream(target)) {
|
int read;
|
while ((read = input.read(buffer)) >= 0) {
|
copied += read;
|
if (copied > properties.getMaxFileBytes()) {
|
throw new IOException("文件超过全文检索解析大小限制");
|
}
|
output.write(buffer, 0, read);
|
}
|
}
|
}
|
|
private DmsFilePreviewTicket ticket(DmsSearchIndexTask task, DmsFileVersionEntity version,
|
DmsFileObjectEntity object) {
|
DmsFilePreviewTicket value = new DmsFilePreviewTicket();
|
value.setScope(DmsFilePreviewTicket.SCOPE);
|
value.setTenantId(task.getTenantId());
|
value.setUserId("dms-search-indexer");
|
value.setFileVersionId(version.getId());
|
value.setFileName(version.getFileName());
|
value.setMimeType(version.getMimeType());
|
value.setSizeBytes(version.getSizeBytes());
|
value.setStoragePlatform(object.getStoragePlatform());
|
value.setBucketName(object.getBucketName());
|
value.setBasePath(object.getBasePath());
|
value.setObjectPath(object.getObjectPath());
|
value.setObjectName(object.getObjectName());
|
value.setExpiresAt(System.currentTimeMillis() + TICKET_TTL_SECONDS * 1000L);
|
return value;
|
}
|
|
private String suffix(String fileName) {
|
int separator = fileName == null ? -1 : fileName.lastIndexOf('.');
|
if (separator < 0) {
|
return ".bin";
|
}
|
String value = fileName.substring(separator).toLowerCase(Locale.ROOT);
|
return value.matches("\\.[a-z0-9]{1,10}") ? value : ".bin";
|
}
|
}
|