Skip to content

Commit

Permalink
fix: display GIF correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
SkyDependence committed Dec 4, 2024
1 parent 46610ac commit 66d5d54
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 49 deletions.
101 changes: 60 additions & 41 deletions src/main/java/com/skydevs/tgdrive/service/impl/BotServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand All @@ -35,10 +32,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.*;

@Service
@Slf4j
Expand All @@ -53,6 +47,7 @@ public class BotServiceImpl implements BotService {
private String botToken;
private String chatId;
private TelegramBot bot;
// tg bot接口限制20MB,传10MB是最佳实践
private final int MAX_FILE_SIZE = 10 * 1024 * 1024;
/*
@Value("${server.port}")
Expand Down Expand Up @@ -110,8 +105,8 @@ private List<String> sendFileStreamInChunks(InputStream inputStream, String file
while ((byteRead = bufferedInputStream.read(buffer)) > 0) {
semaphore.acquire(); // 获取许可,若没有可用许可则阻塞

// 当前块的文件名,第一块为原名
String partName = (partIndex == 0) ? filename : filename + "_part" + partIndex;
// 当前块的文件名
String partName = filename + "_part" + partIndex;
partIndex++;

// 取当前分块数据
Expand All @@ -120,18 +115,11 @@ private List<String> sendFileStreamInChunks(InputStream inputStream, String file
// 提交上传任务,使用CompletableFuture
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
int retryCont = 3;
for (int i = 0; i < retryCont; i++) {
try {
return uploadChunk(chunkData, partName);
} catch (Exception e) {
if (i + 1 == retryCont) {
throw new RuntimeException("已达到重试的最大次数", e);
}
log.warn("正在重试第" + (i + 1) + "次");
}
String fileId = uploadChunk(chunkData, partName);
if (fileId == null) {
throw new RuntimeException("分块 " + partName + " 上传失败");
}
throw new IllegalStateException("Unexpected state: loop exited without returning"); // 理论上不可能到这里
return fileId;
} finally {
semaphore.release(); // 在任务完成后释放信号量
}
Expand All @@ -141,10 +129,18 @@ private List<String> sendFileStreamInChunks(InputStream inputStream, String file

// 等待所有任务完成并按顺序获取结果
List<String> fileIds = new ArrayList<>();
for (CompletableFuture<String> future : futures) {
fileIds.add(future.join()); // 按顺序等待结果
try {
for (CompletableFuture<String> future : futures) {
fileIds.add(future.join()); // 按顺序等待结果
}
return fileIds;
} catch (CompletionException e) {
for (CompletableFuture<String> future : futures) {
future.cancel(true);
}
executorService.shutdown();
throw new RuntimeException("分块上传失败: " + e.getCause().getMessage(), e);
}
return fileIds;
} catch (IOException | InterruptedException e) {
log.error("文件流读取失败或上传失败:{}", e.getMessage());
throw new RuntimeException("文件流读取失败或上传");
Expand All @@ -161,18 +157,43 @@ private List<String> sendFileStreamInChunks(InputStream inputStream, String file
* @return
* @throws EOFException
*/
private String uploadChunk(byte[] chunkData, String partName) throws EOFException {
private String uploadChunk(byte[] chunkData, String partName) {
SendDocument sendDocument = new SendDocument(chatId, chunkData).fileName(partName);
SendResponse response = bot.execute(sendDocument);

// 检查响应
if (response.isOk() && response.message() != null && (response.message().document() != null || response.message().sticker() != null)) {
String fileID = response.message().document().fileId() != null ? response.message().document().fileId() : response.message().sticker().fileId();
log.info("分块上传成功,File ID:{}, 文件名:{}", fileID, partName);
return fileID;
} else {
log.error("分块上传失败,响应信息:{}", response.description());
throw new RuntimeException("分块上传失败");
int retryCount = 3;
for (int i = 1; i <= retryCount; i++) {
// 检查响应
if (response.isOk() && response.message() != null && (response.message().document() != null || response.message().sticker() != null)) {
String fileID = response.message().document().fileId() != null ? response.message().document().fileId() : response.message().sticker().fileId();
log.info("分块上传成功,File ID:{}, 文件名:{}", fileID, partName);
return fileID;
} else {
log.warn("正在重试第" + i + "次");
}
}
log.error("分块上传失败,响应信息:{}", response.description());
return null;
}

/**
* 上传单文件(为了使gif能正常显示,gif上传到tg后,会被转换为MP4)
* @param inputStream
* @param filename
* @return
*/
private String uploadOneFile(InputStream inputStream, String filename) {
try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
byte[] data = new byte[8192];
int byteRead;
while ((byteRead = inputStream.read(data)) != -1) {
buffer.write(data, 0, byteRead);
}
byte[] chunkData = buffer.toByteArray();
return uploadChunk(chunkData, filename);
} catch (Exception e) {
log.error("文件上传失败 :" + e.getMessage());
return null;
}
}

Expand Down Expand Up @@ -210,9 +231,9 @@ private String uploadFile(MultipartFile multipartFile, HttpServletRequest reques
InputStream inputStream = multipartFile.getInputStream();
String filename = multipartFile.getOriginalFilename();
long size = multipartFile.getSize();
List<String> fileIds = sendFileStreamInChunks(inputStream, filename);
if (fileIds.size() == 1) {
String fileID = fileIds.get(0);
if (size > MAX_FILE_SIZE) {
List<String> fileIds = sendFileStreamInChunks(inputStream, filename);
String fileID = createRecordFile(filename, size, fileIds);
FileInfo fileInfo = FileInfo.builder()
.fileId(fileID)
.size(userFriendly.humanReadableFileSize(size))
Expand All @@ -223,8 +244,8 @@ private String uploadFile(MultipartFile multipartFile, HttpServletRequest reques
.build();
fileMapper.insertFile(fileInfo);
return prefix + "/d/" + fileID;
} else if (fileIds.size() > 1) {
String fileID = createRecordFile(filename, size, fileIds);
} else {
String fileID = uploadOneFile(inputStream, filename);
FileInfo fileInfo = FileInfo.builder()
.fileId(fileID)
.size(userFriendly.humanReadableFileSize(size))
Expand All @@ -235,10 +256,8 @@ private String uploadFile(MultipartFile multipartFile, HttpServletRequest reques
.build();
fileMapper.insertFile(fileInfo);
return prefix + "/d/" + fileID;
} else {
return "文件上传失败";
}
} catch (IOException e) {
} catch (Exception e) {
log.error("文件上传失败,响应信息:{}", e.getMessage());
throw new RuntimeException("文件上传失败");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,8 @@ private ResponseEntity<StreamingResponseBody> handleRegularFile(String fileID, I
log.info("文件不是记录文件,直接下载文件...");

File file = botService.getFile(fileID);
String filename = resolveFilename(fileID, file.filePath());
Long fullSize = fileMapper.getFullSizeByFileId(fileID);
if (fullSize == null || fullSize == 0) {
fullSize = file.fileSize();
}
String filename = resolveFilename(fileID, file.filePath(), false);
long fullSize = file.fileSize();

HttpHeaders headers = setHeaders(filename, fullSize);

Expand Down Expand Up @@ -127,7 +124,7 @@ private ResponseEntity<StreamingResponseBody> handleRecordFile(String fileID, Bi
log.info("文件名为:" + record.getFileName());
log.info("检测到记录文件,开始下载并合并分片文件...");

String filename = resolveFilename(fileID, record.getFileName());
String filename = resolveFilename(fileID, record.getFileName(), true);
Long fullSize = fileMapper.getFullSizeByFileId(fileID);

HttpHeaders headers = setHeaders(filename, fullSize);
Expand Down Expand Up @@ -225,13 +222,13 @@ private void handleClientAbortException(IOException e) {
* @param defaultName
* @return
*/
private String resolveFilename(String fileID, String defaultName) {
private String resolveFilename(String fileID, String defaultName, boolean isRecordFile) {
String filename = fileMapper.getFileNameByFileId(fileID);
if (filename == null) {
filename = defaultName;
}
// 上传到tg的gif会被转换为MP4
if (filename.endsWith(".gif")) {
if (!isRecordFile && filename.endsWith(".gif")) {
filename = filename.substring(0, filename.length() - 4) + ".mp4";
}
return filename;
Expand Down

0 comments on commit 66d5d54

Please sign in to comment.