
io.github.kongweiguang.ok.OK Maven / Gradle / Ivy
The newest version!
package io.github.kongweiguang.ok;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import io.github.kongweiguang.ok.core.Config;
import io.github.kongweiguang.ok.core.Const;
import io.github.kongweiguang.ok.core.ContentType;
import io.github.kongweiguang.ok.core.Header;
import io.github.kongweiguang.ok.core.MultiValueMap;
import io.github.kongweiguang.ok.core.Timeout;
import io.github.kongweiguang.ok.core.Util;
import java.time.Duration;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiPredicate;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.internal.http.HttpMethod;
import okhttp3.sse.EventSources;
/**
* 发送请求
*/
public final class OK {
private final OkHttpClient C;
private final Request.Builder builder;
private Req req;
private boolean async;
private boolean retry;
private OK(final Req req) {
this.C = Config.client();
this.builder = new Request.Builder();
req(req).retry(req.max() > 0);
}
/**
* 发送请求
*
* 只有http请求有返回值,ws和sse没有返回值
*
* @param req 请求参数 {@link Req}
* @return Res {@link Res}
*/
public static Res ok(final Req req) {
return new OK(req).ojbk().join();
}
/**
*
异步调用发送请求
* 只有http请求有返回值,ws和sse没有返回值
*
* @param req 请求参数 {@link Req}
* @return Res {@link Res}
*/
public static CompletableFuture okAsync(final Req req) {
return new OK(req).async(true).ojbk();
}
private CompletableFuture ojbk() {
bf();
builder().tag(Req.class, req());
if (reqType()) {
return http0(new AtomicInteger(req().max()), req().delay(), req().predicate());
}
return CompletableFuture.completedFuture(null);
}
private boolean reqType() {
switch (req().reqType()) {
case http:
return true;
case ws:
ws0();
break;
case sse:
sse0();
break;
}
return false;
}
private CompletableFuture http0(final AtomicInteger max,
final Duration duration,
final BiPredicate predicate) {
if (async()) {
return CompletableFuture.supplyAsync(this::execute, Config.exec())
.handle((r, t) -> {
if (handleRetry(max, duration, predicate, r, t)) {
return http0(max, duration, predicate).join();
}
if (nonNull(t) && nonNull(req().fail())) {
req().fail().accept(t);
} else if (r.isOk() && nonNull(req().success())) {
req().success().accept(r);
}
return r;
});
} else {
return CompletableFuture.completedFuture(execute())
.handle((r, t) -> {
if (handleRetry(max, duration, predicate, r, t)) {
return http0(max, duration, predicate).join();
}
return r;
});
}
}
private boolean handleRetry(final AtomicInteger max,
final Duration duration,
final BiPredicate predicate,
final Res r, final Throwable t) {
if (retry() && (max.getAndDecrement() > 0 && predicate.test(r, t))) {
Util.sleep(duration.toMillis());
return true;
}
return false;
}
private Res execute() {
try (Response execute = client().newCall(builder().build()).execute()) {
return Res.of(execute);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void bf() {
addMethod();
addQuery();
addHeader();
addTimeout();
}
private void addTimeout() {
builder().tag(Timeout.class, req().timeout());
}
private void addMethod() {
builder().method(req().method().name(), addBody());
}
private RequestBody addBody() {
RequestBody rb = null;
if (HttpMethod.permitsRequestBody(req().method().name())) {
if (req().isMul()) {
//multipart 格式提交
req().contentType(ContentType.multipart).form().forEach(req().mul()::addFormDataPart);
rb = req().mul().setType(MediaType.parse(req().contentType())).build();
} else if (req().isForm()) {
final FormBody.Builder b = new FormBody.Builder(req().charset());
//form_urlencoded 格式提交
req().contentType(ContentType.form_urlencoded).form().forEach(b::addEncoded);
rb = b.build();
} else {
//字符串提交
rb = RequestBody.create(req().strBody(), MediaType.parse(req().contentType()));
}
}
return rb;
}
private void addQuery() {
if (nonNull(req().url())) {
if (isNull(req().scheme())) {
req().scheme(req().url().getProtocol());
}
if (isNull(req().host())) {
req().host(req().url().getHost());
}
if (req().port() == 0) {
req().port(req().url().getPort() == -1 ? Const.port : req().url().getPort());
}
if (nonNull(req().url().getPath())) {
req().pathFirst(req().url().getPath());
}
Optional.ofNullable(req().url().getQuery())
.map(e -> e.split("&"))
.ifPresent(qr -> {
for (String part : qr) {
String[] kv = part.split("=");
if (kv.length > 1) {
req().query(kv[0], kv[1]);
}
}
});
}
final HttpUrl.Builder ub = new HttpUrl.Builder();
Optional.ofNullable(req().query())
.map(MultiValueMap::map)
.ifPresent(map -> map.forEach((k, v) ->
v.forEach(e -> ub.addEncodedQueryParameter(k, e))));
req().paths().forEach(ub::addPathSegments);
ub.scheme(req().scheme());
ub.host(req().host());
ub.port(req().port());
builder().url(ub.build());
}
private void addHeader() {
if (!req().headers().isEmpty()) {
req().headers().forEach(builder()::addHeader);
}
if (!req().cookie().isEmpty()) {
builder().addHeader(Header.cookie.v(), cookie2Str(req().cookie()));
}
}
private static String cookie2Str(Map cookies) {
StringBuilder sb = new StringBuilder();
cookies.forEach((k, v) -> sb.append(k).append('=').append(v).append("; "));
return sb.toString();
}
private void ws0() {
client().newWebSocket(builder().build(), req().wsListener());
}
private void sse0() {
EventSources.createFactory(client()).newEventSource(builder().build(), req().sseListener());
}
private OK req(final Req req) {
this.req = req;
return this;
}
private OK retry(final boolean retry) {
this.retry = retry;
return this;
}
private OK async(final boolean async) {
this.async = async;
return this;
}
//get
private OkHttpClient client() {
return C;
}
private Request.Builder builder() {
return builder;
}
private Req req() {
return req;
}
private boolean async() {
return async;
}
public boolean retry() {
return retry;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy