Files
emo-grab/src/main/java/quant/rich/emoney/patch/okhttp/PatchOkHttpRule.java

201 lines
6.5 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package quant.rich.emoney.patch.okhttp;
import java.util.*;
import java.util.function.*;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import quant.rich.emoney.patch.okhttp.PatchOkHttp.HeaderInterceptor;
public class PatchOkHttpRule {
@Getter
@Setter
@Accessors(chain=true)
private Integer id;
private final Predicate<RequestContext> condition;
private final List<HeaderAction> actions;
public PatchOkHttpRule(Predicate<RequestContext> condition, List<HeaderAction> actions) {
this.condition = condition;
this.actions = actions;
}
public boolean matches(RequestContext ctx) {
return condition.test(ctx);
}
public void apply(RequestContext ctx, String currentHeader, Consumer<String> overrideSetter) {
for (HeaderAction action : actions) {
action.apply(ctx, currentHeader, overrideSetter);
}
}
@FunctionalInterface
public interface HeaderAction {
void apply(RequestContext ctx, String currentHeader, Consumer<String> overrideValueSetter);
}
/**
* 起始语句,创建一个 Builder
* @return
*/
public static Builder when() {
return new Builder(ctx -> true);
}
public static class Builder {
public static final Logger log = LoggerFactory.getLogger(HeaderInterceptor.class);
private Predicate<RequestContext> condition;
private final List<HeaderAction> actions = new ArrayList<>();
public Builder(Predicate<RequestContext> initial) {
this.condition = initial;
}
public Builder hasHeaderPair(String name, String value) {
return and(ctx -> value.equals(ctx.headers.get(name)));
}
public Builder hasHeaderName(String name) {
return and(ctx -> ctx.headers.containsKey(name));
}
public Builder hasNotHeaderName(String name) {
return not(r -> r.and(ctx -> ctx.headers.containsKey(name)));
}
public Builder hasHeaderValueMatch(String name, String regex) {
Pattern pattern = Pattern.compile(regex);
return and(ctx -> {
String val = ctx.headers.get(name);
return val != null && pattern.matcher(val).matches();
});
}
public Builder hostEndsWith(String suffix) {
return and(ctx -> ctx.host != null && ctx.host.endsWith(suffix));
}
public Builder hostContains(String keyword) {
return and(ctx -> ctx.host != null && ctx.host.contains(keyword));
}
/**
*
* @param pattern
* @return
*/
public Builder hostMatches(String pattern) {
return and(ctx -> ctx.host != null && Pattern.matches(pattern, ctx.host));
}
public Builder isHttp() {
return and(ctx -> "http".equalsIgnoreCase(ctx.scheme));
}
public Builder isHttps() {
return and(ctx -> "https".equalsIgnoreCase(ctx.scheme));
}
/**
* 接收一个 not 条件<br>
* 例Rule.when().not(r -> r.isHttps()).build()
*
* @param block
* @return
*/
public Builder not(Consumer<Builder> block) {
Builder sub = new Builder(ctx -> true); // starts with true
block.accept(sub);
this.condition = this.condition
.and(sub.condition.negate());
return this;
}
public Builder or(Consumer<Builder> block) {
Builder sub = new Builder(ctx -> true);
block.accept(sub);
this.condition = this.condition.or(sub.condition);
return this;
}
public Builder or(Builder other) {
this.condition = this.condition.or(other.condition);
return this;
}
public Builder or(PatchOkHttpRule rule) {
this.condition = this.condition.or(rule::matches);
return this;
}
public Builder and() {
return this;
}
public Builder and(Predicate<RequestContext> other) {
this.condition = this.condition.and(other);
return this;
}
public Builder then() {
return this;
}
public Builder setHeader(String name, String value) {
actions.add((ctx, curr, setter) -> ctx.headers.put(name, value));
return this;
}
public Builder overrideHeader(String headerName, String value) {
actions.add((ctx, curr, setter) -> {
if (curr.equalsIgnoreCase(headerName)) {
log.debug("matches and applying - host: {}, currHeader {}, targetHeader {}, value: {}, classLoader: {}", ctx.host, curr, headerName,
value, this.getClass().getClassLoader());
setter.accept(value);
}
});
return this;
}
/**
* 如果满足条件则覆写指定 Header。当覆写值可能动态变化时使用本方法提供 supplier
* @param headerName
* @param valueSupplier
* @return
*/
public Builder overrideHeader(String headerName, Supplier<String> valueSupplier) {
actions.add((ctx, curr, setter) -> {
if (curr.equalsIgnoreCase(headerName)) {
String value = valueSupplier.get();
log.debug("matches and applying - host: {}, currHeader {}, targetHeader {}, value: {}, classLoader: {}", ctx.host, curr, headerName,
value, this.getClass().getClassLoader());
setter.accept(value);
}
});
return this;
}
public PatchOkHttpRule build() {
return new PatchOkHttpRule(condition, actions);
}
}
public boolean equals(PatchOkHttpRule other) {
if (other == null) return false;
if (this.id == null || other.id == null) return false;
return this.id.equals(other.id);
}
public int hashCode() {
return Objects.hash(id);
}
}