package com.imyeyu.network; import com.imyeyu.io.IO; import com.imyeyu.java.TimiJava; import org.apache.hc.client5.http.fluent.Request; import org.apache.hc.client5.http.fluent.Response; import org.apache.hc.core5.http.HttpEntity; import org.apache.hc.core5.http.io.HttpClientResponseHandler; import org.apache.hc.core5.http.io.entity.EntityUtils; import javax.naming.NoPermissionException; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Path; /** * 封装 {@link org.apache.hc.client5.http.fluent.Request} 计算返回进度 * * @author 夜雨 * @since 2025-06-26 13:03 */ public class ProgressiveRequest extends FileRequest { protected final ProgressiveCallback callback; protected ProgressiveRequest(Request request, ProgressiveCallback callback) { super(request); this.callback = callback; } public static ProgressiveRequest wrap(Request request, ProgressiveCallback callback) { return new ProgressiveRequest(request, callback); } public static ProgressiveRequest get(String url, ProgressiveCallback callback) { return new ProgressiveRequest(Request.get(url), callback); } public static ProgressiveRequest post(String url, ProgressiveCallback callback) { return new ProgressiveRequest(Request.post(url), callback); } @Override public ProgressiveRequest timeout(long ms) { super.timeout(ms); return this; } @Override public ProgressiveRequest header(String key, String value) { request.addHeader(key, value); return this; } @Override public ProgressiveRequest token(String token) { request.addHeader("Token", token); return this; } @Override public ProgressiveRequest language(String langHeader) { request.addHeader("Accept-Language", langHeader); return this; } @Override public ProgressiveRequest body(Object object) { super.body(object); return this; } @Override public ProgressiveRequest bodyEntity(HttpEntity entity) { super.bodyEntity(entity); return this; } @Override public void toFile(Path outputPath) throws IOException, NoPermissionException { processResponse(request.execute(), IO.getOutputStream(outputPath.toFile())); } @Override public void toFile(File file) throws IOException, NoPermissionException { processResponse(request.execute(), IO.getOutputStream(file)); } @Override public String asString() throws IOException { return new String(asBytes()); } @Override public byte[] asBytes() throws IOException { ByteArrayOutputStream os = new ByteArrayOutputStream(); processResponse(request.execute(), os); return os.toByteArray(); } private void processResponse(Response response, OutputStream os) throws IOException { response.handleResponse((HttpClientResponseHandler) resp -> { HttpEntity entity = resp.getEntity(); if (entity == null) { throw new IOException("not found response entity"); } int code = resp.getCode(); if (400 <= code) { throw new IOException("response error: %s".formatted(code)); } long length = entity.getContentLength(); if (TimiJava.isEmpty(callback)) { IO.toOutputStream(entity.getContent(), os); } else { IO.toOutputStream(entity.getContent(), os, new IO.OnWriteCallback() { @Override public boolean handler(long total, long now) { return callback.handler(length, total, now); } }); } EntityUtils.consume(entity); return null; }); } /** * * * @author 夜雨 * @since 2025-06-26 15:18 */ public interface ProgressiveCallback { boolean handler(long total, long read, long now); } }