Skip to content

Commit 1e879f3

Browse files
committed
完成对范围流读取的支持
1 parent aceceef commit 1e879f3

9 files changed

Lines changed: 116 additions & 23 deletions

File tree

CHANGELOG.MD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
更新日志文档,版本顺序从新到旧,最新版本在最前(上)面。
44

5+
# 1.0.8
6+
57
# 1.0.7
68

79
- 添加对应115文件流读取的支持

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
group=run.ikaros.plugin
22
description=A pan115 plugin for ikaros.
3-
version=1.0.7
3+
version=1.0.8

lib/api-1.0.4-sources.jar

-77.6 KB
Binary file not shown.

lib/api-1.0.4.jar

-210 KB
Binary file not shown.

lib/api-1.0.5-sources.jar

18 Bytes
Binary file not shown.

lib/api-1.0.5.jar

42 Bytes
Binary file not shown.

src/main/java/run/ikaros/plugin/pan115/Pan115AttachmentDriverFetcher.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,17 @@ public Flux<DataBuffer> getSteam(Attachment attachment) {
172172
return checkoutMono.flatMapMany(driver -> pan115Repository.openUFileSteam(attachment.getUrl()));
173173
}
174174

175+
@Override
176+
public Flux<DataBuffer> getSteam(Attachment attachment, long start, long end) {
177+
Assert.notNull(attachment, "'attachment' must not null.");
178+
AttachmentType type = attachment.getType();
179+
if (AttachmentType.Driver_Directory.equals(type)) return Flux.empty();
180+
Long driverId = attachment.getDriverId();
181+
Mono<AttachmentDriver> checkoutMono = checkoutToken(driverId);
182+
return checkoutMono.flatMapMany(driver ->
183+
pan115Repository.openUFileSteamWithRange(attachment.getUrl(), start, end));
184+
}
185+
175186
private void applyPan115Token(AttachmentDriver driver) {
176187
Assert.notNull(driver, "'driver' must not null.");
177188
pan115Repository.refreshToken(driver);

src/main/java/run/ikaros/plugin/pan115/repository/DefaultPan115Repository.java

Lines changed: 99 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -258,28 +258,105 @@ public Flux<DataBuffer> openUFileSteam(String pickCode) {
258258
Assert.hasText(pickCode, "'pickCode' must has text.");
259259
final String uFileDownUrl = openUFileDownUrl(pickCode);
260260
return streamFileWithRestTemplate(uFileDownUrl);
261-
// return Flux.create(sink -> {
262-
// Schedulers.boundedElastic().schedule(() -> {
263-
// try {
264-
// ResponseEntity<byte[]> response = restTemplate.getForEntity(
265-
// uFileDownUrl, byte[].class);
266-
// if (response.getStatusCode() == HttpStatus.OK &&
267-
// response.getBody() != null) {
268-
// // 一次性发送所有数据(适合小文件)
269-
// DataBuffer dataBuffer = dataBufferFactory.allocateBuffer(
270-
// response.getBody().length);
271-
// dataBuffer.write(response.getBody());
272-
// sink.next(dataBuffer);
273-
// sink.complete();
274-
// } else {
275-
// sink.error(new RuntimeException(
276-
// "请求失败,状态码: " + response.getStatusCode()));
277-
// }
278-
// } catch (Exception e) {
279-
// sink.error(e);
280-
// }
281-
// });
282-
// });
261+
}
262+
263+
@Override
264+
public Flux<DataBuffer> openUFileSteamWithRange(String pickCode, long start, long end) {
265+
Assert.hasText(pickCode, "'pickCode' must has text.");
266+
final String uFileDownUrl = openUFileDownUrl(pickCode);
267+
return streamFileWithRestTemplateWithRange(uFileDownUrl, start, end, 8192);
268+
}
269+
270+
private Flux<DataBuffer> streamFileWithRestTemplateWithRange(String uFileDownUrl, Long start, Long end, int chunkSize) {
271+
if (chunkSize <= 0) {
272+
chunkSize = 8192; // 默认8KB
273+
}
274+
275+
final int finalChunkSize = chunkSize;
276+
277+
// 设置 Range 请求头
278+
String rangeHeader;
279+
if (start != null && end != null) {
280+
rangeHeader = String.format("bytes=%d-%d", start, end);
281+
} else if (start != null) {
282+
rangeHeader = String.format("bytes=%d-", start);
283+
} else {
284+
rangeHeader = "bytes=0-"; // 默认从头开始
285+
}
286+
287+
return Flux.create(sink -> {
288+
// 使用 boundedElastic 调度器执行阻塞操作
289+
Schedulers.boundedElastic().schedule(() -> {
290+
try {
291+
String newUrl = uFileDownUrl;
292+
if (StringUtils.isNoneBlank(newUrl)) {
293+
newUrl = URLDecoder.decode(newUrl, StandardCharsets.UTF_8);
294+
}
295+
log.debug("Open stream range from {} to {} for url: {}", start, end, newUrl);
296+
restTemplate.execute(newUrl, HttpMethod.GET, new RequestCallback() {
297+
@Override
298+
public void doWithRequest(ClientHttpRequest request) throws IOException {
299+
request.getHeaders().set(HttpHeaders.RANGE, rangeHeader);
300+
request.getHeaders().addAll(headers);
301+
}
302+
},
303+
(ResponseExtractor<Void>) response -> {
304+
if (response.getStatusCode() != HttpStatus.PARTIAL_CONTENT) {
305+
sink.error(new RuntimeException(
306+
"请求失败,状态码: " + response.getStatusCode()));
307+
return null;
308+
}
309+
310+
try (InputStream inputStream = response.getBody()) {
311+
byte[] buffer = new byte[finalChunkSize];
312+
int bytesRead;
313+
AtomicBoolean isCanceled = new AtomicBoolean(false);
314+
315+
sink.onCancel(() -> {
316+
isCanceled.set(true);
317+
try {
318+
inputStream.close();
319+
} catch (IOException e) {
320+
// 忽略关闭异常
321+
}
322+
});
323+
324+
while (!isCanceled.get() &&
325+
(bytesRead = inputStream.read(buffer)) != -1) {
326+
327+
// 创建 DataBuffer
328+
DataBuffer dataBuffer = dataBufferFactory.allocateBuffer(bytesRead);
329+
dataBuffer.write(buffer, 0, bytesRead);
330+
331+
// 发布数据块
332+
sink.next(dataBuffer);
333+
334+
// 检查是否取消
335+
if (sink.isCancelled()) {
336+
log.debug("Close stream range from {} to {} for url: {}", start, end, uFileDownUrl);
337+
break;
338+
}
339+
}
340+
341+
if (!isCanceled.get()) {
342+
sink.complete();
343+
}
344+
} catch (Exception e) {
345+
if (!sink.isCancelled()) {
346+
sink.error(e);
347+
}
348+
}
349+
return null;
350+
});
351+
} catch (Exception e) {
352+
if (!sink.isCancelled()) {
353+
sink.error(e);
354+
}
355+
} finally {
356+
headers.remove(HttpHeaders.RANGE);
357+
}
358+
});
359+
}, FluxSink.OverflowStrategy.BUFFER);
283360
}
284361

285362

src/main/java/run/ikaros/plugin/pan115/repository/Pan115Repository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package run.ikaros.plugin.pan115.repository;
22

3+
import org.reactivestreams.Publisher;
34
import org.springframework.core.io.buffer.DataBuffer;
45
import reactor.core.publisher.Flux;
56
import run.ikaros.api.core.attachment.AttachmentDriver;
@@ -25,4 +26,6 @@ List<Pan115Attachment> openUFileFiles(String cid, Integer limit, Integer cur,
2526
String openVideoPlay(String pickCode);
2627

2728
Flux<DataBuffer> openUFileSteam(String pickCode);
29+
30+
Flux<DataBuffer> openUFileSteamWithRange(String pickCode, long start, long end);
2831
}

0 commit comments

Comments
 (0)