刘光辉
5 小时以前 06f314545ac3514d7ce28939920866ae8188d31c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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";
    }
}