Dedicated line (#376)

Dedicated Line init
This commit is contained in:
hongqiaowei
2021-11-16 15:18:27 +08:00
committed by GitHub
parent 3da394f381
commit a10c236a6e
53 changed files with 794 additions and 896 deletions

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>fizz-gateway-community</artifactId>
<groupId>com.fizzgate</groupId>
<version>2.3.3-beta6</version>
<version>2.3.4-beta1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -1,64 +0,0 @@
/*
* Copyright (C) 2020 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.api.pairing;
import we.util.JacksonUtils;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* @author hongqiaowei
*/
public class ApiPairingDocSet {
public static final int DELETED = 1;
public int isDeleted = 0;
public long id;
public String name;
public String description;
public List<ApiPairingDoc> docs = Collections.emptyList();
public Set<String> appIds = Collections.emptySet();
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ApiPairingDocSet that = (ApiPairingDocSet) o;
return id == that.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public String toString() {
return JacksonUtils.writeValueAsString(this);
}
}

View File

@@ -1,271 +0,0 @@
/*
* Copyright (C) 2020 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.api.pairing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import we.config.AggregateRedisConfig;
import we.config.SystemConfig;
import we.plugin.auth.ApiConfig;
import we.util.JacksonUtils;
import we.util.Result;
import we.util.UrlTransformUtils;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
/**
* @author hongqiaowei
*/
@ConditionalOnProperty(name = SystemConfig.FIZZ_API_PAIRING_SERVER_ENABLE, havingValue = "true")
@Service
public class ApiPairingDocSetService {
private static final Logger log = LoggerFactory.getLogger(ApiPairingDocSetService.class);
private Map<Long /* doc set id */, ApiPairingDocSet> docSetMap = new HashMap<>(64);
private Map<String /* app id */, Set<ApiPairingDocSet>> appDocSetMap = new HashMap<>(64);
private Map<String /* service */, Set<ApiPairingDocSet>> serviceExistsInDocSetMap = new HashMap<>(64);
private Map<Object /* method */, Map<String /* path pattern */, Set<ApiPairingDocSet>>> methodPathExistsInDocSetMap = new HashMap<>();
@Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
private ReactiveStringRedisTemplate rt;
@PostConstruct
public void init() throws Throwable {
Result<?> result = initApiPairingDocSet();
if (result.code == Result.FAIL) {
throw new RuntimeException(result.msg, result.t);
}
result = lsnApiPairingDocSetChange();
if (result.code == Result.FAIL) {
throw new RuntimeException(result.msg, result.t);
}
}
private Result<?> initApiPairingDocSet() {
Result<?> result = Result.succ();
Flux<Map.Entry<Object, Object>> resources = rt.opsForHash().entries("fizz_api_pairing_doc");
resources.collectList()
.defaultIfEmpty(Collections.emptyList())
.flatMap(
es -> {
if (!es.isEmpty()) {
String json = null;
try {
for (Map.Entry<Object, Object> e : es) {
json = (String) e.getValue();
ApiPairingDocSet docSet = JacksonUtils.readValue(json, ApiPairingDocSet.class);
updateDocSetDataStruct(docSet);
}
} catch (Throwable t) {
result.code = Result.FAIL;
result.msg = "init api pairing doc set error, doc set: " + json;
result.t = t;
}
} else {
log.info("no api pairing doc set");
}
return Mono.empty();
}
)
.onErrorReturn(
throwable -> {
result.code = Result.FAIL;
result.msg = "init api pairing doc set error";
result.t = throwable;
return true;
},
result
)
.block();
return result;
}
private Result<?> lsnApiPairingDocSetChange() {
Result<?> result = Result.succ();
String channel = "fizz_api_pairing_doc_channel";
rt.listenToChannel(channel)
.doOnError(
t -> {
result.code = Result.FAIL;
result.msg = "lsn error, channel: " + channel;
result.t = t;
log.error("lsn channel {} error", channel, t);
}
)
.doOnSubscribe(
s -> {
log.info("success to lsn on {}", channel);
}
)
.doOnNext(
msg -> {
String message = msg.getMessage();
try {
ApiPairingDocSet docSet = JacksonUtils.readValue(message, ApiPairingDocSet.class);
updateDocSetDataStruct(docSet);
} catch (Throwable t) {
log.error("update api pairing doc set error, {}", message, t);
}
}
)
.subscribe();
return result;
}
private void updateDocSetDataStruct(ApiPairingDocSet docSet) {
if (docSet.isDeleted == ApiPairingDocSet.DELETED) {
docSetMap.remove(docSet.id);
for (String appId : docSet.appIds) {
Set<ApiPairingDocSet> dss = appDocSetMap.get(appId);
if (dss != null) {
dss.remove(docSet);
if (dss.isEmpty()) {
appDocSetMap.remove(appId);
}
}
}
for (ApiPairingDoc doc : docSet.docs) {
Set<ApiPairingDocSet> dss = serviceExistsInDocSetMap.get(doc.service);
if (dss != null) {
dss.remove(docSet);
if (dss.isEmpty()) {
serviceExistsInDocSetMap.remove(doc.service);
}
}
for (Api api : doc.apis) {
Map<String, Set<ApiPairingDocSet>> pathDocSetMap = methodPathExistsInDocSetMap.get(api.method);
if (pathDocSetMap != null) {
dss = pathDocSetMap.get(api.path);
if (dss != null) {
dss.remove(docSet);
if (dss.isEmpty()) {
pathDocSetMap.remove(api.path);
if (pathDocSetMap.isEmpty()) {
methodPathExistsInDocSetMap.remove(api.method);
}
}
}
}
}
}
log.info("delete doc set: {}", docSet);
} else {
docSetMap.put(docSet.id, docSet);
docSet.appIds.forEach(
appId -> {
Set<ApiPairingDocSet> dss = appDocSetMap.computeIfAbsent(appId, k -> new HashSet<>());
dss.add(docSet);
}
);
docSet.docs.forEach(
doc -> {
Set<ApiPairingDocSet> dss = serviceExistsInDocSetMap.computeIfAbsent(doc.service, k -> new HashSet<>());
dss.add(docSet);
for (Api api : doc.apis) {
Map<String, Set<ApiPairingDocSet>> pathDocSetMap = methodPathExistsInDocSetMap.computeIfAbsent(api.method, k -> new HashMap<>());
dss = pathDocSetMap.computeIfAbsent(api.path, k -> new HashSet<>());
dss.add(docSet);
}
}
);
log.info("update doc set: {}", docSet);
}
}
public Map<Long, ApiPairingDocSet> getDocSetMap() {
return docSetMap;
}
public ApiPairingDocSet get(long id) {
return docSetMap.get(id);
}
public Map<String, Set<ApiPairingDocSet>> getAppDocSetMap() {
return appDocSetMap;
}
public Map<String, Set<ApiPairingDocSet>> getServiceExistsInDocSetMap() {
return serviceExistsInDocSetMap;
}
public Map<Object, Map<String, Set<ApiPairingDocSet>>> getMethodPathExistsInDocSetMap() {
return methodPathExistsInDocSetMap;
}
public boolean existsDocSetMatch(String appId, HttpMethod method, String service, String path) {
Set<ApiPairingDocSet> appDocSets = appDocSetMap.get(appId);
if (appDocSets == null) {
return false;
}
Set<ApiPairingDocSet> serviceDocSets = serviceExistsInDocSetMap.get(service);
if (serviceDocSets == null) {
return false;
}
Set<ApiPairingDocSet> s = new HashSet<>();
Map<String, Set<ApiPairingDocSet>> pathDocSetMap = methodPathExistsInDocSetMap.get(method);
if (pathDocSetMap != null) {
checkPathPattern(pathDocSetMap, path, s);
}
pathDocSetMap = methodPathExistsInDocSetMap.get(ApiConfig.ALL_METHOD);
if (pathDocSetMap != null) {
checkPathPattern(pathDocSetMap, path, s);
}
if (s.isEmpty()) {
return false;
}
s.retainAll(appDocSets);
if (s.isEmpty()) {
return false;
}
s.retainAll(serviceDocSets);
if (s.isEmpty()) {
return false;
}
return true;
}
private void checkPathPattern(Map<String, Set<ApiPairingDocSet>> pathDocSetMap, String path, Set<ApiPairingDocSet> result) {
Set<Map.Entry<String, Set<ApiPairingDocSet>>> entries = pathDocSetMap.entrySet();
for (Map.Entry<String, Set<ApiPairingDocSet>> entry : entries) {
String pathPattern = entry.getKey();
if (pathPattern.equals(path) || UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path)) {
result.addAll(entry.getValue());
}
}
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright (C) 2020 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.api.pairing;
import we.util.JacksonUtils;
import java.util.Collections;
import java.util.Set;
/**
* @author hongqiaowei
*/
public class AppApiPairingDocSet {
public long id;
public String name;
public String description;
public Set<String> services;
public boolean enabled;
@Override
public String toString() {
return JacksonUtils.writeValueAsString(this);
}
}

View File

@@ -42,6 +42,8 @@ public class FizzMangerConfig {
public String managerUrl;
public String pairPath = "/fizz-manager/dedicated-line/pair";
public String docPathPrefix = "/fizz-manager/open-doc/open-doc-show/pair";
@PostConstruct

View File

@@ -22,7 +22,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;
import we.fizz.ConfigLoader;
import we.plugin.auth.ApiConfigService;
import we.plugin.auth.ApiConifg2appsService;
import we.plugin.auth.ApiConfig2appsService;
import we.plugin.auth.AppService;
import we.plugin.auth.GatewayGroupService;
import we.proxy.RpcInstanceService;
@@ -33,7 +33,7 @@ import javax.annotation.Resource;
/**
* refresh config local cache config
* @see ApiConfigService#refreshLocalCache() refresh api config local cache
* @see ApiConifg2appsService#refreshLocalCache() refresh api config to apps local cache
* @see ApiConfig2appsService#refreshLocalCache() refresh api config to apps local cache
* @see ConfigLoader#refreshLocalCache() refresh aggregate config local cache
* @see GatewayGroupService#refreshLocalCache() refresh gateway group local cache
* @see AppService#refreshLocalCache() refresh app local cache
@@ -56,7 +56,7 @@ public class RefreshLocalCacheConfig {
private ApiConfigService apiConfigService;
@Resource
private ApiConifg2appsService apiConifg2appsService;
private ApiConfig2appsService apiConfig2AppsService;
@Resource
private GatewayGroupService gatewayGroupService;
@@ -88,7 +88,7 @@ public class RefreshLocalCacheConfig {
if (refreshLocalCacheConfigProperties.isApiConfig2AppsCacheRefreshEnabled()) {
LOGGER.debug("refresh api config to apps local cache");
try {
apiConifg2appsService.refreshLocalCache();
apiConfig2AppsService.refreshLocalCache();
} catch (Throwable t) {
LOGGER.warn("refresh api config to apps local cache exception", t);
}

View File

@@ -42,22 +42,26 @@ public class SystemConfig {
private static final Logger log = LoggerFactory.getLogger(SystemConfig.class);
public static final String DEFAULT_GATEWAY_PREFIX = "/proxy";
public static final String DEFAULT_GATEWAY_TEST_PREFIX = "/_proxytest";
public static final String DEFAULT_GATEWAY_TEST = "_proxytest";
public static final String DEFAULT_GATEWAY_TEST_PREFIX0 = "/_proxytest/";
public static final String DEFAULT_GATEWAY_PREFIX = "/proxy";
public static final String DEFAULT_GATEWAY_TEST_PREFIX = "/_proxytest";
public static final String DEFAULT_GATEWAY_TEST = "_proxytest";
public static final String DEFAULT_GATEWAY_TEST_PREFIX0 = "/_proxytest/";
public static boolean FIZZ_ERR_RESP_HTTP_STATUS_ENABLE = true;
public static String FIZZ_ERR_RESP_CODE_FIELD = "msgCode";
public static String FIZZ_ERR_RESP_MSG_FIELD = "message";
public static boolean FIZZ_ERR_RESP_HTTP_STATUS_ENABLE = true;
public static String FIZZ_ERR_RESP_CODE_FIELD = "msgCode";
public static String FIZZ_ERR_RESP_MSG_FIELD = "message";
public static final String FIZZ_APP_ID = "fizz-appid";
public static final String FIZZ_SIGN = "fizz-sign";
public static final String FIZZ_TIMESTAMP = "fizz-ts";
public static final String FIZZ_DL_ID = "fizz-dl-id";
public static final String FIZZ_DL_SIGN = "fizz-dl-sign";
public static final String FIZZ_DL_TS = "fizz-dl-ts";
public static final String FIZZ_API_PAIRING_SERVER_ENABLE = "fizz.api.pairing.server.enable";
public static final String FIZZ_API_PAIRING_CLIENT_PREFIX = "fizz.api.pairing.client";
public static final String FIZZ_API_PAIRING_CLIENT_ENABLE = "fizz.api.pairing.client.enable";
public static final String FIZZ_APP_ID = "fizz-appid";
public static final String FIZZ_SIGN = "fizz-sign";
public static final String FIZZ_TIMESTAMP = "fizz-ts";
public static final String FIZZ_DEDICATED_LINE_SERVER_ENABLE = "fizz.dedicated-line.server.enable";
public static final String FIZZ_DEDICATED_LINE_CLIENT_PREFIX = "fizz.dedicated-line.client";
public static final String FIZZ_DEDICATED_LINE_CLIENT_ENABLE = "fizz.dedicated-line.client.enable";
private String gatewayPrefix = DEFAULT_GATEWAY_PREFIX;
@@ -98,32 +102,32 @@ public class SystemConfig {
@Value("${fizz.api.pairing.client.request.timeliness:300}")
private int fizzApiPairingRequestTimeliness = 300; // unit: sec
@Value("${fizz.dedicated-line.client.request.timeliness:300}")
private int fizzDedicatedLineClientRequestTimeliness = 300; // unit: sec
@Value("${fizz.api.pairing.client.request.timeout:0}")
private int fizzApiPairingRequestTimeout = 0; // mills
@Value("${fizz.dedicated-line.client.request.timeout:0}")
private int fizzDedicatedLineClientRequestTimeout = 0; // mills
@Value("${fizz.api.pairing.client.request.retry-count:0}")
private int fizzApiPairingRequestRetryCount = 0;
@Value("${fizz.dedicated-line.client.request.retry-count:0}")
private int fizzDedicatedLineClientRequestRetryCount = 0;
@Value("${fizz.api.pairing.client.request.retry-interval:0}")
private int fizzApiPairingRequestRetryInterval = 0; // mills
@Value("${fizz.dedicated-line.client.request.retry-interval:0}")
private int fizzDedicatedLineClientRequestRetryInterval = 0; // mills
public int fizzApiPairingRequestTimeout() {
return fizzApiPairingRequestTimeout;
public int fizzDedicatedLineClientRequestTimeout() {
return fizzDedicatedLineClientRequestTimeout;
}
public int fizzApiPairingRequestRetryCount() {
return fizzApiPairingRequestRetryCount;
public int fizzDedicatedLineClientRequestRetryCount() {
return fizzDedicatedLineClientRequestRetryCount;
}
public int fizzApiPairingRequestRetryInterval() {
return fizzApiPairingRequestRetryInterval;
public int fizzDedicatedLineClientRequestRetryInterval() {
return fizzDedicatedLineClientRequestRetryInterval;
}
public int fizzApiPairingRequestTimeliness() {
return fizzApiPairingRequestTimeliness;
public int fizzDedicatedLineClientRequestTimeliness() {
return fizzDedicatedLineClientRequestTimeliness;
}

View File

@@ -23,8 +23,8 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import we.global_resource.GlobalResourceService;
import we.plugin.auth.ApiConfig2appsService;
import we.plugin.auth.ApiConfigService;
import we.plugin.auth.ApiConifg2appsService;
import we.plugin.auth.AppService;
import we.plugin.auth.GatewayGroupService;
import we.stats.ratelimit.ResourceRateLimitConfigService;
@@ -53,7 +53,7 @@ public class CacheCheckController {
private ResourceRateLimitConfigService resourceRateLimitConfigService;
@Resource
private ApiConifg2appsService apiConifg2appsService;
private ApiConfig2appsService apiConfig2AppsService;
@Resource
private GlobalResourceService globalResourceService;
@@ -74,7 +74,7 @@ public class CacheCheckController {
}
@GetMapping("/serviceConfigs")
public Mono<String> apiConfigs(ServerWebExchange exchange) {
public Mono<String> serviceConfigs(ServerWebExchange exchange) {
return Mono.just(JacksonUtils.writeValueAsString(apiConfigService.serviceConfigMap));
}
@@ -85,11 +85,11 @@ public class CacheCheckController {
@GetMapping("/apiConfig2appsConfigs")
public Mono<String> apiConfig2appsConfigs(ServerWebExchange exchange) {
return Mono.just(JacksonUtils.writeValueAsString(apiConifg2appsService.getApiConfig2appsMap()));
return Mono.just(JacksonUtils.writeValueAsString(apiConfig2AppsService.getApiConfig2appsMap()));
}
@GetMapping("/globalResources")
public Mono<String> dicts(ServerWebExchange exchange) {
public Mono<String> globalResources(ServerWebExchange exchange) {
return Mono.just(JacksonUtils.writeValueAsString(globalResourceService.getResourceMap()));
}
}

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.api.pairing;
package we.dedicated_line;
import we.util.JacksonUtils;
@@ -26,11 +26,15 @@ import java.util.List;
* @author hongqiaowei
*/
public class ApiPairingDoc {
public class ApiDoc {
public String service;
public List<Api> apis = Collections.emptyList();
public List<MethodAndPath> methodAndPaths = Collections.emptyList();
public void setApis(List<MethodAndPath> methodAndPaths) {
this.methodAndPaths = methodAndPaths;
}
@Override
public String toString() {

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2020 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.dedicated_line;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.util.CollectionUtils;
import we.util.JacksonUtils;
import java.util.*;
/**
* @author hongqiaowei
*/
public class DedicatedLine {
public boolean isDeleted = false;
public String pairCodeId;
public String secretKey;
public String customConfig;
public List<ApiDoc> apiDocs = Collections.emptyList();
@JsonIgnore
public Map<String/*service*/,
Map<Object/*method*/, Set<String/*pathPattern*/>>
>
apiDocMap = Collections.emptyMap();
public Set<String> servicesWithoutApiDocs = Collections.emptySet();
public void setDeleted(int v) {
if (v == 1) {
isDeleted = true;
}
}
public void setDocs(List<ApiDoc> docs) {
apiDocs = docs;
if (CollectionUtils.isEmpty(apiDocs)) {
apiDocMap = Collections.emptyMap();
} else {
apiDocMap = new HashMap<>();
for (ApiDoc apiDoc : apiDocs) {
Map<Object, Set<String>> methodPathsMap = apiDocMap.computeIfAbsent(apiDoc.service, k -> new HashMap<>());
for (MethodAndPath methodAndPath : apiDoc.methodAndPaths) {
Set<String> paths = methodPathsMap.computeIfAbsent(methodAndPath.method, k -> new HashSet<>());
paths.add(methodAndPath.path);
}
}
}
}
public void setServices(Set<String> services) {
servicesWithoutApiDocs = services;
}
@Override
public String toString() {
return JacksonUtils.writeValueAsString(this);
}
}

View File

@@ -15,15 +15,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.api.pairing;
package we.dedicated_line;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.bind.annotation.GetMapping;
@@ -36,37 +34,31 @@ import reactor.core.publisher.Mono;
import we.config.FizzMangerConfig;
import we.config.SystemConfig;
import we.flume.clients.log4j2appender.LogService;
import we.plugin.auth.App;
import we.plugin.auth.AppService;
import we.proxy.FizzWebClient;
import we.util.*;
import we.util.DateTimeUtils;
import we.util.Result;
import we.util.ThreadContext;
import we.util.WebUtils;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author hongqiaowei
*/
@ConditionalOnProperty(name = SystemConfig.FIZZ_API_PAIRING_SERVER_ENABLE, havingValue = "true")
@ConditionalOnProperty(name = SystemConfig.FIZZ_DEDICATED_LINE_SERVER_ENABLE, havingValue = "true")
@RestController
@RequestMapping(SystemConfig.DEFAULT_GATEWAY_PREFIX + "/_fizz-pairing")
public class ApiPairingController {
@RequestMapping(SystemConfig.DEFAULT_GATEWAY_PREFIX + "/_fizz-dedicated-line")
public class DedicatedLineController {
private static final Logger log = LoggerFactory.getLogger(ApiPairingController.class);
private static final Logger log = LoggerFactory.getLogger(DedicatedLineController.class);
@Resource
private SystemConfig systemConfig;
@Resource
private AppService appService;
@Resource
private ApiPairingDocSetService apiPairingDocSetService;
private DedicatedLineService dedicatedLineService;
@Resource
private FizzMangerConfig fizzMangerConfig;
@@ -75,23 +67,19 @@ public class ApiPairingController {
private FizzWebClient fizzWebClient;
private Result<?> auth(ServerWebExchange exchange) {
String appId = WebUtils.getAppId(exchange);
if (appId == null) {
return Result.fail("no app info in request");
}
App app = appService.getApp(appId);
if (app == null) {
return Result.fail(appId + " not exists");
String dedicatedLineId = WebUtils.getDedicatedLineId(exchange);
if (dedicatedLineId == null) {
return Result.fail("no dedicated line id in request");
}
String timestamp = WebUtils.getTimestamp(exchange);
String timestamp = WebUtils.getDedicatedLineTimestamp(exchange);
if (timestamp == null) {
return Result.fail("no timestamp in request");
}
try {
long ts = Long.parseLong(timestamp);
LocalDateTime now = LocalDateTime.now();
long timeliness = systemConfig.fizzApiPairingRequestTimeliness();
long timeliness = systemConfig.fizzDedicatedLineClientRequestTimeliness();
long start = DateTimeUtils.toMillis(now.minusSeconds(timeliness));
long end = DateTimeUtils.toMillis(now.plusSeconds (timeliness));
if (start <= ts && ts <= end) {
@@ -100,17 +88,19 @@ public class ApiPairingController {
return Result.fail("request timestamp invalid");
}
} catch (NumberFormatException e) {
return Result.fail("request timestamp invalid");
return Result.fail("request timestamp format invalid");
}
String sign = WebUtils.getSign(exchange);
String sign = WebUtils.getDedicatedLineSign(exchange);
if (sign == null) {
return Result.fail("no sign in request");
}
boolean equals = ApiPairingUtils.checkSign(appId, timestamp, app.secretkey, sign);
String pairCodeSecretKey = dedicatedLineService.getPairCodeSecretKey(dedicatedLineId);
boolean equals = DedicatedLineUtils.checkSign(dedicatedLineId, timestamp, pairCodeSecretKey, sign);
if (!equals) {
String traceId = WebUtils.getTraceId(exchange);
log.warn("{} request authority: app {}, timestamp {}, sign {} invalid", traceId, appId, timestamp, sign, LogService.BIZ_ID, traceId);
log.warn("{} request authority: dedicated line id {}, timestamp {}, sign {} invalid", traceId, dedicatedLineId, timestamp, sign, LogService.BIZ_ID, traceId);
return Result.fail("request sign invalid");
}
return Result.succ();
@@ -118,37 +108,33 @@ public class ApiPairingController {
@GetMapping("/pair")
public Mono<Void> pair(ServerWebExchange exchange) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
Result<?> auth = auth(exchange);
if (auth.code == Result.SUCC) {
String appId = WebUtils.getAppId(exchange);
List<AppApiPairingDocSet> docs = getAppDocSet(appId);
String docsJson = JacksonUtils.writeValueAsString(docs);
response.setStatusCode(HttpStatus.OK);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
return response.writeWith(Mono.just(response.bufferFactory().wrap(docsJson.getBytes())));
} else {
return WebUtils.response(response, HttpStatus.FORBIDDEN, null, auth.msg);
String managerUrl = fizzMangerConfig.managerUrl;
if (managerUrl == null) {
return WebUtils.response(response, HttpStatus.INTERNAL_SERVER_ERROR, null, "no fizz manager url config");
}
}
String address = managerUrl + fizzMangerConfig.pairPath;
private List<AppApiPairingDocSet> getAppDocSet(String appId) {
Map<Long, ApiPairingDocSet> docSetMap = apiPairingDocSetService.getDocSetMap();
ArrayList<AppApiPairingDocSet> result = ThreadContext.getArrayList();
for (Map.Entry<Long, ApiPairingDocSet> entry : docSetMap.entrySet()) {
ApiPairingDocSet ds = entry.getValue();
AppApiPairingDocSet appDocSet = new AppApiPairingDocSet();
appDocSet.id = ds.id;
appDocSet.name = ds.name;
appDocSet.description = ds.description;
appDocSet.services = ds.docs.stream().map(d -> d.service).collect(Collectors.toSet());
appDocSet.enabled = false;
if (ds.appIds.contains(appId)) {
appDocSet.enabled = true;
}
result.add(appDocSet);
}
return result;
String traceId = WebUtils.getTraceId(exchange);
Mono<ClientResponse> remoteResponseMono = fizzWebClient.send(traceId, request.getMethod(), address, request.getHeaders(), null);
return
remoteResponseMono.flatMap(
remoteResp -> {
response.setStatusCode(remoteResp.statusCode());
HttpHeaders respHeaders = response.getHeaders();
HttpHeaders remoteRespHeaders = remoteResp.headers().asHttpHeaders();
respHeaders.putAll(remoteRespHeaders);
if (log.isDebugEnabled()) {
StringBuilder sb = ThreadContext.getStringBuilder();
WebUtils.response2stringBuilder(traceId, remoteResp, sb);
log.debug(sb.toString(), LogService.BIZ_ID, traceId);
}
return response.writeWith ( remoteResp.body(BodyExtractors.toDataBuffers()) )
.doOnError ( throwable -> cleanup(remoteResp) )
.doOnCancel( () -> cleanup(remoteResp) );
}
);
}
@GetMapping("/doc/**")
@@ -166,7 +152,7 @@ public class ApiPairingController {
String address = managerUrl + fizzMangerConfig.docPathPrefix + uri.substring(dp + 3);
String traceId = WebUtils.getTraceId(exchange);
Mono<ClientResponse> remoteResponseMono = fizzWebClient.send(traceId, request.getMethod(), address, request.getHeaders(), request.getBody());
Mono<ClientResponse> remoteResponseMono = fizzWebClient.send(traceId, request.getMethod(), address, request.getHeaders(), null);
return
remoteResponseMono.flatMap(
remoteResp -> {

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.api.pairing;
package we.dedicated_line;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -51,11 +51,11 @@ import java.util.Set;
* @author hongqiaowei
*/
class FizzApiPairingHttpHandler implements HttpHandler {
class DedicatedLineHttpHandler implements HttpHandler {
private static final String disconnected_client_log_category = "DisconnectedClient";
private static final Logger log = LoggerFactory.getLogger(FizzApiPairingHttpHandler.class);
private static final Logger log = LoggerFactory.getLogger(DedicatedLineHttpHandler.class);
private static final Logger lostClientLog = LoggerFactory.getLogger(disconnected_client_log_category);
@@ -69,19 +69,19 @@ class FizzApiPairingHttpHandler implements HttpHandler {
private SystemConfig systemConfig;
private FizzWebClient fizzWebClient;
private ApiPairingInfoService apiPairingInfoService;
private DedicatedLineInfoService dedicatedLineInfoService;
public FizzApiPairingHttpHandler(ReactiveWebServerApplicationContext applicationContext, WebSessionManager sessionManager, ServerCodecConfigurer codecConfigurer,
LocaleContextResolver localeContextResolver, ForwardedHeaderTransformer forwardedHeaderTransformer) {
public DedicatedLineHttpHandler(ReactiveWebServerApplicationContext applicationContext, WebSessionManager sessionManager, ServerCodecConfigurer codecConfigurer,
LocaleContextResolver localeContextResolver, ForwardedHeaderTransformer forwardedHeaderTransformer) {
this.sessionManager = sessionManager;
this.serverCodecConfigurer = codecConfigurer;
this.localeContextResolver = localeContextResolver;
this.forwardedHeaderTransformer = forwardedHeaderTransformer;
systemConfig = applicationContext.getBean(SystemConfig.class);
fizzWebClient = applicationContext.getBean(FizzWebClient.class);
apiPairingInfoService = applicationContext.getBean(ApiPairingInfoService.class);
systemConfig = applicationContext.getBean(SystemConfig.class);
fizzWebClient = applicationContext.getBean(FizzWebClient.class);
dedicatedLineInfoService = applicationContext.getBean(DedicatedLineInfoService.class);
}
@Override
@@ -105,14 +105,14 @@ class FizzApiPairingHttpHandler implements HttpHandler {
String path = requestURI.getPath();
int secFS = path.indexOf(Consts.S.FORWARD_SLASH, 1);
String service = path.substring(1, secFS);
ApiPairingInfo apiPairingInfo = apiPairingInfoService.get(service);
if (apiPairingInfo == null) {
log.warn("{}{} service no api pairing info", logPrefix, service);
return WebUtils.response(response, HttpStatus.FORBIDDEN, null, service + " service no api pairing info").then(response.setComplete());
DedicatedLineInfo dedicatedLineInfo = dedicatedLineInfoService.get(service);
if (dedicatedLineInfo == null) {
log.warn("{}{} service no dedicated line info", logPrefix, service);
return WebUtils.response(response, HttpStatus.FORBIDDEN, null, service + " service no dedicated line info").then(response.setComplete());
}
StringBuilder b = ThreadContext.getStringBuilder();
b.append(apiPairingInfo.url).append(path);
b.append(dedicatedLineInfo.url).append(path);
String qry = requestURI.getQuery();
if (StringUtils.hasText(qry)) {
if (org.apache.commons.lang3.StringUtils.indexOfAny(qry, Consts.S.LEFT_BRACE, Consts.S.FORWARD_SLASH, Consts.S.HASH) > 0) {
@@ -120,22 +120,23 @@ class FizzApiPairingHttpHandler implements HttpHandler {
}
b.append(Consts.S.QUESTION).append(qry);
}
String targetUrl = b.toString();
String appId = apiPairingInfo.appId;
String secretKey = apiPairingInfo.secretKey;
String timestamp = String.valueOf(System.currentTimeMillis());
String sign = ApiPairingUtils.sign(appId, timestamp, secretKey);
String targetUrl = b.toString();
String pairCodeId = dedicatedLineInfo.pairCodeId;
String secretKey = dedicatedLineInfo.secretKey;
String timestamp = String.valueOf(System.currentTimeMillis());
String sign = DedicatedLineUtils.sign(pairCodeId, timestamp, secretKey);
HttpHeaders writableHttpHeaders = HttpHeaders.writableHttpHeaders(request.getHeaders());
writableHttpHeaders.set(SystemConfig.FIZZ_APP_ID, appId);
writableHttpHeaders.set(SystemConfig.FIZZ_TIMESTAMP, timestamp);
writableHttpHeaders.set(SystemConfig.FIZZ_SIGN, sign);
writableHttpHeaders.set(SystemConfig.FIZZ_DL_ID, pairCodeId);
writableHttpHeaders.set(SystemConfig.FIZZ_DL_TS, timestamp);
writableHttpHeaders.set(SystemConfig.FIZZ_DL_SIGN, sign);
int requestTimeout = systemConfig.fizzApiPairingRequestTimeout();
int retryCount = systemConfig.fizzApiPairingRequestRetryCount();
int retryInterval = systemConfig.fizzApiPairingRequestRetryInterval();
int requestTimeout = systemConfig.fizzDedicatedLineClientRequestTimeout();
int retryCount = systemConfig.fizzDedicatedLineClientRequestRetryCount();
int retryInterval = systemConfig.fizzDedicatedLineClientRequestRetryInterval();
try {
// TODO: 如果有请求体则对请求体加密
Mono<ClientResponse> remoteResponseMono = fizzWebClient.send( request.getId(), request.getMethod(), targetUrl, writableHttpHeaders, request.getBody(),
requestTimeout, retryCount, retryInterval );
@@ -150,6 +151,7 @@ class FizzApiPairingHttpHandler implements HttpHandler {
WebUtils.response2stringBuilder(logPrefix, remoteResp, sb);
log.debug(sb.toString());
}
// TODO: 如果有响应体则对响应体解密响应可能是页面表单文件上传的结果图片等
return response.writeWith ( remoteResp.body(BodyExtractors.toDataBuffers()) )
.doOnError ( throwable -> cleanup(remoteResp) )
.doOnCancel( () -> cleanup(remoteResp) );

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.api.pairing;
package we.dedicated_line;
import we.util.JacksonUtils;
@@ -26,22 +26,26 @@ import java.util.List;
* @author hongqiaowei
*/
public class ApiPairingInfo {
public class DedicatedLineInfo {
public static final int DELETED = 1;
public int isDeleted = 0;
public boolean isDeleted = false;
public String id; // uuid
public String url;
public String appId;
public String pairCodeId;
public String secretKey;
public List<String> services = Collections.emptyList();
public void setDeleted(int v) {
if (v == 1) {
isDeleted = true;
}
}
@Override
public String toString() {
return JacksonUtils.writeValueAsString(this);

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.api.pairing;
package we.dedicated_line;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,20 +39,20 @@ import java.util.Map;
* @author hongqiaowei
*/
@ConditionalOnProperty(name = SystemConfig.FIZZ_API_PAIRING_CLIENT_ENABLE, havingValue = "true")
@ConditionalOnProperty(name = SystemConfig.FIZZ_DEDICATED_LINE_CLIENT_ENABLE, havingValue = "true")
@Service
public class ApiPairingInfoService {
public class DedicatedLineInfoService {
private static final Logger log = LoggerFactory.getLogger(ApiPairingInfoService.class);
private static final Logger log = LoggerFactory.getLogger(DedicatedLineInfoService.class);
private Map<String , ApiPairingInfo> serviceApiPairingInfoMap = new HashMap<>(64);
private Map<String , DedicatedLineInfo> serviceDedicatedLineInfoMap = new HashMap<>(32);
@Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
private ReactiveStringRedisTemplate rt;
@PostConstruct
public void init() throws Throwable {
Result<?> result = initApiPairingInfo();
Result<?> result = initDedicatedLineInfo();
if (result.code == Result.FAIL) {
throw new RuntimeException(result.msg, result.t);
}
@@ -62,9 +62,9 @@ public class ApiPairingInfoService {
}
}
private Result<?> initApiPairingInfo() {
private Result<?> initDedicatedLineInfo() {
Result<?> result = Result.succ();
Flux<Map.Entry<Object, Object>> resources = rt.opsForHash().entries("fizz_api_pairing_info");
Flux<Map.Entry<Object, Object>> resources = rt.opsForHash().entries("fizz_dedicated_line_info");
resources.collectList()
.defaultIfEmpty(Collections.emptyList())
.flatMap(
@@ -74,19 +74,19 @@ public class ApiPairingInfoService {
try {
for (Map.Entry<Object, Object> e : es) {
json = (String) e.getValue();
ApiPairingInfo info = JacksonUtils.readValue(json, ApiPairingInfo.class);
DedicatedLineInfo info = JacksonUtils.readValue(json, DedicatedLineInfo.class);
for (String service : info.services) {
serviceApiPairingInfoMap.put(service, info);
serviceDedicatedLineInfoMap.put(service, info);
}
log.info("init api pairing info: {}", info);
log.info("init dedicated line info: {}", info);
}
} catch (Throwable t) {
result.code = Result.FAIL;
result.msg = "init api pairing info error, info: " + json;
result.msg = "init dedicated line info error, info: " + json;
result.t = t;
}
} else {
log.info("no api pairing info");
log.info("no dedicated line info");
}
return Mono.empty();
}
@@ -94,7 +94,7 @@ public class ApiPairingInfoService {
.onErrorReturn(
throwable -> {
result.code = Result.FAIL;
result.msg = "init api pairing info error";
result.msg = "init dedicated line info error";
result.t = throwable;
return true;
},
@@ -106,7 +106,7 @@ public class ApiPairingInfoService {
private Result<?> lsnApiPairingInfoChange() {
Result<?> result = Result.succ();
String channel = "fizz_api_pairing_info_channel";
String channel = "fizz_dedicated_line_info_channel";
rt.listenToChannel(channel)
.doOnError(
t -> {
@@ -125,20 +125,20 @@ public class ApiPairingInfoService {
msg -> {
String message = msg.getMessage();
try {
ApiPairingInfo info = JacksonUtils.readValue(message, ApiPairingInfo.class);
if (info.isDeleted == ApiPairingDocSet.DELETED) {
DedicatedLineInfo info = JacksonUtils.readValue(message, DedicatedLineInfo.class);
if (info.isDeleted) {
for (String service : info.services) {
serviceApiPairingInfoMap.remove(service);
serviceDedicatedLineInfoMap.remove(service);
}
log.info("remove api pairing info: {}", info);
log.info("remove dedicated line info: {}", info);
} else {
for (String service : info.services) {
serviceApiPairingInfoMap.put(service, info);
serviceDedicatedLineInfoMap.put(service, info);
}
log.info("update api pairing info: {}", info);
log.info("update dedicated line info: {}", info);
}
} catch (Throwable t) {
log.error("update api pairing info error, {}", message, t);
log.error("update dedicated line info error, {}", message, t);
}
}
)
@@ -146,11 +146,7 @@ public class ApiPairingInfoService {
return result;
}
public Map<String, ApiPairingInfo> getServiceApiPairingInfoMap() {
return serviceApiPairingInfoMap;
}
public ApiPairingInfo get(String service) {
return serviceApiPairingInfoMap.get(service);
public DedicatedLineInfo get(String service) {
return serviceDedicatedLineInfoMap.get(service);
}
}

View File

@@ -0,0 +1,188 @@
/*
* Copyright (C) 2020 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.dedicated_line;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import we.config.AggregateRedisConfig;
import we.config.SystemConfig;
import we.plugin.auth.ApiConfig;
import we.util.JacksonUtils;
import we.util.Result;
import we.util.UrlTransformUtils;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @author hongqiaowei
*/
@ConditionalOnProperty(name = SystemConfig.FIZZ_DEDICATED_LINE_SERVER_ENABLE, havingValue = "true")
@Service
public class DedicatedLineService {
private static final Logger log = LoggerFactory.getLogger(DedicatedLineService.class);
private Map<String, DedicatedLine> dedicatedLineMap = new HashMap<>(32);
@Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
private ReactiveStringRedisTemplate rt;
@PostConstruct
public void init() throws Throwable {
Result<?> result = initDedicatedLine();
if (result.code == Result.FAIL) {
throw new RuntimeException(result.msg, result.t);
}
result = lsnDedicatedLineChange();
if (result.code == Result.FAIL) {
throw new RuntimeException(result.msg, result.t);
}
}
private Result<?> initDedicatedLine() {
Result<?> result = Result.succ();
Flux<Map.Entry<Object, Object>> resources = rt.opsForHash().entries("fizz_dedicated_line");
resources.collectList()
.defaultIfEmpty(Collections.emptyList())
.flatMap(
es -> {
if (!es.isEmpty()) {
String json = null;
try {
for (Map.Entry<Object, Object> e : es) {
json = (String) e.getValue();
DedicatedLine dl = JacksonUtils.readValue(json, DedicatedLine.class);
dedicatedLineMap.put(dl.pairCodeId, dl);
}
} catch (Throwable t) {
result.code = Result.FAIL;
result.msg = "init dedicated line error, json: " + json;
result.t = t;
}
} else {
log.info("no dedicated line");
}
return Mono.empty();
}
)
.onErrorReturn(
throwable -> {
result.code = Result.FAIL;
result.msg = "init dedicated line error";
result.t = throwable;
return true;
},
result
)
.block();
return result;
}
private Result<?> lsnDedicatedLineChange() {
Result<?> result = Result.succ();
String channel = "fizz_dedicated_line_channel";
rt.listenToChannel(channel)
.doOnError(
t -> {
result.code = Result.FAIL;
result.msg = "lsn error, channel: " + channel;
result.t = t;
log.error("lsn channel {} error", channel, t);
}
)
.doOnSubscribe(
s -> {
log.info("success to lsn on {}", channel);
}
)
.doOnNext(
msg -> {
String message = msg.getMessage();
try {
DedicatedLine dl = JacksonUtils.readValue(message, DedicatedLine.class);
if (dl.isDeleted) {
dedicatedLineMap.remove(dl.pairCodeId);
} else {
dedicatedLineMap.put(dl.pairCodeId, dl);
}
} catch (Throwable t) {
log.error("update dedicated line error, {}", message, t);
}
}
)
.subscribe();
return result;
}
public boolean auth(String pairCodeId, HttpMethod method, String service, String path) {
DedicatedLine dedicatedLine = dedicatedLineMap.get(pairCodeId);
if (dedicatedLine == null) {
return false;
}
if (dedicatedLine.servicesWithoutApiDocs.contains(service)) {
return true;
}
Map<Object, Set<String>> methodPathsMap = dedicatedLine.apiDocMap.get(service);
if (methodPathsMap == null) {
return false;
}
Set<String> pathPatterns = methodPathsMap.get(method);
if (pathPatterns != null) {
if (pathPatternMatch(path, pathPatterns)) {
return true;
}
}
pathPatterns = methodPathsMap.get(ApiConfig.ALL_METHOD);
if (pathPatterns != null) {
return pathPatternMatch(path, pathPatterns);
}
return false;
}
private boolean pathPatternMatch(String path, Set<String> pathPatterns) {
if (pathPatterns.contains(path)) {
return true;
}
for (String pathPattern : pathPatterns) {
if (UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path)) {
return true;
}
}
return false;
}
public String getPairCodeSecretKey(String pairCodeId) {
DedicatedLine dedicatedLine = dedicatedLineMap.get(pairCodeId);
if (dedicatedLine != null) {
return dedicatedLine.secretKey;
}
return null;
}
}

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.api.pairing;
package we.dedicated_line;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration;
import lombok.SneakyThrows;
@@ -47,9 +47,9 @@ import javax.annotation.PreDestroy;
@Configuration
@ConditionalOnDiscoveryEnabled
@ConditionalOnProperty(name = SystemConfig.FIZZ_API_PAIRING_CLIENT_ENABLE, havingValue = "true")
@ConditionalOnProperty(name = SystemConfig.FIZZ_DEDICATED_LINE_CLIENT_ENABLE, havingValue = "true")
@AutoConfigureAfter({EurekaClientAutoConfiguration.class, NacosDiscoveryAutoConfiguration.class})
public class ApiPairingServiceRegistration implements ApplicationListener<FizzApiPairingWebServerInitializedEvent> {
public class DedicatedLineServiceRegistration implements ApplicationListener<DedicatedLineWebServerInitializedEvent> {
private ServiceRegistry serviceRegistry;
@@ -57,12 +57,12 @@ public class ApiPairingServiceRegistration implements ApplicationListener<FizzAp
@SneakyThrows
@Override
public void onApplicationEvent(FizzApiPairingWebServerInitializedEvent event) {
public void onApplicationEvent(DedicatedLineWebServerInitializedEvent event) {
ReactiveWebServerApplicationContext applicationContext = event.getApplicationContext();
ConfigurableEnvironment env = applicationContext.getEnvironment();
String prefix = SystemConfig.FIZZ_API_PAIRING_CLIENT_PREFIX + ".service-registration";
String prefix = SystemConfig.FIZZ_DEDICATED_LINE_CLIENT_PREFIX + ".service-registration";
String type = env.getProperty(prefix + ".type");
if (StringUtils.isNotBlank(type)) {

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.api.pairing;
package we.dedicated_line;
import we.util.Consts;
import we.util.ThreadContext;
@@ -24,29 +24,29 @@ import we.util.ThreadContext;
* @author hongqiaowei
*/
public abstract class ApiPairingUtils extends org.apache.commons.codec.digest.DigestUtils {
public abstract class DedicatedLineUtils extends org.apache.commons.codec.digest.DigestUtils {
private ApiPairingUtils() {
private DedicatedLineUtils() {
}
public static String sign(String app, String timestamp, String secretKey) {
public static String sign(String pairCodeId, String timestamp, String secretKey) {
StringBuilder b = ThreadContext.getStringBuilder(ThreadContext.sb0);
b.append(app) .append(Consts.S.UNDER_LINE)
.append(timestamp).append(Consts.S.UNDER_LINE)
b.append(pairCodeId).append(Consts.S.UNDER_LINE)
.append(timestamp) .append(Consts.S.UNDER_LINE)
.append(secretKey);
return sha256Hex(b.toString());
}
public static String sign(String app, long timestamp, String secretKey) {
return sign(app, String.valueOf(timestamp), secretKey);
public static String sign(String pairCodeId, long timestamp, String secretKey) {
return sign(pairCodeId, String.valueOf(timestamp), secretKey);
}
public static boolean checkSign(String app, String timestamp, String secretKey, String sign) {
String s = sign(app, timestamp, secretKey);
public static boolean checkSign(String pairCodeId, String timestamp, String secretKey, String sign) {
String s = sign(pairCodeId, timestamp, secretKey);
return s.equals(sign);
}
public static boolean checkSign(String app, long timestamp, String secretKey, String sign) {
return checkSign(app, String.valueOf(timestamp), secretKey, sign);
public static boolean checkSign(String pairCodeId, long timestamp, String secretKey, String sign) {
return checkSign(pairCodeId, String.valueOf(timestamp), secretKey, sign);
}
}

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.api.pairing;
package we.dedicated_line;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,12 +40,12 @@ import javax.annotation.Resource;
* @author hongqiaowei
*/
@ConditionalOnProperty(name = SystemConfig.FIZZ_API_PAIRING_CLIENT_ENABLE, havingValue = "true")
@ConditionalOnProperty(name = SystemConfig.FIZZ_DEDICATED_LINE_CLIENT_ENABLE, havingValue = "true")
@Configuration
@AutoConfigureAfter({HttpHandlerAutoConfiguration.class})
public class FizzApiPairingWebServer {
public class DedicatedLineWebServer {
private static final Logger log = LoggerFactory.getLogger(FizzApiPairingWebServer.class);
private static final Logger log = LoggerFactory.getLogger(DedicatedLineWebServer.class);
@Resource
private ReactiveWebServerApplicationContext applicationContext;
@@ -55,7 +55,7 @@ public class FizzApiPairingWebServer {
private WebServer server;
@Value("${fizz.api.pairing.client.port:8601}")
@Value("${fizz.dedicated-line.client.port:8601}")
private int port = 8601;
@PostConstruct
@@ -63,7 +63,7 @@ public class FizzApiPairingWebServer {
HttpWebHandlerAdapter adapter = (HttpWebHandlerAdapter) httpHandler;
NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory(port);
server = factory.getWebServer(
new FizzApiPairingHttpHandler(
new DedicatedLineHttpHandler(
applicationContext,
new DefaultWebSessionManager(),
adapter.getCodecConfigurer(),
@@ -72,8 +72,8 @@ public class FizzApiPairingWebServer {
)
);
server.start();
log.info("fizz api pairing web server listen on {}", port);
applicationContext.publishEvent(new FizzApiPairingWebServerInitializedEvent(server, applicationContext));
log.info("fizz dedicated line web server listen on {}", port);
applicationContext.publishEvent(new DedicatedLineWebServerInitializedEvent(server, applicationContext));
}
@PreDestroy

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.api.pairing;
package we.dedicated_line;
import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext;
import org.springframework.boot.web.server.WebServer;
@@ -25,11 +25,11 @@ import org.springframework.context.ApplicationEvent;
* @author hongqiaowei
*/
public class FizzApiPairingWebServerInitializedEvent extends ApplicationEvent {
public class DedicatedLineWebServerInitializedEvent extends ApplicationEvent {
private final ReactiveWebServerApplicationContext applicationContext;
public FizzApiPairingWebServerInitializedEvent(WebServer webServer, ReactiveWebServerApplicationContext applicationContext) {
public DedicatedLineWebServerInitializedEvent(WebServer webServer, ReactiveWebServerApplicationContext applicationContext) {
super(webServer);
this.applicationContext = applicationContext;
}

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.api.pairing;
package we.dedicated_line;
import org.springframework.http.HttpMethod;
import we.plugin.auth.ApiConfig;
@@ -25,7 +25,7 @@ import we.util.JacksonUtils;
* @author hongqiaowei
*/
public class Api {
public class MethodAndPath {
public Object method;

View File

@@ -22,7 +22,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@@ -38,7 +37,9 @@ import we.exception.StopAndResponseException;
import we.fizz.exception.FizzRuntimeException;
import we.flume.clients.log4j2appender.LogService;
import we.legacy.RespEntity;
import we.util.*;
import we.util.JacksonUtils;
import we.util.ThreadContext;
import we.util.WebUtils;
import java.net.URI;
@@ -92,7 +93,7 @@ public class FilterExceptionHandlerConfig {
RespEntity rs = null;
if (ex.getStepContext() != null && ex.getStepContext().returnContext()) {
rs = new RespEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), tMsg, traceId, ex.getStepContext());
return resp.writeWith(Mono.just(resp.bufferFactory().wrap(JacksonUtils.writeValueAsString(rs).getBytes())));
return resp.writeWith(Mono.just(resp.bufferFactory().wrap(JacksonUtils.writeValueAsBytes(rs))));
} else {
rs = new RespEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), tMsg, traceId);
return resp.writeWith(Mono.just(resp.bufferFactory().wrap(rs.toString().getBytes())));

View File

@@ -31,7 +31,7 @@ public abstract class FizzWebFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
if (WebUtils.isAdminReq(exchange) || WebUtils.isFizzApiReq(exchange)) {
if (WebUtils.isAdminReq(exchange) || WebUtils.isFizzReq(exchange)) {
return chain.filter(exchange);
} else {
return doFilter(exchange, chain);

View File

@@ -32,7 +32,6 @@ import reactor.core.publisher.Mono;
import reactor.core.publisher.SignalType;
import we.config.SystemConfig;
import we.flume.clients.log4j2appender.LogService;
import we.legacy.RespEntity;
import we.plugin.auth.ApiConfigService;
import we.plugin.auth.AppService;
import we.stats.BlockType;
@@ -71,7 +70,7 @@ public class FlowControlFilter extends FizzWebFilter {
@Resource
private FlowControlFilterProperties flowControlFilterProperties;
private FlowControlFilterProperties flowControlFilterProperties;
@Resource
private ResourceRateLimitConfigService resourceRateLimitConfigService;
@@ -83,10 +82,10 @@ public class FlowControlFilter extends FizzWebFilter {
private ApiConfigService apiConfigService;
@Resource
private AppService appService;
private AppService appService;
@Resource
private SystemConfig systemConfig;
private SystemConfig systemConfig;
@Override
public Mono<Void> doFilter(ServerWebExchange exchange, WebFilterChain chain) {
@@ -107,7 +106,7 @@ public class FlowControlFilter extends FizzWebFilter {
service = WebUtils.getClientService(exchange);
if (service.startsWith(_fizz)) {
fizzApiReq = true;
exchange.getAttributes().put(WebUtils.FIZZ_API_REQUEST, Consts.S.EMPTY);
exchange.getAttributes().put(WebUtils.FIZZ_REQUEST, Consts.S.EMPTY);
}
}

View File

@@ -37,9 +37,7 @@ public class GlobalResource {
public static final int NUMBER = 3;
public static final int JSON = 4;
public static final int DELETED = 1;
public int isDeleted = 0;
public boolean isDeleted = false;
public int id;
@@ -86,7 +84,9 @@ public class GlobalResource {
@JsonProperty("update") long update
) {
this.isDeleted = isDeleted;
if (isDeleted == 1) {
this.isDeleted = true;
}
this.id = id;
this.key = key;
this.type = type;

View File

@@ -134,7 +134,7 @@ public class GlobalResourceService {
String message = msg.getMessage();
try {
GlobalResource r = JacksonUtils.readValue(message, GlobalResource.class);
if (r.isDeleted == GlobalResource.DELETED) {
if (r.isDeleted) {
resourceMap.remove(r.key);
objectMap.remove(r.key);
log.info("remove global resource {}", r.key);

View File

@@ -27,7 +27,6 @@ import we.plugin.PluginConfig;
import we.proxy.Route;
import we.util.JacksonUtils;
import we.util.UrlTransformUtils;
import we.util.WebUtils;
import javax.annotation.Nullable;
import java.util.*;
@@ -49,15 +48,9 @@ public class ApiConfig {
static final byte DUBBO = 5;
}
public static final int DELETED = 1;
public static final String ALL_METHOD = "AM";
public static final char ALLOW = 'a';
public static final String ALL_METHOD = "AM";
private static final String match_all = "/**";
private static final int ENABLE = 1;
private static final String match_all = "/**";
@JsonProperty(
access = JsonProperty.Access.WRITE_ONLY
@@ -67,7 +60,7 @@ public class ApiConfig {
@JsonProperty(
access = JsonProperty.Access.WRITE_ONLY
)
public int isDeleted = 0;
public boolean isDeleted = false;
public Set<String> gatewayGroups = Stream.of(GatewayGroup.DEFAULT).collect(Collectors.toCollection(LinkedHashSet::new));
@@ -80,11 +73,6 @@ public class ApiConfig {
public String backendService;
@JsonProperty(
access = JsonProperty.Access.WRITE_ONLY
)
public HttpMethod method;
public Object fizzMethod = ALL_METHOD;
public String path = match_all;
@@ -96,6 +84,8 @@ public class ApiConfig {
public String backendPath;
public boolean dedicatedLine = false;
@JsonProperty("proxyMode")
public byte type = Type.SERVICE_DISCOVERY;
@@ -103,7 +93,7 @@ public class ApiConfig {
public List<String> httpHostPorts;
public char access = ALLOW;
public boolean allowAccess = true;
public List<PluginConfig> pluginConfigs = Collections.emptyList();
@@ -125,6 +115,18 @@ public class ApiConfig {
public long retryInterval = 0;
public void setDeleted(int v) {
if (v == 1) {
isDeleted = true;
}
}
public void setAccess(char c) {
if (c != 'a') {
allowAccess = false;
}
}
public void setGatewayGroup(String ggs) {
gatewayGroups.remove(GatewayGroup.DEFAULT);
if (StringUtils.isBlank(ggs)) {
@@ -155,19 +157,21 @@ public class ApiConfig {
}
public void setMethod(String m) {
method = HttpMethod.resolve(m);
if (method == null) {
fizzMethod = HttpMethod.resolve(m);
if (fizzMethod == null) {
fizzMethod = ALL_METHOD;
} else {
fizzMethod = method;
}
}
public void setAppEnable(int v) {
if (v == ENABLE) {
if (v == 1) {
checkApp = true;
} else {
checkApp = false;
}
}
public void setDedicatedLine(int v) {
if (v == 1) {
dedicatedLine = true;
}
}
@@ -205,7 +209,8 @@ public class ApiConfig {
public Route getRoute(ServerWebExchange exchange, @Nullable List<PluginConfig> gatewayGroupPluginConfigs) {
ServerHttpRequest request = exchange.getRequest();
Route r = new Route().type( this.type)
Route r = new Route().dedicatedLine( this.dedicatedLine)
.type( this.type)
.method( request.getMethod())
.backendService(this.backendService)
.backendPath( this.backendPath)

View File

@@ -27,14 +27,18 @@ import java.util.List;
public class ApiConfig2apps {
public static final int DELETED = 1;
public int id;
public int isDeleted = 0;
public boolean isDeleted = false;
public List<String> apps;
public void setDeleted(int v) {
if (v == 1) {
isDeleted = true;
}
}
@Override
public String toString() {
return JacksonUtils.writeValueAsString(this);

View File

@@ -38,9 +38,9 @@ import java.util.*;
*/
@Service
public class ApiConifg2appsService {
public class ApiConfig2appsService {
private static final Logger log = LoggerFactory.getLogger(ApiConifg2appsService.class);
private static final Logger log = LoggerFactory.getLogger(ApiConfig2appsService.class);
private static final String fizzApiConfigAppSetSize = "fizz_api_config_app_set_size";
@@ -120,11 +120,7 @@ public class ApiConifg2appsService {
}
private void save(Integer apiConfigId, List<String> as, Map<Integer, Set<String>> apiConfig2appsMap) {
Set<String> appSet = apiConfig2appsMap.get(apiConfigId);
if (appSet == null) {
appSet = new HashSet<>();
apiConfig2appsMap.put(apiConfigId, appSet);
}
Set<String> appSet = apiConfig2appsMap.computeIfAbsent(apiConfigId, k -> new HashSet<>());
appSet.addAll(as);
log(apiConfigId, as);
}
@@ -168,9 +164,9 @@ public class ApiConifg2appsService {
private void updateApiConfig2appsMap(ApiConfig2apps data) {
Set<String> apps = apiConfig2appsMap.get(data.id);
if (data.isDeleted == ApiConfig2apps.DELETED) {
if (data.isDeleted) {
if (apps != null) {
apps.removeAll(data.apps);
data.apps.forEach(apps::remove);
log.info("remove " + data);
}
} else {

View File

@@ -25,7 +25,6 @@ import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicatio
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.Nullable;
@@ -54,7 +53,7 @@ import java.util.regex.Pattern;
@Service
public class ApiConfigService implements ApplicationListener<ContextRefreshedEvent> {
private static final Logger log = LoggerFactory.getLogger(ApiConfigService.class);
private static final Logger log = LoggerFactory.getLogger(ApiConfigService.class);
public Map<String, ServiceConfig> serviceConfigMap = new HashMap<>(128);
@@ -75,7 +74,7 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
private AppService appService;
@Resource
private ApiConifg2appsService apiConifg2appsService;
private ApiConfig2appsService apiConfig2AppsService;
@Resource
private GatewayGroupService gatewayGroupService;
@@ -110,9 +109,8 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
if (k == ReactorUtils.OBJ) {
return Flux.just(e);
}
Object v = e.getValue();
log.info("init api config: {}", v.toString(), LogService.BIZ_ID, k.toString());
String json = (String) v;
String json = (String) e.getValue();
log.info("init api config: {}", json, LogService.BIZ_ID, k.toString());
try {
ApiConfig ac = JacksonUtils.readValue(json, ApiConfig.class);
apiConfigMapTmp.put(ac.id, ac);
@@ -162,15 +160,15 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
try {
ApiConfig ac = JacksonUtils.readValue(json, ApiConfig.class);
ApiConfig r = apiConfigMap.remove(ac.id);
if (ac.isDeleted != ApiConfig.DELETED && r != null) {
r.isDeleted = ApiConfig.DELETED;
if (!ac.isDeleted && r != null) {
r.isDeleted = true;
updateServiceConfigMap(r, serviceConfigMap);
}
updateServiceConfigMap(ac, serviceConfigMap);
if (ac.isDeleted != ApiConfig.DELETED) {
if (!ac.isDeleted) {
apiConfigMap.put(ac.id, ac);
} else {
apiConifg2appsService.remove(ac.id);
apiConfig2AppsService.remove(ac.id);
}
} catch (Throwable t) {
log.error("deser {}", json, t);
@@ -289,7 +287,7 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
public void updateServiceConfigMap(ApiConfig ac, Map<String, ServiceConfig> serviceConfigMap) {
ServiceConfig sc = serviceConfigMap.get(ac.service);
if (ac.isDeleted == ApiConfig.DELETED) {
if (ac.isDeleted) {
if (sc != null) {
sc.remove(ac);
if (sc.apiConfigMap.isEmpty()) {
@@ -353,26 +351,26 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
}
public ApiConfig getApiConfig(String app, String service, HttpMethod method, String path) {
Result<ApiConfig> result = get(null, app, service, method, path);
Result<ApiConfig> result = get(false, null, app, service, method, path);
if (result.code == Result.SUCC) {
return result.data;
}
return null;
}
public Result<ApiConfig> get(String app, String service, HttpMethod method, String path) {
return get(null, app, service, method, path);
public Result<ApiConfig> get(boolean dedicatedLineRequest, String app, String service, HttpMethod method, String path) {
return get(dedicatedLineRequest, null, app, service, method, path);
}
public ApiConfig getApiConfig(Set<String> gatewayGroups, String app, String service, HttpMethod method, String path) {
Result<ApiConfig> result = get(null, app, service, method, path);
Result<ApiConfig> result = get(false, null, app, service, method, path);
if (result.code == Result.SUCC) {
return result.data;
}
return null;
}
public Result<ApiConfig> get(Set<String> gatewayGroups, String app, String service, HttpMethod method, String path) {
public Result<ApiConfig> get(boolean dedicatedLineRequest, Set<String> gatewayGroups, String app, String service, HttpMethod method, String path) {
ServiceConfig sc = serviceConfigMap.get(service);
if (sc == null) {
return Result.fail("no " + service + " service api config");
@@ -380,34 +378,34 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
if (CollectionUtils.isEmpty(gatewayGroups)) {
gatewayGroups = gatewayGroupService.currentGatewayGroupSet;
}
List<ApiConfig> apiConfigs = sc.getApiConfigs(gatewayGroups, method, path);
List<ApiConfig> apiConfigs = sc.getApiConfigs(dedicatedLineRequest, gatewayGroups, method, path);
if (apiConfigs.isEmpty()) {
StringBuilder b = ThreadContext.getStringBuilder();
b.append(service).append(" don't have api config matching ").append(gatewayGroups).append(" group ").append(method).append(" method ").append(path).append(" path");
return Result.fail(b.toString());
}
List<ApiConfig> appCanAccess = ThreadContext.getArrayList();
List<ApiConfig> clientCanAccess = ThreadContext.getArrayList();
for (int i = 0; i < apiConfigs.size(); i++) {
ApiConfig ac = apiConfigs.get(i);
if (ac.checkApp) {
if (StringUtils.isNotBlank(app) && apiConifg2appsService.contains(ac.id, app)) {
appCanAccess.add(ac);
if (!dedicatedLineRequest && ac.checkApp) {
if (StringUtils.isNotBlank(app) && apiConfig2AppsService.contains(ac.id, app)) {
clientCanAccess.add(ac);
}
} else {
appCanAccess.add(ac);
clientCanAccess.add(ac);
}
}
if (appCanAccess.isEmpty()) {
if (clientCanAccess.isEmpty()) {
StringBuilder b = ThreadContext.getStringBuilder();
b.append("app ").append(app).append(" can't access ").append(JacksonUtils.writeValueAsString(apiConfigs));
return Result.fail(b.toString());
}
ApiConfig bestOne = appCanAccess.get(0);
if (appCanAccess.size() != 1) {
appCanAccess.sort(new ApiConfigPathPatternComparator(path)); // singleton ?
ApiConfig ac0 = appCanAccess.get(0);
ApiConfig bestOne = clientCanAccess.get(0);
if (clientCanAccess.size() != 1) {
clientCanAccess.sort(new ApiConfigPathPatternComparator(path)); // singleton ?
ApiConfig ac0 = clientCanAccess.get(0);
bestOne = ac0;
ApiConfig ac1 = appCanAccess.get(1);
ApiConfig ac1 = clientCanAccess.get(1);
if (ac0.path.equals(ac1.path)) {
if (ac0.fizzMethod == ac1.fizzMethod) {
if (StringUtils.isNotBlank(app)) {
@@ -428,11 +426,14 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
public Mono<Result<ApiConfig>> auth(ServerWebExchange exchange) {
ServerHttpRequest req = exchange.getRequest();
LogService.setBizId(WebUtils.getTraceId(exchange));
return auth(exchange, WebUtils.getAppId(exchange), WebUtils.getOriginIp(exchange), WebUtils.getTimestamp(exchange), WebUtils.getSign(exchange),
WebUtils.getClientService(exchange), req.getMethod(), WebUtils.getClientReqPath(exchange));
boolean dedicatedLineRequest = WebUtils.isDedicatedLineRequest(exchange);
return auth(exchange, dedicatedLineRequest,
WebUtils.getAppId(exchange), WebUtils.getOriginIp(exchange), WebUtils.getTimestamp(exchange), WebUtils.getSign(exchange),
WebUtils.getClientService(exchange), req.getMethod(), WebUtils.getClientReqPath(exchange));
}
private Mono<Result<ApiConfig>> auth(ServerWebExchange exchange, String app, String ip, String timestamp, String sign, String service, HttpMethod method, String path) {
private Mono<Result<ApiConfig>> auth(ServerWebExchange exchange, boolean dedicatedLineRequest,
String app, String ip, String timestamp, String sign, String service, HttpMethod method, String path) {
if (!systemConfig.isAggregateTestAuth()) {
if (SystemConfig.DEFAULT_GATEWAY_TEST_PREFIX0.equals(WebUtils.getClientReqPathPrefix(exchange))) {
@@ -440,7 +441,7 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
}
}
Result<ApiConfig> r = get(app, service, method, path);
Result<ApiConfig> r = get(dedicatedLineRequest, app, service, method, path);
if (r.code == Result.FAIL) {
if (apiConfigServiceProperties.isNeedAuth()) {
return Mono.just(r);
@@ -450,7 +451,7 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
}
ApiConfig ac = r.data;
if (ac.checkApp) {
if (!dedicatedLineRequest && ac.checkApp) {
App a = appService.getApp(app);
if (a.useWhiteList && !a.allow(ip)) {
r.code = Result.FAIL;
@@ -487,7 +488,7 @@ public class ApiConfigService implements ApplicationListener<ContextRefreshedEve
return Mono.just(r);
} else {
r.code = Result.FAIL;
r.msg = v.getReason();
r.msg = v.getReason();
return Mono.just(r);
}
}

View File

@@ -18,7 +18,6 @@
package we.plugin.auth;
import org.apache.commons.lang3.StringUtils;
import we.util.Consts;
import we.util.JacksonUtils;
@@ -30,9 +29,7 @@ import java.util.*;
public class App {
public static final String ALL_APP = "*";
public static final int DELETED = 1;
public static final String ALL_APP = "*";
static interface AUTH_TYPE {
static final int SIGN = 1;
@@ -40,7 +37,7 @@ public class App {
static final int SECRET_KEY = 3;
}
public int isDeleted = 0; // tb_app_auth.is_deleted
public boolean isDeleted = false; // tb_app_auth.is_deleted
public int id; // tb_app_auth.id
@@ -60,6 +57,12 @@ public class App {
public Map<String, List<String[]>> ips = new HashMap<>();
public void setDeleted(int v) {
if (v == 1) {
isDeleted = true;
}
}
public void setUseAuth(int i) {
if (i == AUTH_TYPE.SIGN || i == AUTH_TYPE.SECRET_KEY || i == AUTH_TYPE.CUSTOM) {
useAuth = true;

View File

@@ -23,9 +23,8 @@ import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import we.flume.clients.log4j2appender.LogService;
import we.config.AggregateRedisConfig;
import we.util.Consts;
import we.flume.clients.log4j2appender.LogService;
import we.util.JacksonUtils;
import we.util.ReactorUtils;
@@ -80,9 +79,8 @@ public class AppService {
if (k == ReactorUtils.OBJ) {
return Flux.just(e);
}
Object v = e.getValue();
log.info("init app: {}", v.toString(), LogService.BIZ_ID, k.toString());
String json = (String) v;
String json = (String) e.getValue();
log.info("init app: {}", json, LogService.BIZ_ID, k.toString());
try {
App app = JacksonUtils.readValue(json, App.class);
oldAppMapTmp.put(app.id, app);
@@ -127,15 +125,15 @@ public class AppService {
}
).doOnNext(msg -> {
String json = msg.getMessage();
log.info(json, LogService.BIZ_ID, "ac" + System.currentTimeMillis());
log.info("app change: " + json, LogService.BIZ_ID, "ac" + System.currentTimeMillis());
try {
App app = JacksonUtils.readValue(json, App.class);
App r = oldAppMap.remove(app.id);
if (app.isDeleted != App.DELETED && r != null) {
if (!app.isDeleted && r != null) {
appMap.remove(r.app);
}
updateAppMap(app, appMap);
if (app.isDeleted != App.DELETED) {
if (!app.isDeleted) {
oldAppMap.put(app.id, app);
}
} catch (Throwable t) {
@@ -158,7 +156,7 @@ public class AppService {
}
private void updateAppMap(App app, Map<String, App> appMap) {
if (app.isDeleted == App.DELETED) {
if (app.isDeleted) {
App removedApp = appMap.remove(app.app);
log.info("remove " + removedApp);
} else {

View File

@@ -35,11 +35,9 @@ public class GatewayGroup {
public static final String DEFAULT = "default";
public static final int DELETED = 1;
public int id;
public int isDeleted = 0;
public boolean isDeleted = false;
public String group;
@@ -49,6 +47,12 @@ public class GatewayGroup {
public List<PluginConfig> pluginConfigs = Collections.emptyList();
public void setDeleted(int v) {
if (v == 1) {
isDeleted = true;
}
}
public void setGateways(String gateways) {
if (StringUtils.isNotBlank(gateways)) {
Arrays.stream(StringUtils.split(gateways, ',')).forEach(

View File

@@ -26,7 +26,6 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import we.config.AggregateRedisConfig;
import we.flume.clients.log4j2appender.LogService;
import we.util.Consts;
import we.util.JacksonUtils;
import we.util.NetworkUtils;
import we.util.ReactorUtils;
@@ -87,9 +86,8 @@ public class GatewayGroupService {
if (k == ReactorUtils.OBJ) {
return Flux.just(e);
}
Object v = e.getValue();
log.info(k.toString() + Consts.S.COLON + v.toString(), LogService.BIZ_ID, k.toString());
String json = (String) v;
String json = (String) e.getValue();
log.info(json, LogService.BIZ_ID, k.toString());
try {
GatewayGroup gg = JacksonUtils.readValue(json, GatewayGroup.class);
oldGatewayGroupMapTmp.put(gg.id, gg);
@@ -139,11 +137,11 @@ public class GatewayGroupService {
try {
GatewayGroup gg = JacksonUtils.readValue(json, GatewayGroup.class);
GatewayGroup r = oldGatewayGroupMap.remove(gg.id);
if (gg.isDeleted != GatewayGroup.DELETED && r != null) {
if (!gg.isDeleted && r != null) {
gatewayGroupMap.remove(r.group);
}
updateGatewayGroupMap(gg, gatewayGroupMap, currentGatewayGroupSet);
if (gg.isDeleted != GatewayGroup.DELETED) {
if (!gg.isDeleted) {
oldGatewayGroupMap.put(gg.id, gg);
}
} catch (Throwable t) {
@@ -166,7 +164,7 @@ public class GatewayGroupService {
}
private void updateGatewayGroupMap(GatewayGroup gg, Map<String, GatewayGroup> gatewayGroupMap, Set<String> currentGatewayGroupSet) {
if (gg.isDeleted == GatewayGroup.DELETED) {
if (gg.isDeleted) {
GatewayGroup r = gatewayGroupMap.remove(gg.group);
log.info("remove " + r);
} else {

View File

@@ -94,17 +94,17 @@ public class ServiceConfig {
}
@JsonIgnore
public List<ApiConfig> getApiConfigs(Set<String> gatewayGroups, HttpMethod method, String path) {
public List<ApiConfig> getApiConfigs(boolean dedicatedLineRequest, Set<String> gatewayGroups, HttpMethod method, String path) {
ArrayList<ApiConfig> result = ThreadContext.getArrayList(ThreadContext.arrayList0);
for (String gatewayGroup : gatewayGroups) {
List<ApiConfig> apiConfigs = getApiConfigs(gatewayGroup, method, path);
List<ApiConfig> apiConfigs = getApiConfigs(dedicatedLineRequest, gatewayGroup, method, path);
result.addAll(apiConfigs);
}
return result;
}
@JsonIgnore
public List<ApiConfig> getApiConfigs(String gatewayGroup, HttpMethod method, String path) {
public List<ApiConfig> getApiConfigs(boolean dedicatedLineRequest, String gatewayGroup, HttpMethod method, String path) {
Map<Object, Map<String, Set<ApiConfig>>> method2pathPattenMap = apiConfigMap.get(gatewayGroup);
if (method2pathPattenMap == null) {
return Collections.emptyList();
@@ -112,42 +112,50 @@ public class ServiceConfig {
ArrayList<ApiConfig> result = ThreadContext.getArrayList();
Map<String, Set<ApiConfig>> pathPattern2apiConfigsMap = method2pathPattenMap.get(method);
if (pathPattern2apiConfigsMap != null) {
checkPathPattern(pathPattern2apiConfigsMap, path, result);
checkPathPattern(pathPattern2apiConfigsMap, dedicatedLineRequest, path, result);
}
pathPattern2apiConfigsMap = method2pathPattenMap.get(ApiConfig.ALL_METHOD);
if (pathPattern2apiConfigsMap != null) {
checkPathPattern(pathPattern2apiConfigsMap, path, result);
checkPathPattern(pathPattern2apiConfigsMap, dedicatedLineRequest, path, result);
}
return result;
}
}
private void checkPathPattern(Map<String, Set<ApiConfig>> pathPattern2apiConfigMap, String path, ArrayList<ApiConfig> result) {
Set<Map.Entry<String, Set<ApiConfig>>> entries = pathPattern2apiConfigMap.entrySet();
boolean clear = false;
for (Map.Entry<String, Set<ApiConfig>> entry : entries) {
String pathPattern = entry.getKey();
Set<ApiConfig> apiConfigs = entry.getValue();
if (pathPattern.equals(path)) {
for (ApiConfig ac : apiConfigs) {
if (ac.access == ApiConfig.ALLOW) {
if (!clear && !result.isEmpty()) {
result.clear();
clear = true;
private void checkPathPattern(Map<String, Set<ApiConfig>> pathPattern2apiConfigMap, boolean dedicatedLineRequest, String path, ArrayList<ApiConfig> result) {
Set<Map.Entry<String, Set<ApiConfig>>> entries = pathPattern2apiConfigMap.entrySet();
boolean clear = false;
for (Map.Entry<String, Set<ApiConfig>> entry : entries) {
String pathPattern = entry.getKey();
Set<ApiConfig> apiConfigs = entry.getValue();
if (pathPattern.equals(path)) {
for (ApiConfig ac : apiConfigs) {
if (ac.allowAccess) {
if (!clear && !result.isEmpty()) {
result.clear();
clear = true;
}
result.add(ac);
}
}
if (clear && !result.isEmpty()) {
return;
}
} else if (UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path)) {
for (ApiConfig ac : apiConfigs) {
if (ac.allowAccess) {
if (dedicatedLineRequest) {
if (ac.dedicatedLine) {
result.add(ac);
}
} else {
if (!ac.dedicatedLine) {
result.add(ac);
}
}
}
result.add(ac);
}
}
if (clear && !result.isEmpty()) {
return;
}
} else if (UrlTransformUtils.ANT_PATH_MATCHER.match(pathPattern, path)) {
for (ApiConfig ac : apiConfigs) {
if (ac.access == ApiConfig.ALLOW) {
result.add(ac);
}
}
}
} // end for
}
}
}

View File

@@ -95,45 +95,45 @@ public class CallbackService {
ServiceInstance si = service2instMap.get(r.service);
if (si == null) {
send = fizzWebClient.send2service(traceId, method, r.service, r.path, headers, body)
.onErrorResume( crError(exchange, r, method, headers, body) );
.onErrorResume( crError(exchange, r, method, headers, body) );
} else {
String uri = buildUri(req, si, r.path);
send = fizzWebClient.send(traceId, method, uri, headers, body)
.onErrorResume( crError(exchange, r, method, headers, body) );
.onErrorResume( crError(exchange, r, method, headers, body) );
}
} else {
send = aggregateService.request(WebUtils.getTraceId(exchange), WebUtils.getClientReqPathPrefix(exchange), method.name(), r.service, r.path, req.getQueryParams(), headers, body)
.onErrorResume( arError(exchange, r, method, headers, body) );
.onErrorResume( arError(exchange, r, method, headers, body) );
}
sends[i] = send;
}
return Flux.mergeSequential(sends)
.collectList()
.flatMap(
sendResults -> {
Object r = null;
for (int i = 1; i < sendResults.size(); i++) {
r = sendResults.get(i);
if (r instanceof ClientResponse && !(r instanceof FizzFailClientResponse)) {
clean((ClientResponse) r);
}
}
r = sendResults.get(0);
Throwable t = null;
if (r instanceof FizzFailClientResponse) {
t = ((FizzFailClientResponse) r).throwable;
return Mono.error(Utils.runtimeExceptionWithoutStack(t.getMessage()));
} if (r instanceof FailAggregateResult) {
t = ((FailAggregateResult) r).throwable;
return Mono.error(Utils.runtimeExceptionWithoutStack(t.getMessage()));
} else if (r instanceof ClientResponse) {
return genServerResponse(exchange, (ClientResponse) r);
} else {
return aggregateService.genAggregateResponse(exchange, (AggregateResult) r);
}
}
)
;
.collectList()
.flatMap(
sendResults -> {
Object r = null;
for (int i = 1; i < sendResults.size(); i++) {
r = sendResults.get(i);
if (r instanceof ClientResponse && !(r instanceof FizzFailClientResponse)) {
clean((ClientResponse) r);
}
}
r = sendResults.get(0);
Throwable t = null;
if (r instanceof FizzFailClientResponse) {
t = ((FizzFailClientResponse) r).throwable;
return Mono.error(Utils.runtimeExceptionWithoutStack(t.getMessage()));
} if (r instanceof FailAggregateResult) {
t = ((FailAggregateResult) r).throwable;
return Mono.error(Utils.runtimeExceptionWithoutStack(t.getMessage()));
} else if (r instanceof ClientResponse) {
return genServerResponse(exchange, (ClientResponse) r);
} else {
return aggregateService.genAggregateResponse(exchange, (AggregateResult) r);
}
}
)
;
}
private Function<Throwable, Mono<? extends ClientResponse>> crError(ServerWebExchange exchange, Receiver r, HttpMethod method, HttpHeaders headers, DataBuffer body) {
@@ -201,14 +201,14 @@ public class CallbackService {
log.debug(b.toString(), LogService.BIZ_ID, traceId);
}
return clientResp.writeWith(remoteResp.body(BodyExtractors.toDataBuffers()))
.doOnError(throwable -> clean(remoteResp)).doOnCancel(() -> clean(remoteResp));
.doOnError(throwable -> clean(remoteResp)).doOnCancel(() -> clean(remoteResp));
}
public Mono<Result> replay(CallbackReplayReq req) {
HashSet<String> gatewayGroups = new HashSet<>();
gatewayGroups.add(req.gatewayGroup);
Result<ApiConfig> result = apiConfigService.get(gatewayGroups, req.app, req.service, req.method, req.path);
Result<ApiConfig> result = apiConfigService.get(false, gatewayGroups, req.app, req.service, req.method, req.path);
ApiConfig ac = result.data;
if (ac == null) {
return Mono.just(Result.fail("no api config for " + req.path));
@@ -227,13 +227,13 @@ public class CallbackService {
if (si != null) {
String uri = buildUri("http", si, r.path);
send = fizzWebClient.send(req.id, req.method, uri, req.headers, req.body)
.onErrorResume( crError(req, r.service, r.path) );
.onErrorResume( crError(req, r.service, r.path) );
sends.add(send);
}
} else {
String traceId = CommonConstants.TRACE_ID_PREFIX + req.id;
send = aggregateService.request(traceId, aggrConfigPrefix, req.method.name(), r.service, r.path, null, req.headers, req.body)
.onErrorResume( arError(req, r.service, r.path) );
.onErrorResume( arError(req, r.service, r.path) );
sends.add(send);
}
}
@@ -243,11 +243,11 @@ public class CallbackService {
for (ServiceTypePath stp : req.assignServices) {
if (stp.type == ApiConfig.Type.SERVICE_DISCOVERY) {
send = fizzWebClient.send2service(req.id, req.method, stp.service, stp.path, req.headers, req.body)
.onErrorResume( crError(req, stp.service, stp.path) );
.onErrorResume( crError(req, stp.service, stp.path) );
} else {
String traceId = CommonConstants.TRACE_ID_PREFIX + req.id;
send = aggregateService.request(traceId, aggrConfigPrefix, req.method.name(), stp.service, stp.path, null, req.headers, req.body)
.onErrorResume( arError(req, stp.service, stp.path) );
.onErrorResume( arError(req, stp.service, stp.path) );
}
sends.add(send);
}
@@ -256,27 +256,27 @@ public class CallbackService {
int ss = sends.size();
Mono<Object>[] sendArr = sends.toArray(new Mono[ss]);
return Flux.mergeSequential(sendArr)
.collectList()
.map(
sendResults -> {
int c = Result.SUCC;
Throwable t = null;
for (int i = 0; i < sendResults.size(); i++) {
Object r = sendResults.get(i);
if (r instanceof FizzFailClientResponse) {
c = Result.FAIL;
t = ((FizzFailClientResponse) r).throwable;
} else if (r instanceof FailAggregateResult) {
c = Result.FAIL;
t = ((FailAggregateResult) r).throwable;
} else if (r instanceof ClientResponse) {
clean((ClientResponse) r);
}
}
return Result.with(c, t);
}
)
;
.collectList()
.map(
sendResults -> {
int c = Result.SUCC;
Throwable t = null;
for (int i = 0; i < sendResults.size(); i++) {
Object r = sendResults.get(i);
if (r instanceof FizzFailClientResponse) {
c = Result.FAIL;
t = ((FizzFailClientResponse) r).throwable;
} else if (r instanceof FailAggregateResult) {
c = Result.FAIL;
t = ((FailAggregateResult) r).throwable;
} else if (r instanceof ClientResponse) {
clean((ClientResponse) r);
}
}
return Result.with(c, t);
}
)
;
}
private Function<Throwable, Mono<? extends AggregateResult>> arError(CallbackReplayReq req, String service, String path) {
@@ -304,5 +304,4 @@ public class CallbackService {
private void clean(ClientResponse cr) {
cr.bodyToMono(Void.class).subscribe();
}
}

View File

@@ -30,6 +30,8 @@ import java.util.List;
public class Route {
public boolean dedicatedLine = false;
public byte type;
public HttpMethod method;
@@ -64,6 +66,11 @@ public class Route {
public long retryInterval = 0;
public Route dedicatedLine(boolean b) {
dedicatedLine = b;
return this;
}
public Route type(int t) {
type = (byte) t;
return this;

View File

@@ -292,7 +292,7 @@ public class RpcInstanceServiceImpl implements RpcInstanceService {
return isDeleted;
}
public void setIsDeleted(Integer isDeleted) {
public void setDeleted(Integer isDeleted) {
this.isDeleted = isDeleted;
}

View File

@@ -39,6 +39,9 @@ import java.util.Map;
public abstract class FizzEurekaHelper {
private FizzEurekaHelper() {
}
public static FizzEurekaServiceRegistration getServiceRegistration(FizzEurekaProperties fizzEurekaProperties) {
InetUtils inetUtils = fizzEurekaProperties.applicationContext.getBean(InetUtils.class);

View File

@@ -33,6 +33,9 @@ import java.util.Map;
public abstract class FizzNacosHelper {
private FizzNacosHelper() {
}
public static FizzNacosServiceRegistration getServiceRegistration(FizzNacosProperties fizzNacosProperties) {
fizzNacosProperties.init();
NacosServiceRegistry nacosServiceRegistry = new NacosServiceRegistry(fizzNacosProperties);

View File

@@ -39,8 +39,6 @@ public class ResourceRateLimitConfig {
static final byte IP = 7;
}
public static final int DELETED = 1;
public static final String NODE = "_global";
public static final String NODE_RESOURCE = buildResourceId(null, null, NODE, null, null);
@@ -53,11 +51,7 @@ public class ResourceRateLimitConfig {
public static final String APP_DEFAULT_RESOURCE = buildResourceId(APP_DEFAULT, null, null, null, null);
private static final int ENABLE = 1;
private static final int UNABLE = 0;
public int isDeleted = 0;
public boolean isDeleted = false;
public int id;
@@ -89,8 +83,14 @@ public class ResourceRateLimitConfig {
return enable;
}
public void setDeleted(int v) {
if (v == 1) {
isDeleted = true;
}
}
public void setEnable(int v) {
if (v == ENABLE) {
if (v == 1) {
enable = true;
} else {
enable = false;

View File

@@ -77,9 +77,8 @@ public class ResourceRateLimitConfigService {
if (k == ReactorUtils.OBJ) {
return Flux.just(e);
}
Object v = e.getValue();
log.info("rateLimitConfig: " + v.toString(), LogService.BIZ_ID, k.toString());
String json = (String) v;
String json = (String) e.getValue();
log.info("rateLimitConfig: " + json, LogService.BIZ_ID, k.toString());
try {
ResourceRateLimitConfig rrlc = JacksonUtils.readValue(json, ResourceRateLimitConfig.class);
oldResourceRateLimitConfigMapTmp.put(rrlc.id, rrlc);
@@ -127,11 +126,11 @@ public class ResourceRateLimitConfigService {
try {
ResourceRateLimitConfig rrlc = JacksonUtils.readValue(json, ResourceRateLimitConfig.class);
ResourceRateLimitConfig r = oldResourceRateLimitConfigMap.remove(rrlc.id);
if (rrlc.isDeleted != ResourceRateLimitConfig.DELETED && r != null) {
if (!rrlc.isDeleted && r != null) {
resourceRateLimitConfigMap.remove(r.getResourceId());
}
updateResourceRateLimitConfigMap(rrlc, resourceRateLimitConfigMap);
if (rrlc.isDeleted != ResourceRateLimitConfig.DELETED) {
if (!rrlc.isDeleted) {
oldResourceRateLimitConfigMap.put(rrlc.id, rrlc);
}
} catch (Throwable t) {
@@ -155,7 +154,7 @@ public class ResourceRateLimitConfigService {
private void updateResourceRateLimitConfigMap(ResourceRateLimitConfig rrlc,
Map<String, ResourceRateLimitConfig> resourceRateLimitConfigMap) {
if (rrlc.isDeleted == ResourceRateLimitConfig.DELETED) {
if (rrlc.isDeleted) {
ResourceRateLimitConfig removedRrlc = resourceRateLimitConfigMap.remove(rrlc.getResourceId());
log.info("remove " + removedRrlc);
} else {

View File

@@ -111,7 +111,7 @@ public abstract class WebUtils {
public static final String ADMIN_REQUEST = "ar@";
public static final String FIZZ_API_REQUEST = "far@";
public static final String FIZZ_REQUEST = "fr@";
private WebUtils() {
@@ -121,8 +121,8 @@ public abstract class WebUtils {
return exchange.getAttribute(ADMIN_REQUEST) != null;
}
public static boolean isFizzApiReq(ServerWebExchange exchange) {
return exchange.getAttribute(FIZZ_API_REQUEST) != null;
public static boolean isFizzReq(ServerWebExchange exchange) {
return exchange.getAttribute(FIZZ_REQUEST) != null;
}
public static void setGatewayPrefix(String p) {
@@ -149,6 +149,11 @@ public abstract class WebUtils {
return exchange.getRequest().getHeaders().get(header);
}
public static boolean isDedicatedLineRequest(ServerWebExchange exchange) {
String v = exchange.getRequest().getHeaders().getFirst(SystemConfig.FIZZ_DL_ID);
return v != null;
}
public static String getAppId(ServerWebExchange exchange) {
HttpHeaders headers = exchange.getRequest().getHeaders();
for (int i = 0; i < appHeaders.size(); i++) {
@@ -181,6 +186,18 @@ public abstract class WebUtils {
}
return null;
}
public static String getDedicatedLineId(ServerWebExchange exchange) {
return getHeaderValue(exchange, SystemConfig.FIZZ_DL_ID);
}
public static String getDedicatedLineTimestamp(ServerWebExchange exchange) {
return getHeaderValue(exchange, SystemConfig.FIZZ_DL_TS);
}
public static String getDedicatedLineSign(ServerWebExchange exchange) {
return getHeaderValue(exchange, SystemConfig.FIZZ_DL_SIGN);
}
public static String getClientService(ServerWebExchange exchange) {
String svc = exchange.getAttribute(clientService);

View File

@@ -1,72 +0,0 @@
package we.api.pairing;
import org.junit.Assert;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import we.Fizz;
import we.redis.RedisProperties;
import we.redis.RedisServerConfiguration;
import we.redis.RedisTemplateConfiguration;
import we.util.JacksonUtils;
import we.util.ReflectionUtils;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @author hongqiaowei
*/
@TestPropertySource("/application.properties")
@SpringJUnitConfig(classes = {RedisProperties.class, RedisTemplateConfiguration.class, RedisServerConfiguration.class})
public class ApiPairingDocSetServiceTests {
@Resource
StringRedisTemplate stringRedisTemplate;
@Resource
ReactiveStringRedisTemplate reactiveStringRedisTemplate;
ApiPairingDocSetService apiPairingDocSetService;
@BeforeEach
void beforeEach() throws NoSuchFieldException {
apiPairingDocSetService = new ApiPairingDocSetService();
ReflectionUtils.set(apiPairingDocSetService, "rt", reactiveStringRedisTemplate);
}
@Test
void initTest() throws Throwable {
Fizz.context = new GenericApplicationContext();
Fizz.context.refresh();
Map<String, String> hash = new HashMap<>();
hash.put("c", "{\"id\":1,\"name\":\"DocSet1\",\"docs\":[{\"service\":\"we-meb\",\"apis\":[{\"method\":\"GET\",\"path\":\"/getMebInfo\"}]}],\"appIds\":[\"app1\"]}");
hash.put("d", "{\"id\":2,\"name\":\"DocSet2\",\"docs\":[{\"service\":\"we-meb\",\"apis\":[{\"method\":\"GET\",\"path\":\"/getMebInfo\"}]}],\"appIds\":[\"app1\"]}");
// hash.put("a", "{\"isDeleted\":1,\"id\":1,\"name\":\"DocSet1\",\"docs\":[{\"service\":\"we-meb\",\"apis\":[{\"method\":\"GET\",\"path\":\"/getMebInfo\"}]}],\"appIds\":[\"app1\"]}");
// hash.put("b", "{\"isDeleted\":1,\"id\":2,\"name\":\"DocSet2\",\"docs\":[{\"service\":\"we-meb\",\"apis\":[{\"method\":\"GET\",\"path\":\"/getMebInfo\"}]}],\"appIds\":[\"app1\"]}");
stringRedisTemplate.opsForHash().putAll("fizz_api_pairing_doc", hash);
apiPairingDocSetService.init();
Map<Long, ApiPairingDocSet> docSetMap = apiPairingDocSetService.getDocSetMap();
Map<String, Set<ApiPairingDocSet>> appDocSetMap = apiPairingDocSetService.getAppDocSetMap();
Map<String, Set<ApiPairingDocSet>> serviceExistsInDocSetMap = apiPairingDocSetService.getServiceExistsInDocSetMap();
Map<Object, Map<String, Set<ApiPairingDocSet>>> methodPathExistsInDocSetMap = apiPairingDocSetService.getMethodPathExistsInDocSetMap();
// System.err.println("docSetMap: " + JacksonUtils.writeValueAsString(docSetMap));
// System.err.println("appDocSetMap: " + JacksonUtils.writeValueAsString(appDocSetMap));
// System.err.println("serviceExistsInDocSetMap: " + JacksonUtils.writeValueAsString(serviceExistsInDocSetMap));
// System.err.println("methodPathExistsInDocSetMap: " + JacksonUtils.writeValueAsString(methodPathExistsInDocSetMap));
boolean b = apiPairingDocSetService.existsDocSetMatch("app1", HttpMethod.GET, "we-meb", "/getMebInfo");
Assert.assertTrue(b);
}
}

View File

@@ -0,0 +1,45 @@
package we.dedicated_line;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import we.Fizz;
import we.redis.RedisProperties;
import we.redis.RedisServerConfiguration;
import we.redis.RedisTemplateConfiguration;
import we.util.ReflectionUtils;
import javax.annotation.Resource;
/**
* @author hongqiaowei
*/
@TestPropertySource("/application.properties")
@SpringJUnitConfig(classes = {RedisProperties.class, RedisTemplateConfiguration.class, RedisServerConfiguration.class})
public class DedicatedLineServiceTests {
@Resource
StringRedisTemplate stringRedisTemplate;
@Resource
ReactiveStringRedisTemplate reactiveStringRedisTemplate;
DedicatedLineService dedicatedLineService;
@BeforeEach
void beforeEach() throws NoSuchFieldException {
dedicatedLineService = new DedicatedLineService();
ReflectionUtils.set(dedicatedLineService, "rt", reactiveStringRedisTemplate);
}
@Test
void initTest() throws Throwable {
Fizz.context = new GenericApplicationContext();
Fizz.context.refresh();
}
}

View File

@@ -9,17 +9,13 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import we.redis.RedisProperties;
import we.redis.RedisServerConfiguration;
import we.redis.RedisTemplateConfiguration;
import we.stats.ratelimit.ResourceRateLimitConfigService;
import we.util.JacksonUtils;
import we.util.ReflectionUtils;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
@@ -31,17 +27,17 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class ApiConfig2appsServiceTests {
@Resource
StringRedisTemplate stringRedisTemplate;
StringRedisTemplate stringRedisTemplate;
@Resource
ReactiveStringRedisTemplate reactiveStringRedisTemplate;
ApiConifg2appsService apiConifg2appsService;
ApiConfig2appsService apiConfig2AppsService;
@BeforeEach
void beforeEach() throws NoSuchFieldException {
apiConifg2appsService = new ApiConifg2appsService();
ReflectionUtils.set(apiConifg2appsService, "rt", reactiveStringRedisTemplate);
apiConfig2AppsService = new ApiConfig2appsService();
ReflectionUtils.set(apiConfig2AppsService, "rt", reactiveStringRedisTemplate);
}
@Test
@@ -55,10 +51,10 @@ public class ApiConfig2appsServiceTests {
stringRedisTemplate.opsForSet().add("fizz_api_config_app:61_0", "app_b", "app_c");
stringRedisTemplate.opsForSet().add("fizz_api_config_app:61_1", "app_d");
apiConifg2appsService.init();
apiConfig2AppsService.init();
Thread.sleep(4000);
Map<Integer, Set<String>> apiConfig2appsMap = apiConifg2appsService.getApiConfig2appsMap();
Map<Integer, Set<String>> apiConfig2appsMap = apiConfig2AppsService.getApiConfig2appsMap();
// System.err.println("r: " + JacksonUtils.writeValueAsString(apiConfig2appsMap));
assertTrue(apiConfig2appsMap.get(61).contains("app_c"));
}