1. 服务编排调试模式开关从接口配置抽出来独立控制
2. 新增网关分组管理
3. 新增插件管理
4. appid管理新增自定义配置和IP段配置
5. 路由管理展示优化
6. 接口统计新增统计数据和图表展示
This commit is contained in:
Francis Dong
2020-10-21 10:01:04 +08:00
parent c6153fe90e
commit 7445fe88fc
61 changed files with 1166 additions and 597 deletions

View File

@@ -0,0 +1,9 @@
package we;
import org.springframework.context.ConfigurableApplicationContext;
public class FizzAppContext {
public static ConfigurableApplicationContext appContext;
}

View File

@@ -1,20 +1,3 @@
/*
* 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; package we;
import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig; import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
@@ -24,20 +7,16 @@ import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration; import org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration;
import org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration; import org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.ConfigurableApplicationContext;
/** @SpringBootApplication(
* @author lancer exclude = {ErrorWebFluxAutoConfiguration.class, RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class},
* @author francis scanBasePackages = {"we", "com.wh"}
*/ )
@SpringBootApplication(exclude = {ErrorWebFluxAutoConfiguration.class, RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class}) @EnableApolloConfig
// @EnableApolloConfig
@EnableDiscoveryClient @EnableDiscoveryClient
public class FizzGatewayApplication { public class FizzGatewayApplication {
public static ConfigurableApplicationContext appContext;
public static void main(String[] args) { public static void main(String[] args) {
FizzGatewayApplication.appContext = SpringApplication.run(FizzGatewayApplication.class, args); FizzAppContext.appContext = SpringApplication.run(FizzGatewayApplication.class, args);
} }
} }

View File

@@ -27,8 +27,6 @@ import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration; import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory; import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource; import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Order;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.properties.PropertiesConfigurationBuilder; import org.apache.logging.log4j.core.config.properties.PropertiesConfigurationBuilder;
import java.net.URI; import java.net.URI;

View File

@@ -23,8 +23,9 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient;
/** /**
* @author lancer * @author hongqiaowei
*/ */
@Configuration @Configuration
@ConfigurationProperties(prefix = AggrWebClientConfig.prefix) @ConfigurationProperties(prefix = AggrWebClientConfig.prefix)
public class AggrWebClientConfig extends WebClientConfig { public class AggrWebClientConfig extends WebClientConfig {

View File

@@ -23,6 +23,7 @@ import org.springframework.context.annotation.Configuration;
/** /**
* @author unknown * @author unknown
*/ */
@Configuration @Configuration
public class AppConfigProperties { public class AppConfigProperties {

View File

@@ -23,8 +23,9 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient;
/** /**
* @author lancer * @author hongqiaowei
*/ */
@Configuration @Configuration
@ConfigurationProperties(prefix = ProxyWebClientConfig.prefix) @ConfigurationProperties(prefix = ProxyWebClientConfig.prefix)
public class ProxyWebClientConfig extends WebClientConfig { public class ProxyWebClientConfig extends WebClientConfig {

View File

@@ -30,8 +30,9 @@ import org.springframework.data.redis.connection.lettuce.LettucePoolingClientCon
import org.springframework.data.redis.core.ReactiveStringRedisTemplate; import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public abstract class RedisReactiveConfig { public abstract class RedisReactiveConfig {
protected static final Logger log = LoggerFactory.getLogger(RedisReactiveConfig.class); protected static final Logger log = LoggerFactory.getLogger(RedisReactiveConfig.class);

View File

@@ -21,14 +21,15 @@ import we.util.Constants;
import we.util.Utils; import we.util.Utils;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public abstract class RedisReactiveProperties { public abstract class RedisReactiveProperties {
private String host = "127.0.0.1"; private String host = "127.0.0.1";
private int port = 6379; private int port = 6379;
private String password; private String password;
private int database = 0; private int database = 0;
public String getHost() { public String getHost() {
return host; return host;

View File

@@ -20,11 +20,13 @@ package we.config;
import com.ctrip.framework.apollo.model.ConfigChange; import com.ctrip.framework.apollo.model.ConfigChange;
import com.ctrip.framework.apollo.model.ConfigChangeEvent; import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import we.plugin.auth.GatewayGroup; import we.plugin.auth.GatewayGroup;
import we.util.Constants; import we.util.Constants;
import we.util.JacksonUtils; import we.util.JacksonUtils;
import we.util.NetworkUtils; import we.util.NetworkUtils;
import we.util.WebUtils; import we.util.WebUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -36,8 +38,9 @@ import javax.management.RuntimeErrorException;
import java.util.*; import java.util.*;
/** /**
* @author lancer * @author hongqiaowei
*/ */
@Configuration @Configuration
public class SystemConfig { public class SystemConfig {
@@ -51,19 +54,19 @@ public class SystemConfig {
private Set<String> logHeaderSet = new HashSet<>(); private Set<String> logHeaderSet = new HashSet<>();
@Value("${gateway-group:}") // @Value("${gateway-group:}")
private String gatewayGroup; // private String gatewayGroup;
//
private Map<String, Set<Character>> server2gatewayGroupSetMap = new HashMap<>(); // private Map<String, Set<Character>> server2gatewayGroupSetMap = new HashMap<>();
//
private Set<Character> currentServerGatewayGroupSet; // private Set<Character> currentServerGatewayGroupSet;
@Value("${spring.profiles.active}") @Value("${spring.profiles.active}")
private String profile; private String profile;
public Set<Character> getCurrentServerGatewayGroupSet() { // public Set<Character> getCurrentServerGatewayGroupSet() {
return currentServerGatewayGroupSet; // return currentServerGatewayGroupSet;
} // }
public Set<String> getLogHeaderSet() { public Set<String> getLogHeaderSet() {
return logHeaderSet; return logHeaderSet;
@@ -73,7 +76,7 @@ public class SystemConfig {
public void afterPropertiesSet() { public void afterPropertiesSet() {
afterLogResponseBodySet(); afterLogResponseBodySet();
afterLogHeadersSet(); afterLogHeadersSet();
afterGatewayGroupSet(); // afterGatewayGroupSet();
} }
private void afterLogResponseBodySet() { private void afterLogResponseBodySet() {
@@ -90,42 +93,42 @@ public class SystemConfig {
log.info("log header list: " + logHeaderSet.toString()); log.info("log header list: " + logHeaderSet.toString());
} }
private void afterGatewayGroupSet() { // private void afterGatewayGroupSet() {
server2gatewayGroupSetMap.clear(); // server2gatewayGroupSetMap.clear();
if (StringUtils.isNotBlank(gatewayGroup)) { // if (StringUtils.isNotBlank(gatewayGroup)) {
Arrays.stream(StringUtils.split(gatewayGroup, ';')).forEach( // Arrays.stream(StringUtils.split(gatewayGroup, ';')).forEach(
gg -> { // gg -> {
Character group = Character.valueOf(gg.charAt(0)); // Character group = Character.valueOf(gg.charAt(0));
String servers = gg.substring(gg.indexOf(':') + 1); // String servers = gg.substring(gg.indexOf(':') + 1);
Arrays.stream(StringUtils.split(servers, ',')).forEach( // Arrays.stream(StringUtils.split(servers, ',')).forEach(
s -> { // s -> {
Set<Character> gs = server2gatewayGroupSetMap.get(s); // Set<Character> gs = server2gatewayGroupSetMap.get(s);
if (gs == null) { // if (gs == null) {
gs = new HashSet<>(); // gs = new HashSet<>();
server2gatewayGroupSetMap.put(s, gs); // server2gatewayGroupSetMap.put(s, gs);
} // }
gs.add(group); // gs.add(group);
} // }
); // );
} // }
); // );
} // }
log.info("server 2 gateway group set map: " + JacksonUtils.writeValueAsString(server2gatewayGroupSetMap)); // log.info("server 2 gateway group set map: " + JacksonUtils.writeValueAsString(server2gatewayGroupSetMap));
String serverIp = NetworkUtils.getServerIp(); // String serverIp = NetworkUtils.getServerIp();
currentServerGatewayGroupSet = server2gatewayGroupSetMap.get(serverIp); // currentServerGatewayGroupSet = server2gatewayGroupSetMap.get(serverIp);
if (currentServerGatewayGroupSet == null) { // if (currentServerGatewayGroupSet == null) {
if (Constants.Profiles.DEV.equals(profile) || Constants.Profiles.TEST.equals(profile)) { // if (Constants.Profiles.DEV.equals(profile) || Constants.Profiles.TEST.equals(profile)) {
currentServerGatewayGroupSet = new HashSet<>(); // currentServerGatewayGroupSet = new HashSet<>();
currentServerGatewayGroupSet.add(GatewayGroup.C); // currentServerGatewayGroupSet.add(GatewayGroup.C);
currentServerGatewayGroupSet.add(GatewayGroup.B); // currentServerGatewayGroupSet.add(GatewayGroup.B);
currentServerGatewayGroupSet.add(GatewayGroup.T); // currentServerGatewayGroupSet.add(GatewayGroup.T);
server2gatewayGroupSetMap.put(serverIp, currentServerGatewayGroupSet); // server2gatewayGroupSetMap.put(serverIp, currentServerGatewayGroupSet);
} else { // } else {
throw new RuntimeException("no gateway group config for " + serverIp); // throw new RuntimeException("no gateway group config for " + serverIp);
} // }
} // }
log.info("current server: " + serverIp + ", belong to: " + currentServerGatewayGroupSet); // log.info("current server: " + serverIp + ", belong to: " + currentServerGatewayGroupSet);
} // }
@ApolloConfigChangeListener @ApolloConfigChangeListener
private void configChangeListter(ConfigChangeEvent cce) { private void configChangeListter(ConfigChangeEvent cce) {
@@ -142,10 +145,10 @@ public class SystemConfig {
} else if (p.equals("log.headers")) { } else if (p.equals("log.headers")) {
logHeaders = nv; logHeaders = nv;
afterLogHeadersSet(); afterLogHeadersSet();
} else if (p.equals("gateway-group")) { } /*else if (p.equals("gateway-group")) {
gatewayGroup = nv; gatewayGroup = nv;
afterGatewayGroupSet(); afterGatewayGroupSet();
} }*/
} }
); );
} }

View File

@@ -39,31 +39,32 @@ import java.time.Duration;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public abstract class WebClientConfig { public abstract class WebClientConfig {
protected static final Logger log = LoggerFactory.getLogger(WebClientConfig.class); protected static final Logger log = LoggerFactory.getLogger(WebClientConfig.class);
private String name; private String name;
private int maxConnections = 2_000; private int maxConnections = 2_000;
private Duration maxIdleTime = Duration.ofMillis(40_000); private Duration maxIdleTime = Duration.ofMillis(40_000);
private Duration pendingAcquireTimeout = Duration.ofMillis(6_000); private Duration pendingAcquireTimeout = Duration.ofMillis(6_000);
private long connReadTimeout = 20_000; private long connReadTimeout = 20_000;
private long connWriteTimeout = 20_000; private long connWriteTimeout = 20_000;
private int chConnTimeout = 20_000; private int chConnTimeout = 20_000;
private boolean chTcpNodelay = true; private boolean chTcpNodelay = true;
private boolean chSoKeepAlive = true; private boolean chSoKeepAlive = true;
private boolean compress = false; private boolean compress = false;
public String getName() { public String getName() {
return name; return name;
@@ -148,7 +149,9 @@ public abstract class WebClientConfig {
private ConnectionProvider getConnectionProvider() { private ConnectionProvider getConnectionProvider() {
String cpName = name + "-cp"; String cpName = name + "-cp";
ConnectionProvider cp = ConnectionProvider.builder(cpName).maxConnections(maxConnections) ConnectionProvider cp = ConnectionProvider.builder(cpName).maxConnections(maxConnections)
.pendingAcquireTimeout(pendingAcquireTimeout).maxIdleTime(maxIdleTime).build(); .pendingAcquireTimeout(pendingAcquireTimeout)
.maxIdleTime(maxIdleTime)
.build();
log.info(cpName + ' ' + cp); log.info(cpName + ' ' + cp);
return cp; return cp;
} }

View File

@@ -40,8 +40,9 @@ import reactor.netty.resources.LoopResources;
import java.time.Duration; import java.time.Duration;
/** /**
* @author lancer * @author hongqiaowei
*/ */
@Configuration @Configuration
@ConfigurationProperties(prefix = "server") @ConfigurationProperties(prefix = "server")
@EnableConfigurationProperties(ServerProperties.class) @EnableConfigurationProperties(ServerProperties.class)
@@ -124,9 +125,9 @@ public class WebFluxConfig {
// .channel(NioServerSocketChannel.class) // .channel(NioServerSocketChannel.class)
.option(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT) .option(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT)
// .option(ChannelOption.SO_BACKLOG, 8192) // .option(ChannelOption.SO_BACKLOG, 8192)
.childOption(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT) .childOption(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT)
.childOption(ChannelOption.SO_KEEPALIVE, true) .childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.TCP_NODELAY, true) .childOption(ChannelOption.TCP_NODELAY, true)
) )
) )
); );

View File

@@ -17,13 +17,13 @@
package we.controller; package we.controller;
import we.fizz.ConfigLoader;
import we.util.ScriptUtils;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.fizz.ConfigLoader;
import we.util.ScriptUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.File; import java.io.File;
@@ -32,6 +32,7 @@ import java.nio.charset.StandardCharsets;
/** /**
* @author unknown * @author unknown
*/ */
@RestController @RestController
@RequestMapping(value = "/config") @RequestMapping(value = "/config")
public class ConfigController { public class ConfigController {
@@ -45,7 +46,7 @@ public class ConfigController {
return Mono.just("ok"); return Mono.just("ok");
} }
// add by lancer // add by hongqiaowei
@PostMapping(value = "/fullUpdCommonJs", consumes = MediaType.TEXT_PLAIN_VALUE) @PostMapping(value = "/fullUpdCommonJs", consumes = MediaType.TEXT_PLAIN_VALUE)
public Mono<String> fullUpdCommonJs(ServerWebExchange exchange, @RequestBody String js) { public Mono<String> fullUpdCommonJs(ServerWebExchange exchange, @RequestBody String js) {
try { try {

View File

@@ -18,50 +18,64 @@
package we.controller; package we.controller;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import we.plugin.auth.ApiConfigService; import com.alibaba.fastjson.JSON;
import we.plugin.auth.AppService;
import we.util.JacksonUtils;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.plugin.auth.ApiConfigService;
import we.plugin.auth.AppService;
import we.plugin.auth.GatewayGroupService;
import we.util.JacksonUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
/** /**
* @author unknown * @author unknown
*/ */
@RestController @RestController
public class HealthController { public class HealthController {
@Resource
private GatewayGroupService gatewayGroupService;
@Resource @Resource
private AppService appService; private AppService appService;
@Resource @Resource
private ApiConfigService apiConfigService; private ApiConfigService apiConfigService;
@GetMapping("/time") // add by hongqiaowei
public Mono<String> time(ServerWebExchange exchange) throws Exception{
Date d = new Date();
return Mono.just("Time: " + d.toString());
}
// add by lancer
@GetMapping("/sysgc") @GetMapping("/sysgc")
public Mono<String> sysgc(ServerWebExchange exchange) throws Exception { public Mono<String> sysgc(ServerWebExchange exchange) throws Exception {
System.gc(); System.gc();
return Mono.just("sysgc done"); return Mono.just("sysgc done");
} }
@GetMapping("/gatewayGroups")
public Mono<String> gatewayGroups(ServerWebExchange exchange) throws Exception {
return Mono.just(JacksonUtils.writeValueAsString(gatewayGroupService.gatewayGroupMap));
}
@GetMapping("/currentGatewayGroups")
public Mono<String> currentGatewayGroups(ServerWebExchange exchange) throws Exception {
return Mono.just(JacksonUtils.writeValueAsString(gatewayGroupService.currentGatewayGroupSet));
}
@GetMapping("/apps") @GetMapping("/apps")
public Mono<String> apps(ServerWebExchange exchange) throws Exception { public Mono<String> apps(ServerWebExchange exchange) throws Exception {
return Mono.just(JacksonUtils.writeValueAsString(appService.getAppMap())); return Mono.just(JacksonUtils.writeValueAsString(appService.getAppMap()));
} }
@GetMapping("/apiConfigs") @GetMapping("/serviceConfigs")
public Mono<String> apiConfigs(ServerWebExchange exchange) throws Exception { public Mono<String> apiConfigs(ServerWebExchange exchange) throws Exception {
return Mono.just(JacksonUtils.writeValueAsString(apiConfigService.getApp2gatewayGroupMap())); return Mono.just(JacksonUtils.writeValueAsString(apiConfigService.serviceConfigMap));
} }
} }

View File

@@ -17,12 +17,6 @@
package we.controller; package we.controller;
import we.controller.req.BaseManagerConfigReq;
import we.controller.req.GetConfigStrReq;
import we.controller.req.GetConfigReq;
import we.controller.resp.ConfigStrResp;
import we.controller.resp.ConfigResp;
import we.fizz.ConfigLoader;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -30,6 +24,12 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.controller.req.BaseManagerConfigReq;
import we.controller.req.GetConfigReq;
import we.controller.req.GetConfigStrReq;
import we.controller.resp.ConfigResp;
import we.controller.resp.ConfigStrResp;
import we.fizz.ConfigLoader;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;

View File

@@ -17,12 +17,12 @@
package we.controller.resp; package we.controller.resp;
import we.fizz.ConfigLoader;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import we.fizz.ConfigLoader;
/** /**
* 聚合配置响应实体类 * 聚合配置响应实体类
* @author zhongjie * @author zhongjie

View File

@@ -17,7 +17,6 @@
package we.filter; package we.filter;
import we.config.SystemConfig;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
@@ -27,11 +26,14 @@ import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter; import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource; import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import we.config.SystemConfig;
import javax.annotation.Resource; import javax.annotation.Resource;
/** /**
* @author lancer * @author hongqiaowei
*/ */
@Configuration @Configuration
public class CorsFilterConfig { public class CorsFilterConfig {

View File

@@ -17,8 +17,6 @@
package we.filter; package we.filter;
import we.exception.StopAndResponseException;
import we.util.WebUtils;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
@@ -29,10 +27,13 @@ import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebExceptionHandler; import org.springframework.web.server.WebExceptionHandler;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.exception.StopAndResponseException;
import we.util.WebUtils;
/** /**
* @author lancer * @author hongqiaowei
*/ */
@Configuration @Configuration
public class FilterExceptionHandlerConfig { public class FilterExceptionHandlerConfig {

View File

@@ -20,8 +20,9 @@ package we.filter;
import java.util.Map; import java.util.Map;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public class FilterResult { public class FilterResult {
public String id; public String id;

View File

@@ -38,24 +38,24 @@ import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain; import org.springframework.web.server.WebFilterChain;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import we.flume.clients.log4j2appender.LogService;
import io.netty.buffer.UnpooledByteBufAllocator;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import we.constants.CommonConstants; import we.constants.CommonConstants;
import we.fizz.AggregateResource; import we.fizz.AggregateResource;
import we.fizz.AggregateResult; import we.fizz.AggregateResult;
import we.fizz.ConfigLoader; import we.fizz.ConfigLoader;
import we.fizz.Pipeline; import we.fizz.Pipeline;
import we.fizz.input.Input; import we.fizz.input.Input;
import we.flume.clients.log4j2appender.LogService;
import we.util.Constants; import we.util.Constants;
import we.util.MapUtil; import we.util.MapUtil;
import we.util.WebUtils; import we.util.WebUtils;
import io.netty.buffer.UnpooledByteBufAllocator;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
/** /**
* @author lancer * @author francis
*/ */
@Component @Component
@Order(2) @Order(2)

View File

@@ -17,8 +17,6 @@
package we.filter; package we.filter;
import we.flume.clients.log4j2appender.LogService;
import we.util.WebUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
@@ -27,10 +25,14 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain; import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.flume.clients.log4j2appender.LogService;
import we.util.ThreadContext;
import we.util.WebUtils;
/** /**
* @author lancer * @author hongqiaowei
*/ */
@Component @Component
@Order(0) @Order(0)
public class FizzLogFilter implements WebFilter { public class FizzLogFilter implements WebFilter {
@@ -46,7 +48,7 @@ public class FizzLogFilter implements WebFilter {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
return chain.filter(exchange).doAfterTerminate( return chain.filter(exchange).doAfterTerminate(
() -> { () -> {
StringBuilder b = new StringBuilder(160); StringBuilder b = ThreadContext.getStringBuilder();
WebUtils.request2stringBuilder(exchange, b); WebUtils.request2stringBuilder(exchange, b);
b.append(resp).append(exchange.getResponse().getStatusCode()) b.append(resp).append(exchange.getResponse().getStatusCode())
.append(in) .append(System.currentTimeMillis() - startTime); .append(in) .append(System.currentTimeMillis() - startTime);

View File

@@ -17,15 +17,6 @@
package we.filter; package we.filter;
import we.config.SystemConfig;
import we.plugin.FixedPluginFilter;
import we.plugin.PluginConfig;
import we.plugin.PluginFilter;
import we.plugin.auth.*;
import we.plugin.stat.StatPluginFilter;
import we.util.Constants;
import we.util.ReactorUtils;
import we.util.WebUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -37,15 +28,24 @@ import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain; import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.plugin.FixedPluginFilter;
import we.plugin.PluginConfig;
import we.plugin.PluginFilter;
import we.plugin.auth.ApiConfig;
import we.plugin.auth.ApiConfigService;
import we.plugin.auth.AuthPluginFilter;
import we.plugin.stat.StatPluginFilter;
import we.util.ReactorUtils;
import we.util.WebUtils;
import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
/** /**
* @author lancer * @author hongqiaowei
*/ */
@Component(PreFilter.PRE_FILTER) @Component(PreFilter.PRE_FILTER)
@Order(1) @Order(1)
public class PreFilter extends ProxyAggrFilter { public class PreFilter extends ProxyAggrFilter {
@@ -62,25 +62,12 @@ public class PreFilter extends ProxyAggrFilter {
@Value("${b-services:x}") @Value("${b-services:x}")
private Set<String> bServices = new HashSet<>(); private Set<String> bServices = new HashSet<>();
@Resource
private SystemConfig systemConfig;
@Resource(name = StatPluginFilter.STAT_PLUGIN_FILTER) @Resource(name = StatPluginFilter.STAT_PLUGIN_FILTER)
private StatPluginFilter statPluginFilter; private StatPluginFilter statPluginFilter;
@Resource(name = AuthPluginFilter.AUTH_PLUGIN_FILTER) @Resource(name = AuthPluginFilter.AUTH_PLUGIN_FILTER)
private AuthPluginFilter authPluginFilter; private AuthPluginFilter authPluginFilter;
private char currentGatewayGroup;
@PostConstruct
public void setCurrentGatewayGroup() {
for (Character gg : systemConfig.getCurrentServerGatewayGroupSet()) {
currentGatewayGroup = gg.charValue();
log.info("current gateway group is " + currentGatewayGroup);
break;
}
}
@Override @Override
public Mono<Void> doFilter(ServerWebExchange exchange, WebFilterChain chain) { public Mono<Void> doFilter(ServerWebExchange exchange, WebFilterChain chain) {
@@ -88,24 +75,11 @@ public class PreFilter extends ProxyAggrFilter {
Map<String, String> appendHdrs = new HashMap<>(6, 1.0f); Map<String, String> appendHdrs = new HashMap<>(6, 1.0f);
Map<String, Object> eas = exchange.getAttributes(); eas.put(WebUtils.FILTER_CONTEXT, fc); Map<String, Object> eas = exchange.getAttributes(); eas.put(WebUtils.FILTER_CONTEXT, fc);
eas.put(WebUtils.APPEND_HEADERS, appendHdrs); eas.put(WebUtils.APPEND_HEADERS, appendHdrs);
eas.put(WebUtils.CGG, currentGatewayGroup);
String app = WebUtils.getHeaderValue(exchange, WebUtils.APP_HEADER); String app = WebUtils.getHeaderValue(exchange, WebUtils.APP_HEADER);
if (StringUtils.isBlank(app)) { if (StringUtils.isNotBlank(app)) {
if (Constants.Profiles.DEV.equals(profile) || Constants.Profiles.TEST.equals(profile)) { eas.put(WebUtils.APP_HEADER, app);
String service = WebUtils.getServiceId(exchange);
if (bServices.contains(service)) {
app = App.TO_B;
} else {
app = App.TO_C;
}
} else if (currentGatewayGroup == GatewayGroup.B) {
app = App.TO_B;
} else {
app = App.TO_C;
}
} }
eas.put(WebUtils.APP_HEADER, app);
Mono vm = statPluginFilter.filter(exchange, null, null); Mono vm = statPluginFilter.filter(exchange, null, null);
return chain(exchange, vm, authPluginFilter).defaultIfEmpty(ReactorUtils.NULL) return chain(exchange, vm, authPluginFilter).defaultIfEmpty(ReactorUtils.NULL)
@@ -120,11 +94,7 @@ public class PreFilter extends ProxyAggrFilter {
if (ac.pluginConfigs == null || ac.pluginConfigs.isEmpty()) { if (ac.pluginConfigs == null || ac.pluginConfigs.isEmpty()) {
return m.flatMap(func(exchange, chain)); return m.flatMap(func(exchange, chain));
} else { } else {
return m.flatMap( return m.flatMap(e -> {return executeManagedPluginFilters(exchange, ac.pluginConfigs);})
e -> {
return executeManagedPluginFilters(exchange, ac.pluginConfigs);
}
)
.defaultIfEmpty(ReactorUtils.NULL).flatMap(func(exchange, chain)); .defaultIfEmpty(ReactorUtils.NULL).flatMap(func(exchange, chain));
} }
} else if (authRes == ApiConfigService.Access.YES) { } else if (authRes == ApiConfigService.Access.YES) {

View File

@@ -17,15 +17,16 @@
package we.filter; package we.filter;
import we.util.WebUtils;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain; import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.util.WebUtils;
/** /**
* @author lancer * @author hongqiaowei
*/ */
// TODO 类名调整 // TODO 类名调整
public abstract class ProxyAggrFilter implements WebFilter { public abstract class ProxyAggrFilter implements WebFilter {

View File

@@ -17,11 +17,6 @@
package we.filter; package we.filter;
import we.flume.clients.log4j2appender.LogService;
import we.legacy.RespEntity;
import we.proxy.FizzWebClient;
import we.util.ThreadContext;
import we.util.WebUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
@@ -36,14 +31,23 @@ import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain; import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.flume.clients.log4j2appender.LogService;
import we.legacy.RespEntity;
import we.plugin.auth.ApiConfig;
import we.plugin.auth.AuthPluginFilter;
import we.proxy.FizzWebClient;
import we.util.ThreadContext;
import we.util.WebUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
/** /**
* @author lancer * @author hongqiaowei
*/ */
@Component @Component
@Order(Ordered.LOWEST_PRECEDENCE) @Order(Ordered.LOWEST_PRECEDENCE)
public class RouteFilter extends ProxyAggrFilter { public class RouteFilter extends ProxyAggrFilter {
@@ -79,7 +83,6 @@ public class RouteFilter extends ProxyAggrFilter {
private Mono<Void> doFilter0(ServerWebExchange exchange, WebFilterChain chain) { private Mono<Void> doFilter0(ServerWebExchange exchange, WebFilterChain chain) {
ServerHttpRequest clientReq = exchange.getRequest(); ServerHttpRequest clientReq = exchange.getRequest();
String rid = clientReq.getId();
HttpHeaders hdrs = new HttpHeaders(); HttpHeaders hdrs = new HttpHeaders();
clientReq.getHeaders().forEach( clientReq.getHeaders().forEach(
(h, vs) -> { (h, vs) -> {
@@ -101,37 +104,65 @@ public class RouteFilter extends ProxyAggrFilter {
); );
} }
return fizzWebClient.proxySend2service(rid, clientReq.getMethod(), WebUtils.getServiceId(exchange), WebUtils.getRelativeUri(exchange), hdrs, exchange.getRequest().getBody()).flatMap( ApiConfig ac = null;
remoteResp -> { Object authRes = WebUtils.getFilterResultDataItem(exchange, AuthPluginFilter.AUTH_PLUGIN_FILTER, AuthPluginFilter.RESULT);
ServerHttpResponse clientResp = exchange.getResponse(); if (authRes instanceof ApiConfig) {
clientResp.setStatusCode(remoteResp.statusCode()); ac = (ApiConfig) authRes;
HttpHeaders clientRespHeaders = clientResp.getHeaders(); }
HttpHeaders remoteRespHeaders = remoteResp.headers().asHttpHeaders();
remoteRespHeaders.entrySet().forEach( String relativeUri = WebUtils.getRelativeUri(exchange);
h -> { if (ac == null || ac.proxyMode == ApiConfig.DIRECT_PROXY_MODE) {
String k = h.getKey(); return send(exchange, WebUtils.getServiceId(exchange), relativeUri, hdrs);
if (clientRespHeaders.containsKey(k)) { } else {
if (k.equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN) || k.equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS) String realUri;
|| k.equals(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS) || k.equals(HttpHeaders.ACCESS_CONTROL_MAX_AGE)) { String backendUrl = ac.getNextBackendUrl();
} else { int acpLen = ac.path.length();
clientRespHeaders.put(k, h.getValue()); if (acpLen == 1) {
} realUri = backendUrl + relativeUri;
} else { } else {
clientRespHeaders.put(k, h.getValue()); realUri = backendUrl + relativeUri.substring(acpLen);
} }
} relativeUri.substring(acpLen);
); return fizzWebClient.send(clientReq.getId(), clientReq.getMethod(), realUri, hdrs, clientReq.getBody()).flatMap(genServerResponse(exchange));
if (log.isDebugEnabled()) { }
StringBuilder b = ThreadContext.getStringBuilder();
WebUtils.response2stringBuilder(rid, remoteResp, b);
log.debug(b.toString(), LogService.BIZ_ID, rid);
}
return clientResp.writeWith(remoteResp.body(BodyExtractors.toDataBuffers()))
.doOnError(throwable -> cleanup(remoteResp)).doOnCancel(() -> cleanup(remoteResp));
}
);
} }
private Mono<Void> send(ServerWebExchange exchange, String service, String relativeUri, HttpHeaders hdrs) {
ServerHttpRequest clientReq = exchange.getRequest();
return fizzWebClient.proxySend2service(clientReq.getId(), clientReq.getMethod(), service, relativeUri, hdrs, clientReq.getBody()).flatMap(genServerResponse(exchange));
}
private Function<ClientResponse, Mono<? extends Void>> genServerResponse(ServerWebExchange exchange) {
return remoteResp -> {
ServerHttpResponse clientResp = exchange.getResponse();
clientResp.setStatusCode(remoteResp.statusCode());
HttpHeaders clientRespHeaders = clientResp.getHeaders();
HttpHeaders remoteRespHeaders = remoteResp.headers().asHttpHeaders();
remoteRespHeaders.entrySet().forEach(
h -> {
String k = h.getKey();
if (clientRespHeaders.containsKey(k)) {
if (k.equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN) || k.equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)
|| k.equals(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS) || k.equals(HttpHeaders.ACCESS_CONTROL_MAX_AGE)) {
} else {
clientRespHeaders.put(k, h.getValue());
}
} else {
clientRespHeaders.put(k, h.getValue());
}
}
);
if (log.isDebugEnabled()) {
StringBuilder b = ThreadContext.getStringBuilder();
String rid = exchange.getRequest().getId();
WebUtils.response2stringBuilder(rid, remoteResp, b);
log.debug(b.toString(), LogService.BIZ_ID, rid);
}
return clientResp.writeWith(remoteResp.body(BodyExtractors.toDataBuffers()))
.doOnError(throwable -> cleanup(remoteResp)).doOnCancel(() -> cleanup(remoteResp));
};
}
private void cleanup(ClientResponse clientResponse) { private void cleanup(ClientResponse clientResponse) {
if (clientResponse != null) { if (clientResponse != null) {
clientResponse.bodyToMono(Void.class).subscribe(); clientResponse.bodyToMono(Void.class).subscribe();

View File

@@ -19,10 +19,12 @@ package we.fizz;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import we.config.AppConfigProperties; import we.config.AppConfigProperties;
import we.fizz.input.ClientInputConfig; import we.fizz.input.ClientInputConfig;
import we.fizz.input.Input; import we.fizz.input.Input;
import we.fizz.input.InputType; import we.fizz.input.InputType;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.noear.snack.ONode; import org.noear.snack.ONode;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@@ -32,6 +34,10 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
import static we.listener.AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE;
import static we.util.Constants.Symbol.FORWARD_SLASH;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
@@ -41,9 +47,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import static we.listener.AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE;
import static we.util.Constants.Symbol.FORWARD_SLASH;
/** /**
* *
* @author francis * @author francis
@@ -56,7 +59,7 @@ public class ConfigLoader {
* 聚合配置存放Hash的Key * 聚合配置存放Hash的Key
*/ */
private static final String AGGREGATE_HASH_KEY = "fizz_aggregate_config"; private static final String AGGREGATE_HASH_KEY = "fizz_aggregate_config";
private static Map<String, String> aggregateResources = null; private static Map<String, String> aggregateResources = null;
private static Map<String, ConfigInfo> resourceKey2ConfigInfoMap = null; private static Map<String, ConfigInfo> resourceKey2ConfigInfoMap = null;
private static Map<String, String> aggregateId2ResourceKeyMap = null; private static Map<String, String> aggregateId2ResourceKeyMap = null;
@@ -80,8 +83,13 @@ public class ConfigLoader {
clientInputConfig.setHeaders(cfgNode.select("$.headers").toObject(Map.class)); clientInputConfig.setHeaders(cfgNode.select("$.headers").toObject(Map.class));
clientInputConfig.setMethod(cfgNode.select("$.method").getString()); clientInputConfig.setMethod(cfgNode.select("$.method").getString());
clientInputConfig.setPath(cfgNode.select("$.path").getString()); clientInputConfig.setPath(cfgNode.select("$.path").getString());
if(cfgNode.select("$.debug") != null) { if(clientInputConfig.getPath().startsWith(TEST_PATH_PREFIX)) {
clientInputConfig.setDebug(cfgNode.select("$.debug").getBoolean()); // always enable debug for testing
clientInputConfig.setDebug(true);
}else {
if(cfgNode.select("$.debug") != null) {
clientInputConfig.setDebug(cfgNode.select("$.debug").getBoolean());
}
} }
clientInputConfig.setType(InputType.valueOf(cfgNode.select("$.type").getString())); clientInputConfig.setType(InputType.valueOf(cfgNode.select("$.type").getString()));
clientInputConfig.setLangDef(cfgNode.select("$.langDef").toObject(Map.class)); clientInputConfig.setLangDef(cfgNode.select("$.langDef").toObject(Map.class));

View File

@@ -25,11 +25,7 @@ import java.util.Map;
import javax.script.ScriptException; import javax.script.ScriptException;
import we.fizz.input.ClientInputConfig;
import we.fizz.input.InputConfig;
import we.schema.util.I18nUtils; import we.schema.util.I18nUtils;
import we.util.JsonSchemaUtils;
import org.noear.snack.ONode; import org.noear.snack.ONode;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -37,14 +33,17 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import we.flume.clients.log4j2appender.LogService;
import we.fizz.input.Input;
import we.fizz.input.PathMapping;
import we.fizz.input.ScriptHelper;
import we.util.MapUtil;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.fizz.input.ClientInputConfig;
import we.fizz.input.Input;
import we.fizz.input.InputConfig;
import we.fizz.input.PathMapping;
import we.fizz.input.ScriptHelper;
import we.flume.clients.log4j2appender.LogService;
import we.util.JsonSchemaUtils;
import we.util.MapUtil;
/** /**
* *

View File

@@ -30,14 +30,14 @@ import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import reactor.core.publisher.Mono;
import we.fizz.input.Input; import we.fizz.input.Input;
import we.fizz.input.InputConfig; import we.fizz.input.InputConfig;
import we.fizz.input.InputContext; import we.fizz.input.InputContext;
import we.fizz.input.InputFactory; import we.fizz.input.InputFactory;
import we.fizz.input.InputType; import we.fizz.input.InputType;
import reactor.core.publisher.Mono;
/** /**
* *
* @author linwaiwai * @author linwaiwai

View File

@@ -19,11 +19,10 @@ package we.fizz.input;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import reactor.core.publisher.Mono;
import we.fizz.StepContext; import we.fizz.StepContext;
import we.fizz.StepResponse; import we.fizz.StepResponse;
import reactor.core.publisher.Mono;
/** /**
* *
* @author linwaiwai * @author linwaiwai

View File

@@ -34,16 +34,16 @@ import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import we.flume.clients.log4j2appender.LogService;
import we.FizzGatewayApplication; import reactor.core.publisher.Mono;
import we.FizzAppContext;
import we.constants.CommonConstants; import we.constants.CommonConstants;
import we.fizz.StepContext; import we.fizz.StepContext;
import we.fizz.StepResponse; import we.fizz.StepResponse;
import we.flume.clients.log4j2appender.LogService;
import we.proxy.FizzWebClient; import we.proxy.FizzWebClient;
import we.util.MapUtil; import we.util.MapUtil;
import reactor.core.publisher.Mono;
/** /**
* *
* @author linwaiwai * @author linwaiwai
@@ -222,7 +222,7 @@ public class RequestInput extends Input {
String aggrPath = (String)inputContext.getStepContext().getInputReqAttr("path"); String aggrPath = (String)inputContext.getStepContext().getInputReqAttr("path");
String aggrService = aggrPath.split("\\/")[2]; String aggrService = aggrPath.split("\\/")[2];
FizzWebClient client = FizzGatewayApplication.appContext.getBean(FizzWebClient.class); FizzWebClient client = FizzAppContext.appContext.getBean(FizzWebClient.class);
return client.aggrSend(aggrService, aggrMethod, aggrPath, null, method, url, return client.aggrSend(aggrService, aggrMethod, aggrPath, null, method, url,
MapUtil.toHttpHeaders(headers), request.get("body"), (long)timeout); MapUtil.toHttpHeaders(headers), request.get("body"), (long)timeout);
} }

View File

@@ -30,6 +30,7 @@ import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.ctrip.framework.apollo.core.utils.StringUtils; import com.ctrip.framework.apollo.core.utils.StringUtils;
import we.constants.CommonConstants; import we.constants.CommonConstants;
import we.exception.StopAndResponseException; import we.exception.StopAndResponseException;
import we.fizz.StepContext; import we.fizz.StepContext;

View File

@@ -1,33 +1,31 @@
/*
* 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.flume.clients.log4j2appender; package we.flume.clients.log4j2appender;
/**
* @author lancer
*/
public enum LogService { public enum LogService {
BIZ_ID, HANDLE_STGY; BIZ_ID, HANDLE_STGY, APP;
public static void cleanBizId() {
setBizId(null);
}
public static Object getBizId() {
return ThreadContext.get(Constants.BIZ_ID);
}
public static void setBizId(Object bizId) { public static void setBizId(Object bizId) {
ThreadContext.set(Constants.BIZ_ID, bizId);
} }
public static String toKF(String topic) { public static String toKF(String topic) {
return topic; return topic;
} }
public static String toESaKF(String topic) {
return Constants.AND + topic;
}
public static class Constants {
static final String BIZ_ID = "bizId";
static final char AND = '&';
}
} }

View File

@@ -0,0 +1,76 @@
package we.flume.clients.log4j2appender;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
/** for internal use */
public abstract class ThreadContext {
private static ThreadLocal<Map<String, Object>> tl = new ThreadLocal<>();
private static final int mapCap = 16;
private static final float mapLoadFactor = 1.0f;
private static final String sb = "sb";
private static final int sbCap = 256;
public static StringBuilder getStringBuilder() {
return getStringBuilder(true);
}
public static StringBuilder getStringBuilder(boolean clean) {
Map<String, Object> m = getMap();
StringBuilder b = (StringBuilder) m.get(sb);
if (b == null) {
b = new StringBuilder(sbCap);
m.put(sb, b);
} else {
if (clean) {
b.delete(0, b.length());
}
}
return b;
}
public static SimpleDateFormat getSimpleDateFormat(String pattern) {
Map<String, Object> m = getMap();
SimpleDateFormat sdf = (SimpleDateFormat) m.get(pattern);
if (sdf == null) {
sdf = new SimpleDateFormat(pattern);
m.put(pattern, sdf);
}
return sdf;
}
public static Object get(String key, Class<?> clz) {
Object obj = get(key);
if (obj == null) {
try {
obj = clz.newInstance();
set(key, obj);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
return obj;
}
private static Map<String, Object> getMap() {
Map<String, Object> m = tl.get();
if (m == null) {
m = new HashMap<>(mapCap, mapLoadFactor);
tl.set(m);
}
return m;
}
public static Object get(String key) {
return getMap().get(key);
}
public static void set(String key, Object obj) {
getMap().put(key, obj);
}
}

View File

@@ -17,13 +17,15 @@
package we.legacy; package we.legacy;
import we.util.Constants;
import we.util.ThreadContext;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import we.util.Constants;
import we.util.ThreadContext;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public class RespEntity { public class RespEntity {
private static final String f0 = "{\"msgCode\":"; private static final String f0 = "{\"msgCode\":";

View File

@@ -19,7 +19,7 @@ package we.listener;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.TypeReference;
import we.fizz.ConfigLoader;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
@@ -31,14 +31,16 @@ import org.springframework.util.StringUtils;
import reactor.core.Disposable; import reactor.core.Disposable;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers; import reactor.core.scheduler.Schedulers;
import we.fizz.ConfigLoader;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import java.net.InetAddress;
import java.util.List;
import static we.listener.AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_MESSAGE_LISTENER_CONTAINER; import static we.listener.AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_MESSAGE_LISTENER_CONTAINER;
import java.net.InetAddress;
import java.util.List;
/** /**
* 聚合Channel监听器 * 聚合Channel监听器
* @author zhongjie * @author zhongjie

View File

@@ -17,8 +17,6 @@
package we.listener; package we.listener;
import we.config.RedisReactiveConfig;
import we.config.RedisReactiveProperties;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@@ -27,6 +25,9 @@ import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate; import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.data.redis.listener.ReactiveRedisMessageListenerContainer; import org.springframework.data.redis.listener.ReactiveRedisMessageListenerContainer;
import we.config.RedisReactiveConfig;
import we.config.RedisReactiveProperties;
/** /**
* 聚合配置Redis配置 * 聚合配置Redis配置
* @author zhongjie * @author zhongjie

View File

@@ -14,16 +14,19 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.plugin; package we.plugin;
import we.FizzGatewayApplication;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import we.FizzAppContext;
import we.util.ThreadContext;
import java.util.*; import java.util.*;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public abstract class FixedPluginFilter extends PluginFilter { public abstract class FixedPluginFilter extends PluginFilter {
@@ -56,7 +59,7 @@ public abstract class FixedPluginFilter extends PluginFilter {
); );
String fid = pf.getId(); String fid = pf.getId();
fixedPluginFilterMap.put(fid, pf); fixedPluginFilterMap.put(fid, pf);
StringBuilder b = new StringBuilder(256); StringBuilder b = ThreadContext.getStringBuilder();
b.append("add ").append(fid).append('\n'); b.append("add ").append(fid).append('\n');
b.append("fixed plugin filters: \n"); b.append("fixed plugin filters: \n");
filters2sb(b); filters2sb(b);
@@ -67,7 +70,7 @@ public abstract class FixedPluginFilter extends PluginFilter {
if (fixedPluginFilterList == null) { if (fixedPluginFilterList == null) {
synchronized (fixedPluginFilterMap) { synchronized (fixedPluginFilterMap) {
if (fixedPluginFilterList == null) { if (fixedPluginFilterList == null) {
Map<String, FixedPluginFilter> beansOfType = FizzGatewayApplication.appContext.getBeansOfType(FixedPluginFilter.class); Map<String, FixedPluginFilter> beansOfType = FizzAppContext.appContext.getBeansOfType(FixedPluginFilter.class);
if (beansOfType == null || beansOfType.isEmpty()) { if (beansOfType == null || beansOfType.isEmpty()) {
fixedPluginFilterList = Collections.EMPTY_LIST; fixedPluginFilterList = Collections.EMPTY_LIST;
} else { } else {
@@ -82,7 +85,7 @@ public abstract class FixedPluginFilter extends PluginFilter {
fixedPluginFilterMap.put(f.getId(), f); fixedPluginFilterMap.put(f.getId(), f);
} }
); );
StringBuilder b = new StringBuilder(256); StringBuilder b = ThreadContext.getStringBuilder();
b.append("fixed plugin filters: \n"); b.append("fixed plugin filters: \n");
filters2sb(b); filters2sb(b);
log.info(b.toString()); log.info(b.toString());

View File

@@ -14,17 +14,17 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.plugin; package we.plugin;
import com.fasterxml.jackson.core.JsonProcessingException;
import we.util.JacksonUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import we.util.JacksonUtils;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public class PluginConfig { public class PluginConfig {

View File

@@ -14,23 +14,24 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.plugin; package we.plugin;
import we.flume.clients.log4j2appender.LogService;
import we.filter.FilterResult;
import we.legacy.RespEntity;
import we.util.WebUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.filter.FilterResult;
import we.flume.clients.log4j2appender.LogService;
import we.legacy.RespEntity;
import we.util.WebUtils;
import java.util.Map; import java.util.Map;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public abstract class PluginFilter { public abstract class PluginFilter {

View File

@@ -14,66 +14,90 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.plugin.auth; package we.plugin.auth;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import we.plugin.PluginConfig; import we.plugin.PluginConfig;
import we.util.Constants; import we.util.Constants;
import we.util.JacksonUtils; import we.util.JacksonUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import java.util.List; import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public class ApiConfig { public class ApiConfig {
public static final int DELETED = 1; public static final int DELETED = 1;
public static final char ALLOW = 'a'; public static final char ALLOW = 'a';
public static final char FORBID = 'f'; public static final char FORBID = 'f';
public int id; // tb_api_auth.id public static final byte DIRECT_PROXY_MODE = 1;
public int isDeleted = 0; // tb_api_auth.is_deleted public static final byte PREFIX_REWRITE_PROXY_MODE = 2;
public char gatewayGroup; // tb_api_auth.gateway_group @JsonIgnore
public int id; // tb_api_auth.id
@JsonIgnore
public int isDeleted = 0; // tb_api_auth.is_deleted
public Set<String> gatewayGroups = new HashSet<>(6);
public String service; public String service;
public HttpMethod method = HttpMethod.X; public HttpMethod method = HttpMethod.X;
public String path = String.valueOf(Constants.Symbol.FORWARD_SLASH); public String path = String.valueOf(Constants.Symbol.FORWARD_SLASH);
private String app; public Set<String> apps = new HashSet<>(6);
public char access = ALLOW; public byte proxyMode = DIRECT_PROXY_MODE;
private AtomicInteger counter = new AtomicInteger(-1);
public List<String> backendUrls;
public char access = ALLOW;
public List<PluginConfig> pluginConfigs; public List<PluginConfig> pluginConfigs;
public void setApp(String a) { public void setGatewayGroup(String ggs) {
app = a; if (StringUtils.isBlank(ggs)) {
gatewayGroups.add("*");
} else {
Arrays.stream(StringUtils.split(ggs, ',')).forEach(
gg -> {
gatewayGroups.add(gg.trim());
}
);
}
} }
public String app() { public void setApp(String as) {
if (StringUtils.isBlank(app)) { if (StringUtils.isBlank(as)) {
if (gatewayGroup == GatewayGroup.C) { apps.add("*");
app = App.TO_C; } else {
} else if (gatewayGroup == GatewayGroup.B) { Arrays.stream(StringUtils.split(as, ',')).forEach(
app = App.TO_B; a -> {
} else { apps.add(a.trim());
throw new RuntimeException(toString() + " no app", null, false, false) {}; }
} );
} }
return app;
} }
public void setPath(String p) { public void setPath(String p) {
if (StringUtils.isNotBlank(p)) { if (StringUtils.isNotBlank(p)) {
path = p; path = p.trim();
} }
} }
@@ -84,6 +108,16 @@ public class ApiConfig {
} }
} }
@JsonIgnore
public String getNextBackendUrl() {
int idx = counter.incrementAndGet();
if (idx < 0) {
counter.set(0);
idx = 0;
}
return backendUrls.get(idx % backendUrls.size());
}
@Override @Override
public String toString() { public String toString() {
return JacksonUtils.writeValueAsString(this); return JacksonUtils.writeValueAsString(this);

View File

@@ -14,15 +14,12 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.plugin.auth; package we.plugin.auth;
import com.ctrip.framework.apollo.model.ConfigChange; import com.ctrip.framework.apollo.model.ConfigChange;
import com.ctrip.framework.apollo.model.ConfigChangeEvent; import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import we.flume.clients.log4j2appender.LogService;
import we.config.SystemConfig;
import we.listener.AggregateRedisConfig;
import we.util.*;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -36,6 +33,9 @@ import org.springframework.stereotype.Service;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.flume.clients.log4j2appender.LogService;
import we.listener.AggregateRedisConfig;
import we.util.*;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
@@ -43,7 +43,7 @@ import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* @author lancer * @author hongqiaowei
*/ */
@Service @Service
@@ -61,9 +61,9 @@ public class ApiConfigService {
private static final String secretKeyHeader = "fizz-secretkey"; private static final String secretKeyHeader = "fizz-secretkey";
private Map<String, GatewayGroup> app2gatewayGroupMap = new HashMap<>(32); public Map<String, ServiceConfig> serviceConfigMap = new HashMap<>(128);
private Map<Integer, ApiConfig> apiConfigMap = new HashMap<>(128); private Map<Integer, ApiConfig> apiConfigMap = new HashMap<>(128);
// TODO XXX // TODO XXX
@Value("${serviceWhiteList:x}") @Value("${serviceWhiteList:x}")
@@ -94,14 +94,17 @@ public class ApiConfigService {
} }
} }
@Value("${auth.compatible-wh:false}")
private boolean compatibleWh;
@Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE) @Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
private ReactiveStringRedisTemplate rt; private ReactiveStringRedisTemplate rt;
@Resource @Resource
private SystemConfig systemConfig; private AppService appService;
@Resource @Resource
private AppService appService; private GatewayGroupService gatewayGroupService;
@Autowired(required = false) @Autowired(required = false)
private CustomAuth customAuth; private CustomAuth customAuth;
@@ -127,7 +130,7 @@ public class ApiConfigService {
try { try {
ApiConfig ac = JacksonUtils.readValue(json, ApiConfig.class); ApiConfig ac = JacksonUtils.readValue(json, ApiConfig.class);
apiConfigMap.put(ac.id, ac); apiConfigMap.put(ac.id, ac);
updateApp2gatewayGroupMap(ac); updateServiceConfigMap(ac);
return Flux.just(e); return Flux.just(e);
} catch (Throwable t) { } catch (Throwable t) {
throwable[0] = t; throwable[0] = t;
@@ -167,9 +170,9 @@ public class ApiConfigService {
ApiConfig r = apiConfigMap.remove(ac.id); ApiConfig r = apiConfigMap.remove(ac.id);
if (ac.isDeleted != ApiConfig.DELETED && r != null) { if (ac.isDeleted != ApiConfig.DELETED && r != null) {
r.isDeleted = ApiConfig.DELETED; r.isDeleted = ApiConfig.DELETED;
updateApp2gatewayGroupMap(r); updateServiceConfigMap(r);
} }
updateApp2gatewayGroupMap(ac); updateServiceConfigMap(ac);
if (ac.isDeleted != ApiConfig.DELETED) { if (ac.isDeleted != ApiConfig.DELETED) {
apiConfigMap.put(ac.id, ac); apiConfigMap.put(ac.id, ac);
} }
@@ -192,24 +195,21 @@ public class ApiConfigService {
return Mono.just(ReactorUtils.EMPTY_THROWABLE); return Mono.just(ReactorUtils.EMPTY_THROWABLE);
} }
private void updateApp2gatewayGroupMap(ApiConfig ac) { private void updateServiceConfigMap(ApiConfig ac) {
GatewayGroup gg = app2gatewayGroupMap.get(ac.app()); ServiceConfig sc = serviceConfigMap.get(ac.service);
if (ac.isDeleted == ApiConfig.DELETED) { if (ac.isDeleted == ApiConfig.DELETED) {
if (gg == null) { if (sc == null) {
log.info("no gateway group for " + ac.app()); log.info("no " + ac.service + " config to delete");
} else { } else {
gg.remove(ac); sc.remove(ac);
if (gg.getServiceConfigMap().isEmpty()) {
app2gatewayGroupMap.remove(ac.app());
}
} }
} else { } else {
if (gg == null) { if (sc == null) {
gg = new GatewayGroup(ac.gatewayGroup); sc = new ServiceConfig(ac.service);
app2gatewayGroupMap.put(ac.app(), gg); serviceConfigMap.put(ac.service, sc);
gg.add(ac); sc.add(ac);
} else { } else {
gg.update(ac); sc.update(ac);
} }
} }
} }
@@ -218,13 +218,15 @@ public class ApiConfigService {
YES (null), YES (null),
CANT_ACCESS_CURRENT_GATEWAY_GROUP ("cant access current gateway group"), NO_SERVICE_CONFIG ("no service config"),
NO_GATEWAY_GROUP_FOR_APP ("no gateway group for app"), NO_API_CONFIG ("no api config"),
NO_APP_CONFIG_FOR_APP ("no app config for app"), GATEWAY_GROUP_CANT_PROXY_API ("gateway group cant proxy api"),
ORIGIN_IP_NOT_IN_WHITE_LIST ("origin ip not in white list"), APP_NOT_IN_API_LEGAL_APPS ("app not in api legal apps"),
IP_NOT_IN_WHITE_LIST ("ip not in white list"),
NO_TIMESTAMP_OR_SIGN ("no timestamp or sign"), NO_TIMESTAMP_OR_SIGN ("no timestamp or sign"),
@@ -236,10 +238,6 @@ public class ApiConfigService {
SERVICE_NOT_OPEN ("service not open"), SERVICE_NOT_OPEN ("service not open"),
NO_SERVICE_EXPOSE_TO_APP ("no service expose to app"),
SERVICE_API_NOT_EXPOSE_TO_APP ("service api not expose to app"),
CANT_ACCESS_SERVICE_API ("cant access service api"); CANT_ACCESS_SERVICE_API ("cant access service api");
private String reason; private String reason;
@@ -254,7 +252,6 @@ public class ApiConfigService {
} }
public Mono<Object> canAccess(ServerWebExchange exchange) { public Mono<Object> canAccess(ServerWebExchange exchange) {
ServerHttpRequest req = exchange.getRequest(); ServerHttpRequest req = exchange.getRequest();
HttpHeaders hdrs = req.getHeaders(); HttpHeaders hdrs = req.getHeaders();
LogService.setBizId(req.getId()); LogService.setBizId(req.getId());
@@ -262,56 +259,83 @@ public class ApiConfigService {
WebUtils.getServiceId(exchange), req.getMethod(), WebUtils.getReqPath(exchange)); WebUtils.getServiceId(exchange), req.getMethod(), WebUtils.getReqPath(exchange));
} }
private Mono<Object> canAccess(ServerWebExchange exchange, String app, String ip, String timestamp, String sign, String secretKey, private Mono<Object> canAccess(ServerWebExchange exchange, String app, String ip, String timestamp, String sign, String secretKey,
String service, HttpMethod method, String path) { String service, HttpMethod method, String path) {
GatewayGroup gg = app2gatewayGroupMap.get(app); boolean toCorBapp = App.TO_C.equals(app) || App.TO_B.equals(app); if (!whiteListSet.contains(service)) { // TODO XXX
return Mono.just(Access.SERVICE_NOT_OPEN);
if (gg == null) { }
if (toCorBapp) { return Mono.just(Access.YES); } else { return logWarnAndResult("no gateway group for " + app, Access.NO_GATEWAY_GROUP_FOR_APP); } ServiceConfig sc = serviceConfigMap.get(service);
if (sc == null) {
if (compatibleWh) {
return Mono.just(Access.YES);
} else {
return logWarnAndResult(service + Constants.Symbol.BLANK + Access.NO_SERVICE_CONFIG.getReason(), Access.NO_SERVICE_CONFIG);
}
} else { } else {
Set<Character> currentServerGatewayGroupSet = systemConfig.getCurrentServerGatewayGroupSet(); String api = ThreadContext.getStringBuilder().append(service).append(Constants.Symbol.BLANK).append(method.name()).append(Constants.Symbol.BLANK + path).toString();
if (currentServerGatewayGroupSet.contains(gg.id)) { ApiConfig ac0 = null;
Mono<Access> am = Mono.just(Access.YES); for (String g : gatewayGroupService.currentGatewayGroupSet) { // compatible
App a = appService.getApp(app); ac0 = sc.getApiConfig(method, path, g, app);
if (a == null) { if (ac0 != null) {
if (!toCorBapp) { return logWarnAndResult("no app config for " + app, Access.NO_APP_CONFIG_FOR_APP); } break;
} else if (a.useWhiteList && !a.ips.contains(ip)) {
return logWarnAndResult(ip + " not in " + app + " white list", Access.ORIGIN_IP_NOT_IN_WHITE_LIST);
} else if (a.useAuth) {
if (a.authType == App.SIGN_AUTH) {
if (StringUtils.isBlank(timestamp) || StringUtils.isBlank(sign)) { return logWarnAndResult(app + " lack timestamp " + timestamp + " or sign " + sign, Access.NO_TIMESTAMP_OR_SIGN); }
else if (!validate(app, timestamp, a.secretkey, sign)) { return logWarnAndResult(app + " sign " + sign + " invalid", Access.SIGN_INVALID); }
} else if (customAuth == null) {
return logWarnAndResult(app + " no custom auth", Access.NO_CUSTOM_AUTH);
} else {
am = customAuth.auth(exchange, app, ip, timestamp, sign, secretKey, a);
}
}
return am.flatMap(
v -> {
LogService.setBizId(exchange.getRequest().getId());
if (v == Access.CUSTOM_AUTH_REJECT || v != Access.YES) { return Mono.just(Access.CUSTOM_AUTH_REJECT); }
if (!whiteListSet.contains(service)) { return Mono.just(Access.SERVICE_NOT_OPEN); } // TODO XXX
ServiceConfig sc = gg.getServiceConfig(service);
if (sc == null) {
if (toCorBapp) { return Mono.just(Access.YES); } else { return logWarnAndResult("no service expose to " + app, Access.NO_SERVICE_EXPOSE_TO_APP); }
} else {
ApiConfig ac = sc.getApiConfig(method, path);
if (ac == null) {
if (toCorBapp) { return Mono.just(Access.YES); } else { return logWarnAndResult(service + ' ' + method.name() + ' ' + path + " not expose to " + app, Access.SERVICE_API_NOT_EXPOSE_TO_APP); }
} else if (ac.access == ApiConfig.ALLOW) {
return Mono.just(ac);
} else {
return logWarnAndResult(app + " cant access " + service + ' ' + method.name() + ' ' + path, Access.CANT_ACCESS_SERVICE_API);
}
}
}
);
} else {
return logWarnAndResult(app + " cant access " + currentServerGatewayGroupSet, Access.CANT_ACCESS_CURRENT_GATEWAY_GROUP);
} }
}
ApiConfig ac = ac0;
if (ac == null) {
if (compatibleWh) {
return Mono.just(Access.YES);
} else {
return logWarnAndResult(api + " no api config", Access.NO_API_CONFIG);
}
} else if (gatewayGroupService.currentGatewayGroupIn(ac.gatewayGroups)) {
if (ac.apps.contains(App.ALL_APP)) {
return allow(api, ac);
} else if (app != null && ac.apps.contains(app)) {
if (ac.access == ApiConfig.ALLOW) {
App a = appService.getApp(app);
if (a.useWhiteList && !a.allow(ip)) {
return logWarnAndResult(ip + " not in " + app + " white list", Access.IP_NOT_IN_WHITE_LIST);
} else if (a.useAuth) {
if (a.authType == App.SIGN_AUTH) {
if (StringUtils.isBlank(timestamp) || StringUtils.isBlank(sign)) {
return logWarnAndResult(app + " lack timestamp " + timestamp + " or sign " + sign, Access.NO_TIMESTAMP_OR_SIGN);
} else if (!validate(app, timestamp, a.secretkey, sign)) {
return logWarnAndResult(app + " sign " + sign + " invalid", Access.SIGN_INVALID);
} else {
return Mono.just(ac);
}
} else if (customAuth == null) {
return logWarnAndResult(app + " no custom auth", Access.NO_CUSTOM_AUTH);
} else {
return customAuth.auth(exchange, app, ip, timestamp, sign, secretKey, a).flatMap(v -> {
if (v == Access.YES) {
return Mono.just(ac);
} else {
return Mono.just(Access.CUSTOM_AUTH_REJECT);
}
});
}
} else {
return Mono.just(ac);
}
} else {
return logWarnAndResult("cant access " + api, Access.CANT_ACCESS_SERVICE_API);
}
} else {
return logWarnAndResult(app + " not in " + api + " legal apps", Access.APP_NOT_IN_API_LEGAL_APPS);
}
} else {
return logWarnAndResult(gatewayGroupService.currentGatewayGroupSet + " cant proxy " + api, Access.GATEWAY_GROUP_CANT_PROXY_API);
}
}
}
private static Mono<Object> allow(String api, ApiConfig ac) {
if (ac.access == ApiConfig.ALLOW) {
return Mono.just(ac);
} else {
return logWarnAndResult("cant access " + api, Access.CANT_ACCESS_SERVICE_API);
} }
} }
@@ -321,12 +345,8 @@ public class ApiConfigService {
} }
private static boolean validate(String app, String timestamp, String secretKey, String sign) { private static boolean validate(String app, String timestamp, String secretKey, String sign) {
StringBuilder b = new StringBuilder(128); StringBuilder b = ThreadContext.getStringBuilder();
b.append(app).append(Constants.Symbol.UNDERLINE).append(timestamp).append(Constants.Symbol.UNDERLINE).append(secretKey); b.append(app).append(Constants.Symbol.UNDERLINE).append(timestamp).append(Constants.Symbol.UNDERLINE).append(secretKey);
return sign.equals(DigestUtils.md532(b.toString())); return sign.equals(DigestUtils.md532(b.toString()));
} }
public Map<String, GatewayGroup> getApp2gatewayGroupMap() {
return app2gatewayGroupMap;
}
} }

View File

@@ -14,25 +14,24 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.plugin.auth; package we.plugin.auth;
import we.util.JacksonUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Arrays; import we.util.Constants;
import java.util.Collections; import we.util.JacksonUtils;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public class App { public class App {
public static final String TO_C = "2c"; public static final String ALL_APP = "*";
public static final String TO_B = "2b";
public static final int DELETED = 1; public static final int DELETED = 1;
@@ -56,7 +55,9 @@ public class App {
public boolean useWhiteList = false; public boolean useWhiteList = false;
public Set<String> ips = Collections.emptySet(); public String config;
private Map<String, String[]> ips = new HashMap<>(6);
public void setUseAuth(int i) { public void setUseAuth(int i) {
if (i == 1) { if (i == 1) {
@@ -72,10 +73,69 @@ public class App {
public void setIps(String ips) { public void setIps(String ips) {
if (StringUtils.isNotBlank(ips)) { if (StringUtils.isNotBlank(ips)) {
this.ips = Arrays.stream(StringUtils.split(ips, ',')).collect(Collectors.toSet()); Arrays.stream(StringUtils.split(ips, ',')).forEach(
ip -> {
ip = ip.trim();
int i = ip.lastIndexOf('.');
String subnet = ip.substring(0, i).trim();
String addrSeg = ip.substring(i + 1).trim();
if ("*".equals(addrSeg)) {
this.ips.put(subnet, new String[]{"2", "254"});
} else if (addrSeg.indexOf('-') > 0) {
String[] a = StringUtils.split(addrSeg, '-');
String beg = a[0].trim();
String end = a[1].trim();
this.ips.put(subnet, new String[]{beg, end});
} else {
this.ips.put(subnet, new String[]{addrSeg, addrSeg});
}
}
);
} }
} }
public boolean allow(String ip) {
int originSubnetLen = ip.lastIndexOf(Constants.Symbol.DOT);
for (Map.Entry<String, String[]> e : ips.entrySet()) {
String subnet = e.getKey();
int subnetLen = subnet.length();
byte i = 0;
if (subnetLen == originSubnetLen) {
for (; i < subnetLen; i++) {
if (subnet.charAt(i) != ip.charAt(i)) {
break;
}
}
if (i == subnetLen) {
int originAddrLen = ip.length() - originSubnetLen - 1;
String[] addrSeg = e.getValue();
String addrSegBeg = addrSeg[0];
String addrSegEnd = addrSeg[1];
if (originAddrLen < addrSegBeg.length() || addrSegEnd.length() < originAddrLen) {
return false;
} else {
if (originAddrLen == addrSegBeg.length()) {
for (byte j = 0; j < addrSegBeg.length(); j++) {
if (ip.charAt(originSubnetLen + 1 + j) < addrSegBeg.charAt(j)) {
return false;
}
}
}
if (originAddrLen == addrSegEnd.length()) {
for (byte j = 0; j < addrSegEnd.length(); j++) {
if (addrSegEnd.charAt(j) < ip.charAt(originSubnetLen + 1 + j)) {
return false;
}
}
}
return true;
}
}
}
}
return false;
}
@Override @Override
public String toString() { public String toString() {
return JacksonUtils.writeValueAsString(this); return JacksonUtils.writeValueAsString(this);

View File

@@ -14,19 +14,20 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.plugin.auth; package we.plugin.auth;
import we.flume.clients.log4j2appender.LogService;
import we.listener.AggregateRedisConfig;
import we.util.Constants;
import we.util.JacksonUtils;
import we.util.ReactorUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate; import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.flume.clients.log4j2appender.LogService;
import we.listener.AggregateRedisConfig;
import we.util.Constants;
import we.util.JacksonUtils;
import we.util.ReactorUtils;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
@@ -37,7 +38,7 @@ import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* @author lancer * @author hongqiaowei
*/ */
@Service @Service

View File

@@ -14,23 +14,24 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.plugin.auth; package we.plugin.auth;
import we.flume.clients.log4j2appender.LogService;
import we.plugin.PluginFilter;
import we.util.WebUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.flume.clients.log4j2appender.LogService;
import we.plugin.PluginFilter;
import we.util.WebUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.HashMap; import java.util.Collections;
import java.util.Map; import java.util.Map;
/** /**
* @author lancer * @author hongqiaowei
*/ */
@Component(AuthPluginFilter.AUTH_PLUGIN_FILTER) @Component(AuthPluginFilter.AUTH_PLUGIN_FILTER)
@@ -52,8 +53,7 @@ public class AuthPluginFilter extends PluginFilter {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("req auth: " + r, LogService.BIZ_ID, exchange.getRequest().getId()); log.debug("req auth: " + r, LogService.BIZ_ID, exchange.getRequest().getId());
} }
Map<String, Object> data = new HashMap<>(1, 1.0f); Map<String, Object> data = Collections.singletonMap(RESULT, r);
data.put(RESULT, r);
return WebUtils.transmitSuccessFilterResultAndEmptyMono(exchange, AUTH_PLUGIN_FILTER, data); return WebUtils.transmitSuccessFilterResultAndEmptyMono(exchange, AUTH_PLUGIN_FILTER, data);
} }
); );

View File

@@ -14,13 +14,14 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.plugin.auth; package we.plugin.auth;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public interface CustomAuth { public interface CustomAuth {

View File

@@ -14,70 +14,52 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.plugin.auth; package we.plugin.auth;
import com.fasterxml.jackson.annotation.JsonIgnore; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import we.util.JacksonUtils;
import java.util.HashMap; import java.util.Arrays;
import java.util.Map; import java.util.HashSet;
import java.util.Set;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public class GatewayGroup { public class GatewayGroup {
private static final Logger log = LoggerFactory.getLogger(GatewayGroup.class); private static final Logger log = LoggerFactory.getLogger(GatewayGroup.class);
public static final char C = 'c'; public static final String DEFAULT = "default";
public static final char B = 'b'; public static final int DELETED = 1;
public static final char T = 't'; public int id;
public char id; public int isDeleted = 0;
private Map<String, ServiceConfig> serviceConfigMap = new HashMap<>(128); public String group;
public GatewayGroup(char id) { public String name;
this.id = id;
}
public Map<String, ServiceConfig> getServiceConfigMap() { public Set<String> gateways = new HashSet<>();
return serviceConfigMap;
}
@JsonIgnore public void setGateways(String gateways) {
public ServiceConfig getServiceConfig(String id) { if (StringUtils.isNotBlank(gateways)) {
return serviceConfigMap.get(id); Arrays.stream(StringUtils.split(gateways, ',')).forEach(
} ip -> {
this.gateways.add(ip.trim());
public void remove(ApiConfig ac) { }
ServiceConfig sc = serviceConfigMap.get(ac.service); );
if (sc == null) {
log.info("no service config for " + ac);
} else {
sc.remove(ac);
if (sc.apiConfigMap().isEmpty()) {
serviceConfigMap.remove(ac.service);
}
} }
} }
public void add(ApiConfig ac) { @Override
ServiceConfig sc = new ServiceConfig(ac.service); public String toString() {
serviceConfigMap.put(ac.service, sc); return JacksonUtils.writeValueAsString(this);
sc.add(ac);
}
public void update(ApiConfig ac) {
ServiceConfig sc = serviceConfigMap.get(ac.service);
if (sc == null) {
add(ac);
} else {
sc.update(ac);
}
} }
} }

View File

@@ -0,0 +1,97 @@
/*
* 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.plugin.auth;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import we.util.JacksonUtils;
import java.util.HashMap;
import java.util.Map;
/**
* @author hongqiaowei
*/
public class GatewayGroup2appsToApiConfig {
private static final Logger log = LoggerFactory.getLogger(GatewayGroup2appsToApiConfig.class);
private Map<String/*gg*/, Map<String/*a*/, ApiConfig>> configMap = new HashMap<>(6);
public Map<String, Map<String, ApiConfig>> getConfigMap() {
return configMap;
}
public void setConfigMap(Map<String, Map<String, ApiConfig>> configMap) {
this.configMap = configMap;
}
public void add(ApiConfig ac) {
for (String gg : ac.gatewayGroups) {
Map<String, ApiConfig> app2apiConfigMap = configMap.get(gg);
if (app2apiConfigMap == null) {
app2apiConfigMap = new HashMap<>();
configMap.put(gg, app2apiConfigMap);
}
for (String a : ac.apps) {
app2apiConfigMap.put(a, ac);
log.info(gg + " add " + a + " -> " + ac);
}
}
}
public void remove(ApiConfig ac) {
for (String gg : ac.gatewayGroups) {
Map<String, ApiConfig> app2apiConfigMap = configMap.get(gg);
if (app2apiConfigMap != null) {
for (String a : ac.apps) {
ApiConfig r = app2apiConfigMap.remove(a);
log.info(gg + " remove " + a + " -> " + r);
}
}
}
}
public void update(ApiConfig ac) {
for (String gg : ac.gatewayGroups) {
Map<String, ApiConfig> app2apiConfigMap = configMap.get(gg);
if (app2apiConfigMap == null) {
app2apiConfigMap = new HashMap<>();
configMap.put(gg, app2apiConfigMap);
}
for (String a : ac.apps) {
ApiConfig old = app2apiConfigMap.put(a, ac);
log.info(gg + " update " + a + " -> " + old + " with " + ac);
}
}
}
public ApiConfig get(String gatewayGroup, String app) {
Map<String, ApiConfig> app2apiConfigMap = configMap.get(gatewayGroup);
if (app2apiConfigMap == null) {
return null;
} else {
return app2apiConfigMap.get(app);
}
}
public String toString() {
return JacksonUtils.writeValueAsString(this);
}
}

View File

@@ -0,0 +1,181 @@
/*
* 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.plugin.auth;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.listener.AggregateRedisConfig;
import we.util.Constants;
import we.util.JacksonUtils;
import we.util.NetworkUtils;
import we.util.ReactorUtils;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* @author hongqiaowei
*/
@Service
public class GatewayGroupService {
private static final Logger log = LoggerFactory.getLogger(GatewayGroupService.class);
private static final String fizzGatewayGroup = "fizz_gateway_group";
private static final String fizzGatewayGroupChannel = "fizz_gateway_group_channel";
public Map<String, GatewayGroup> gatewayGroupMap = new HashMap<>(6);
private Map<Integer, GatewayGroup> oldGatewayGroupMap = new HashMap<>(6);
public Set<String> currentGatewayGroupSet = new HashSet<>(6);
@Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
private ReactiveStringRedisTemplate rt;
@PostConstruct
public void init() throws Throwable {
final Throwable[] throwable = new Throwable[1];
Throwable error = Mono.just(Objects.requireNonNull(rt.opsForHash().entries(fizzGatewayGroup)
.defaultIfEmpty(new AbstractMap.SimpleEntry<>(ReactorUtils.OBJ, ReactorUtils.OBJ)).onErrorStop().doOnError(t -> {
log.info(null, t);
})
.concatMap(e -> {
Object k = e.getKey();
if (k == ReactorUtils.OBJ) {
return Flux.just(e);
}
Object v = e.getValue();
log.info(k.toString() + Constants.Symbol.COLON + v.toString(), LogService.BIZ_ID, k.toString());
String json = (String) v;
try {
GatewayGroup gg = JacksonUtils.readValue(json, GatewayGroup.class);
oldGatewayGroupMap.put(gg.id, gg);
updateGatewayGroupMap(gg);
return Flux.just(e);
} catch (Throwable t) {
throwable[0] = t;
log.info(json, t);
return Flux.error(t);
}
}).blockLast())).flatMap(
e -> {
if (throwable[0] != null) {
return Mono.error(throwable[0]);
}
return lsnGatewayGroupChange();
}
).block();
if (error != ReactorUtils.EMPTY_THROWABLE) {
throw error;
}
}
private Mono<Throwable> lsnGatewayGroupChange() {
final Throwable[] throwable = new Throwable[1];
final boolean[] b = {false};
rt.listenToChannel(fizzGatewayGroupChannel).doOnError(t -> {
throwable[0] = t;
b[0] = false;
log.error("lsn " + fizzGatewayGroupChannel, t);
}).doOnSubscribe(
s -> {
b[0] = true;
log.info("success to lsn on " + fizzGatewayGroupChannel);
}
).doOnNext(msg -> {
String json = msg.getMessage();
log.info(json, LogService.BIZ_ID, "gg" + System.currentTimeMillis());
try {
GatewayGroup gg = JacksonUtils.readValue(json, GatewayGroup.class);
GatewayGroup r = oldGatewayGroupMap.remove(gg.id);
if (gg.isDeleted != GatewayGroup.DELETED && r != null) {
gatewayGroupMap.remove(r.group);
}
updateGatewayGroupMap(gg);
if (gg.isDeleted != GatewayGroup.DELETED) {
oldGatewayGroupMap.put(gg.id, gg);
}
} catch (Throwable t) {
log.info(json, t);
}
}).subscribe();
Throwable t = throwable[0];
while (!b[0]) {
if (t != null) {
return Mono.error(t);
} else {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
return Mono.error(e);
}
}
}
return Mono.just(ReactorUtils.EMPTY_THROWABLE);
}
private void updateGatewayGroupMap(GatewayGroup gg) {
if (gg.isDeleted == GatewayGroup.DELETED) {
GatewayGroup r = gatewayGroupMap.remove(gg.group);
log.info("remove " + r);
} else {
GatewayGroup existGatewayGroup = gatewayGroupMap.get(gg.group);
gatewayGroupMap.put(gg.group, gg);
if (existGatewayGroup == null) {
log.info("add " + gg);
} else {
log.info("update " + existGatewayGroup + " with " + gg);
}
}
updateCurrentGatewayGroupSet();
}
private void updateCurrentGatewayGroupSet() {
String ip = NetworkUtils.getServerIp();
currentGatewayGroupSet.clear();
gatewayGroupMap.forEach(
(k, gg) -> {
if (gg.gateways.contains(ip)) {
currentGatewayGroupSet.add(gg.group);
}
}
);
if (currentGatewayGroupSet.isEmpty()) {
currentGatewayGroupSet.add(GatewayGroup.DEFAULT);
}
}
public boolean currentGatewayGroupIn(Set<String> gatewayGroups) {
for (String cgg : currentGatewayGroupSet) {
if (gatewayGroups.contains(cgg)) {
return true;
}
}
return false;
}
}

View File

@@ -14,10 +14,14 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.plugin.auth; package we.plugin.auth;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import org.apache.commons.lang3.StringUtils;
import we.util.Constants; import we.util.Constants;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
@@ -27,99 +31,122 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public class ServiceConfig { public class ServiceConfig {
private static final Logger log = LoggerFactory.getLogger(ServiceConfig.class); private static final Logger log = LoggerFactory.getLogger(ServiceConfig.class);
private static final String forward_slash_str = String.valueOf(Constants.Symbol.FORWARD_SLASH); public String id;
public String id; @JsonIgnore
public Map<Integer, ApiConfig> apiConfigMap = new HashMap<>(32);
private Map<Integer, ApiConfig> apiConfigMap = new HashMap<>(32); public Map<String, EnumMap<HttpMethod, GatewayGroup2appsToApiConfig>> path2methodToApiConfigMapMap = new HashMap<>(6);
private Map<String, EnumMap<HttpMethod, ApiConfig>> path2methodToApiConfigMapMap = new HashMap<>(32);
public ServiceConfig(String id) { public ServiceConfig(String id) {
this.id = id; this.id = id;
} }
public Map<Integer, ApiConfig> apiConfigMap() { public void add(ApiConfig ac) {
return apiConfigMap; apiConfigMap.put(ac.id, ac);
} EnumMap<HttpMethod, GatewayGroup2appsToApiConfig> method2apiConfigMap = path2methodToApiConfigMapMap.get(ac.path);
if (method2apiConfigMap == null) {
public Map<String, EnumMap<HttpMethod, ApiConfig>> getPath2methodToApiConfigMapMap() { method2apiConfigMap = new EnumMap<>(HttpMethod.class);
return path2methodToApiConfigMapMap; GatewayGroup2appsToApiConfig gatewayGroup2appsToApiConfig = new GatewayGroup2appsToApiConfig();
gatewayGroup2appsToApiConfig.add(ac);
method2apiConfigMap.put(ac.method, gatewayGroup2appsToApiConfig);
path2methodToApiConfigMapMap.put(ac.path, method2apiConfigMap);
} else {
GatewayGroup2appsToApiConfig gatewayGroup2appsToApiConfig = method2apiConfigMap.get(ac.method);
if (gatewayGroup2appsToApiConfig == null) {
gatewayGroup2appsToApiConfig = new GatewayGroup2appsToApiConfig();
method2apiConfigMap.put(ac.method, gatewayGroup2appsToApiConfig);
}
gatewayGroup2appsToApiConfig.add(ac);
}
log.info("add " + ac);
} }
public void remove(ApiConfig ac) { public void remove(ApiConfig ac) {
ApiConfig remove = apiConfigMap.remove(ac.id); ApiConfig remove = apiConfigMap.remove(ac.id);
log.info(remove + " is removed from api config map"); Map<HttpMethod, GatewayGroup2appsToApiConfig> method2apiConfigMap = path2methodToApiConfigMapMap.get(ac.path);
Map<HttpMethod, ApiConfig> method2apiConfigMap = path2methodToApiConfigMapMap.get(ac.path);
if (method2apiConfigMap != null) {
ApiConfig r = method2apiConfigMap.remove(ac.method);
log.info(r + " is removed from method 2 api config map");
if (method2apiConfigMap.isEmpty()) {
path2methodToApiConfigMapMap.remove(ac.path);
}
} else {
log.info("no method 2 api config map for " + ac.path);
}
}
public void add(ApiConfig ac) {
apiConfigMap.put(ac.id, ac);
EnumMap<HttpMethod, ApiConfig> method2apiConfigMap = path2methodToApiConfigMapMap.get(ac.path);
if (method2apiConfigMap == null) { if (method2apiConfigMap == null) {
method2apiConfigMap = new EnumMap<>(HttpMethod.class); log.info("no config to delete for " + ac.service + ' ' + ac.path);
path2methodToApiConfigMapMap.put(ac.path, method2apiConfigMap); } else {
GatewayGroup2appsToApiConfig gatewayGroup2appsToApiConfig = method2apiConfigMap.get(ac.method);
if (gatewayGroup2appsToApiConfig == null) {
log.info("no config to delete for " + ac.service + ' ' + ac.method + ' ' + ac.path);
} else {
log.info(id + " remove " + ac);
gatewayGroup2appsToApiConfig.remove(ac);
}
} }
method2apiConfigMap.put(ac.method, ac);
log.info(ac + " is added to api config map");
} }
public void update(ApiConfig ac) { public void update(ApiConfig ac) {
ApiConfig prev = apiConfigMap.put(ac.id, ac); ApiConfig prev = apiConfigMap.put(ac.id, ac);
log.info(prev + " is updated by " + ac + " in api config map"); log.info(prev + " is updated by " + ac + " in api config map");
EnumMap<HttpMethod, ApiConfig> method2apiConfigMap = path2methodToApiConfigMapMap.get(ac.path); EnumMap<HttpMethod, GatewayGroup2appsToApiConfig> method2apiConfigMap = path2methodToApiConfigMapMap.get(ac.path);
if (method2apiConfigMap == null) { if (method2apiConfigMap == null) {
method2apiConfigMap = new EnumMap<>(HttpMethod.class); method2apiConfigMap = new EnumMap<>(HttpMethod.class);
GatewayGroup2appsToApiConfig gatewayGroup2appsToApiConfig = new GatewayGroup2appsToApiConfig();
gatewayGroup2appsToApiConfig.add(ac);
method2apiConfigMap.put(ac.method, gatewayGroup2appsToApiConfig);
path2methodToApiConfigMapMap.put(ac.path, method2apiConfigMap); path2methodToApiConfigMapMap.put(ac.path, method2apiConfigMap);
} else {
GatewayGroup2appsToApiConfig gatewayGroup2appsToApiConfig = method2apiConfigMap.get(ac.method);
if (gatewayGroup2appsToApiConfig == null) {
gatewayGroup2appsToApiConfig = new GatewayGroup2appsToApiConfig();
method2apiConfigMap.put(ac.method, gatewayGroup2appsToApiConfig);
gatewayGroup2appsToApiConfig.add(ac);
} else {
log.info(id + " update " + ac);
gatewayGroup2appsToApiConfig.update(ac);
}
} }
ApiConfig put = method2apiConfigMap.put(ac.method, ac);
log.info(put + " is updated by " + ac + " in method 2 api config map");
} }
@JsonIgnore @JsonIgnore
public ApiConfig getApiConfig(HttpMethod method, String path) { public ApiConfig getApiConfig(HttpMethod method, String path, String gatewayGroup, String app) {
GatewayGroup2appsToApiConfig r = getApiConfig0(method, path);
if (r == null) {
return null;
}
if (StringUtils.isBlank(app)) {
app = App.ALL_APP;
}
return r.get(gatewayGroup, app);
}
private GatewayGroup2appsToApiConfig getApiConfig0(HttpMethod method, String path) {
while (true) { while (true) {
EnumMap<HttpMethod, ApiConfig> method2apiConfigMap = path2methodToApiConfigMapMap.get(path); EnumMap<HttpMethod, GatewayGroup2appsToApiConfig> method2apiConfigMap = path2methodToApiConfigMapMap.get(path);
if (method2apiConfigMap == null) { if (method2apiConfigMap == null) {
int i = path.lastIndexOf(Constants.Symbol.FORWARD_SLASH); int i = path.lastIndexOf(Constants.Symbol.FORWARD_SLASH);
if (i == 0) { if (i == 0) {
method2apiConfigMap = path2methodToApiConfigMapMap.get(forward_slash_str); method2apiConfigMap = path2methodToApiConfigMapMap.get(Constants.Symbol.FORWARD_SLASH_STR);
if (method2apiConfigMap == null) { if (method2apiConfigMap == null) {
return null; return null;
} else { } else {
return getApiConfig0(method, method2apiConfigMap); return getApiConfig1(method, method2apiConfigMap);
} }
} else { } else {
path = path.substring(0, i); path = path.substring(0, i);
} }
} else { } else {
return getApiConfig0(method, method2apiConfigMap); return getApiConfig1(method, method2apiConfigMap);
} }
} }
} }
private ApiConfig getApiConfig0(HttpMethod method, EnumMap<HttpMethod, ApiConfig> method2apiConfigMap) { private GatewayGroup2appsToApiConfig getApiConfig1(HttpMethod method, EnumMap<HttpMethod, GatewayGroup2appsToApiConfig> method2apiConfigMap) {
ApiConfig ac = method2apiConfigMap.get(method); GatewayGroup2appsToApiConfig r = method2apiConfigMap.get(method);
if (ac == null) { if (r == null) {
return method2apiConfigMap.get(HttpMethod.X); return method2apiConfigMap.get(HttpMethod.X);
} else { } else {
return ac; return r;
} }
} }
} }

View File

@@ -14,24 +14,32 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.plugin.stat; package we.plugin.stat;
import we.flume.clients.log4j2appender.LogService; import org.apache.commons.lang3.StringUtils;
import we.plugin.PluginFilter;
import we.util.Constants;
import we.util.ThreadContext;
import we.util.WebUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.flume.clients.log4j2appender.LogService;
import we.listener.AggregateRedisConfig;
import we.plugin.PluginFilter;
import we.plugin.auth.GatewayGroupService;
import we.util.Constants;
import we.util.ThreadContext;
import we.util.WebUtils;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Iterator;
import java.util.Map; import java.util.Map;
/** /**
* @author lancer * @author hongqiaowei
*/ */
@Component(StatPluginFilter.STAT_PLUGIN_FILTER) @Component(StatPluginFilter.STAT_PLUGIN_FILTER)
@@ -41,8 +49,6 @@ public class StatPluginFilter extends PluginFilter {
public static final String STAT_PLUGIN_FILTER = "statPlugin"; public static final String STAT_PLUGIN_FILTER = "statPlugin";
private static final String accessStat = "$accessStat";
private static final String ip = "\"ip\":"; private static final String ip = "\"ip\":";
private static final String gatewayGroup = "\"gatewayGroup\":"; private static final String gatewayGroup = "\"gatewayGroup\":";
@@ -60,24 +66,37 @@ public class StatPluginFilter extends PluginFilter {
@Value("${stat.open:false}") @Value("${stat.open:false}")
private boolean statOpen = false; private boolean statOpen = false;
@Value("${stat.topic:fizz_access_stat}") @Value("${stat.channel:fizz_access_stat}")
private String fizzAccessStatChannel;
@Value("${stat.topic:}")
private String fizzAccessStatTopic; private String fizzAccessStatTopic;
@Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
private ReactiveStringRedisTemplate rt;
@Resource
private GatewayGroupService gatewayGroupService;
private String currentGatewayGroups;
@PostConstruct
public void init() {
Iterator<String> it = gatewayGroupService.currentGatewayGroupSet.iterator();
currentGatewayGroups = it.next();
while (it.hasNext()) {
currentGatewayGroups = currentGatewayGroups + ',' + it.next();
}
}
@Override @Override
public Mono<Void> doFilter(ServerWebExchange exchange, Map<String, Object> config, String fixedConfig) { public Mono<Void> doFilter(ServerWebExchange exchange, Map<String, Object> config, String fixedConfig) {
if (statOpen) { if (statOpen) {
StringBuilder b = (StringBuilder) ThreadContext.get(accessStat); StringBuilder b = ThreadContext.getStringBuilder();
if (b == null) {
b = new StringBuilder(128);
ThreadContext.set(accessStat, b);
} else {
b.delete(0, b.length());
}
b.append(Constants.Symbol.LEFT_BRACE); b.append(Constants.Symbol.LEFT_BRACE);
b.append(ip); toJsonStringValue(b, WebUtils.getOriginIp(exchange)); b.append(Constants.Symbol.COMMA); b.append(ip); toJsonStringValue(b, WebUtils.getOriginIp(exchange)); b.append(Constants.Symbol.COMMA);
b.append(gatewayGroup); toJsonStringValue(b, WebUtils.getCurrentGatewayGroup(exchange)); b.append(Constants.Symbol.COMMA); b.append(gatewayGroup); toJsonStringValue(b, currentGatewayGroups); b.append(Constants.Symbol.COMMA);
b.append(service); toJsonStringValue(b, WebUtils.getServiceId(exchange)); b.append(Constants.Symbol.COMMA); b.append(service); toJsonStringValue(b, WebUtils.getServiceId(exchange)); b.append(Constants.Symbol.COMMA);
b.append(appid); toJsonStringValue(b, WebUtils.getAppId(exchange)); b.append(Constants.Symbol.COMMA); b.append(appid); toJsonStringValue(b, WebUtils.getAppId(exchange)); b.append(Constants.Symbol.COMMA);
b.append(apiMethod); toJsonStringValue(b, exchange.getRequest().getMethodValue()); b.append(Constants.Symbol.COMMA); b.append(apiMethod); toJsonStringValue(b, exchange.getRequest().getMethodValue()); b.append(Constants.Symbol.COMMA);
@@ -85,7 +104,11 @@ public class StatPluginFilter extends PluginFilter {
b.append(reqTime) .append(System.currentTimeMillis()); b.append(reqTime) .append(System.currentTimeMillis());
b.append(Constants.Symbol.RIGHT_BRACE); b.append(Constants.Symbol.RIGHT_BRACE);
log.info(b.toString(), LogService.HANDLE_STGY, LogService.toKF(fizzAccessStatTopic)); if (StringUtils.isBlank(fizzAccessStatTopic)) {
rt.convertAndSend(fizzAccessStatChannel, b.toString());
} else {
log.info(b.toString(), LogService.HANDLE_STGY, LogService.toKF(fizzAccessStatTopic));
}
} }
return WebUtils.transmitSuccessFilterResultAndEmptyMono(exchange, STAT_PLUGIN_FILTER, null); return WebUtils.transmitSuccessFilterResultAndEmptyMono(exchange, STAT_PLUGIN_FILTER, null);

View File

@@ -14,10 +14,11 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.proxy; package we.proxy;
/** /**
* @author lancer * @author hongqiaowei
* 请求转发/调用后端接口时的负载均衡、流控、failover、超时等配置 * 请求转发/调用后端接口时的负载均衡、流控、failover、超时等配置
*/ */

View File

@@ -14,17 +14,13 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.proxy; package we.proxy;
import com.netflix.appinfo.InstanceInfo; import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.EurekaClient; import com.netflix.discovery.EurekaClient;
import com.netflix.discovery.shared.Applications; import com.netflix.discovery.shared.Applications;
import we.flume.clients.log4j2appender.LogService;
import we.config.AggrWebClientConfig;
import we.config.ProxyWebClientConfig;
import we.util.Constants;
import we.util.ThreadContext;
import we.util.WebUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
@@ -38,14 +34,22 @@ import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.config.AggrWebClientConfig;
import we.config.ProxyWebClientConfig;
import we.flume.clients.log4j2appender.LogService;
import we.util.Constants;
import we.util.ThreadContext;
import we.util.WebUtils;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* @author lancer * @author hongqiaowei
*/ */
@Service @Service
@@ -95,18 +99,26 @@ public class FizzWebClient {
return aggrResolveAddressSend(aggrService, aggrMethod, aggrPath, originReqIdOrBizId, method, uriOrSvc, headers, body, null); return aggrResolveAddressSend(aggrService, aggrMethod, aggrPath, originReqIdOrBizId, method, uriOrSvc, headers, body, null);
} }
private Mono<ClientResponse> aggrResolveAddressSend(String aggrService, HttpMethod aggrMethod, String aggrPath, @Nullable String originReqIdOrBizId, public Mono<ClientResponse> send(String reqId, HttpMethod method, String uriOrSvc, @Nullable HttpHeaders headers, @Nullable Object body) {
HttpMethod method, String uriOrSvc, @Nullable HttpHeaders headers, @Nullable Object body, @Nullable CallBackendConfig cbc) { return send(reqId, method, uriOrSvc, headers, body, null);
}
public Mono<ClientResponse> send(String reqId, HttpMethod method, String uriOrSvc, HttpHeaders headers, Object body, CallBackendConfig cbc) {
String s = extractServiceOrAddress(uriOrSvc); String s = extractServiceOrAddress(uriOrSvc);
if (isService(s)) { if (isService(s)) {
String path = uriOrSvc.substring(uriOrSvc.indexOf(Constants.Symbol.FORWARD_SLASH, 10)); String path = uriOrSvc.substring(uriOrSvc.indexOf(Constants.Symbol.FORWARD_SLASH, 10));
return send2service(originReqIdOrBizId, method, s, path, headers, body, cbc); return send2service(reqId, method, s, path, headers, body, cbc);
} else { } else {
return send2uri(originReqIdOrBizId, method, uriOrSvc, headers, body, cbc); return send2uri(reqId, method, uriOrSvc, headers, body, cbc);
} }
} }
private Mono<ClientResponse> aggrResolveAddressSend(String aggrService, HttpMethod aggrMethod, String aggrPath, @Nullable String originReqIdOrBizId,
HttpMethod method, String uriOrSvc, @Nullable HttpHeaders headers, @Nullable Object body, @Nullable CallBackendConfig cbc) {
return send(originReqIdOrBizId, method, uriOrSvc, headers, body, cbc);
}
public Mono<ClientResponse> proxySend2service(@Nullable String originReqIdOrBizId, HttpMethod method, String service, String relativeUri, public Mono<ClientResponse> proxySend2service(@Nullable String originReqIdOrBizId, HttpMethod method, String service, String relativeUri,
@Nullable HttpHeaders headers, @Nullable Object body) { @Nullable HttpHeaders headers, @Nullable Object body) {
@@ -218,7 +230,23 @@ public class FizzWebClient {
return b.append(Constants.Symbol.HTTP_PROTOCOL_PREFIX).append(inst.getIPAddr()).append(Constants.Symbol.COLON).append(inst.getPort()).append(path).toString(); return b.append(Constants.Symbol.HTTP_PROTOCOL_PREFIX).append(inst.getIPAddr()).append(Constants.Symbol.COLON).append(inst.getPort()).append(path).toString();
} }
// private static List<InstanceInfo> aggrMemberInsts = new ArrayList<>();
// static {
// InstanceInfo i0 = InstanceInfo.Builder.newBuilder().setAppName("TRIP-MINI").setIPAddr("xxx.25.63.192").setPort(7094).build();
// aggrMemberInsts.add(i0);
// }
// private static AtomicLong counter = new AtomicLong(0);
// private static final String aggrMember = "trip-mini";
private InstanceInfo roundRobinChoose1instFrom(String service) { private InstanceInfo roundRobinChoose1instFrom(String service) {
// if (aggrMember.equals(service)) {
// int idx = (int) (counter.incrementAndGet() % aggrMemberInsts.size());
// return aggrMemberInsts.get(idx);
// }
List<InstanceInfo> insts = eurekaClient.getInstancesByVipAddress(service, false); List<InstanceInfo> insts = eurekaClient.getInstancesByVipAddress(service, false);
if (insts == null || insts.isEmpty()) { if (insts == null || insts.isEmpty()) {
throw new RuntimeException("eureka no " + service, null, false, false) {}; throw new RuntimeException("eureka no " + service, null, false, false) {};

View File

@@ -14,12 +14,13 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.util; package we.util;
import org.apache.commons.lang3.SystemUtils; import org.apache.commons.lang3.SystemUtils;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public final class Constants { public final class Constants {
@@ -33,6 +34,7 @@ public final class Constants {
public static final char BLANK = ' '; public static final char BLANK = ' ';
public static final char SPACE = BLANK; public static final char SPACE = BLANK;
public static final char FORWARD_SLASH = '/'; public static final char FORWARD_SLASH = '/';
public static final String FORWARD_SLASH_STR = "/";
public static final char BACK_SLASH = '\\'; public static final char BACK_SLASH = '\\';
public static final char DOT = '.'; public static final char DOT = '.';
public static final char SEMICOLON = ';'; public static final char SEMICOLON = ';';

View File

@@ -14,9 +14,8 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.util;
import we.util.Constants.DatetimePattern; package we.util;
import java.time.*; import java.time.*;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@@ -25,8 +24,10 @@ import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import we.util.Constants.DatetimePattern;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public abstract class DateTimeUtils { public abstract class DateTimeUtils {

View File

@@ -22,7 +22,7 @@ import org.apache.commons.codec.binary.Hex;
import java.security.MessageDigest; import java.security.MessageDigest;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public abstract class DigestUtils extends org.apache.commons.codec.digest.DigestUtils { public abstract class DigestUtils extends org.apache.commons.codec.digest.DigestUtils {

View File

@@ -14,6 +14,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.util; package we.util;
import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.annotation.JsonInclude.Include;
@@ -23,6 +24,7 @@ import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.module.SimpleModule;
import we.plugin.auth.ApiConfig; import we.plugin.auth.ApiConfig;
import we.util.Constants.DatetimePattern; import we.util.Constants.DatetimePattern;
@@ -33,7 +35,7 @@ import java.time.format.DateTimeFormatter;
import java.util.Date; import java.util.Date;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public abstract class JacksonUtils { public abstract class JacksonUtils {
@@ -42,19 +44,19 @@ public abstract class JacksonUtils {
static { static {
JsonFactory f = new JsonFactory(); JsonFactory f = new JsonFactory();
f.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); f.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
f.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); f.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
m = new ObjectMapper(f); m = new ObjectMapper(f);
m.setSerializationInclusion(Include.NON_EMPTY); m.setSerializationInclusion(Include.NON_EMPTY);
m.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true); m.configure( SerializationFeature. WRITE_ENUMS_USING_TO_STRING, true);
m.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true); m.configure( DeserializationFeature. READ_ENUMS_USING_TO_STRING, true);
m.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, true); m.configure( DeserializationFeature. FAIL_ON_NUMBERS_FOR_ENUMS, true);
m.configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, true); // FIXME m.configure( SerializationFeature. WRITE_EMPTY_JSON_ARRAYS, true); // FIXME
m.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, true); m.configure( SerializationFeature. WRITE_NULL_MAP_VALUES, true);
m.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); m.configure( DeserializationFeature. FAIL_ON_UNKNOWN_PROPERTIES, false);
m.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true); m.configure( JsonParser.Feature. ALLOW_UNQUOTED_CONTROL_CHARS, true);
SimpleModule m0 = new SimpleModule(); SimpleModule m0 = new SimpleModule();
m0.addDeserializer(Date.class, new DateDeseralizer()); m0.addDeserializer(Date.class, new DateDeseralizer());

View File

@@ -14,6 +14,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.util; package we.util;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -27,7 +28,7 @@ import java.security.SecureRandom;
import java.util.Enumeration; import java.util.Enumeration;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public class NetworkUtils { public class NetworkUtils {
@@ -75,7 +76,7 @@ public class NetworkUtils {
public static int getServerId() { public static int getServerId() {
if (serverId == -1) { if (serverId == -1) {
try { try {
StringBuilder b = new StringBuilder(); StringBuilder b = ThreadContext.getStringBuilder();
Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces(); Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces();
while (nis.hasMoreElements()) { while (nis.hasMoreElements()) {
NetworkInterface ni = nis.nextElement(); NetworkInterface ni = nis.nextElement();

View File

@@ -14,12 +14,13 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.util; package we.util;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public interface ReactorUtils { public interface ReactorUtils {

View File

@@ -14,10 +14,11 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.util; package we.util;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public class Script { public class Script {

View File

@@ -14,9 +14,9 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.util; package we.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import javax.script.*; import javax.script.*;
@@ -26,7 +26,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public abstract class ScriptUtils { public abstract class ScriptUtils {

View File

@@ -14,6 +14,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.util; package we.util;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@@ -21,7 +22,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public abstract class ThreadContext { public abstract class ThreadContext {
@@ -29,7 +30,7 @@ public abstract class ThreadContext {
private static ThreadLocal<Map<String, Object>> tl = new ThreadLocal<>(); private static ThreadLocal<Map<String, Object>> tl = new ThreadLocal<>();
private static final int mapCap = 32; private static final int mapCap = 32;
private static final String sb = "_sb"; private static final String sb = "$sb";
private static final int sbCap = 256; private static final int sbCap = 256;
/** use me carefully! */ /** use me carefully! */
@@ -39,31 +40,29 @@ public abstract class ThreadContext {
/** use me carefully! */ /** use me carefully! */
public static StringBuilder getStringBuilder(boolean clean) { public static StringBuilder getStringBuilder(boolean clean) {
// Map<String, Object> m = getMap(); Map<String, Object> m = getMap();
// StringBuilder b = (StringBuilder) m.get(sb); StringBuilder b = (StringBuilder) m.get(sb);
// if (b == null) { if (b == null) {
// b = new StringBuilder(sbCap); b = new StringBuilder(sbCap);
// m.put(sb, b); m.put(sb, b);
// } else { } else {
// if (clean) { if (clean) {
// b.delete(0, b.length()); b.delete(0, b.length());
// } }
// } }
// return b; return b;
return new StringBuilder(64);
} }
public static StringBuilder getStringBuilder(String key) { public static StringBuilder getStringBuilder(String key) {
// StringBuilder b = (StringBuilder) get(key); StringBuilder b = (StringBuilder) get(key);
// if (b == null) { if (b == null) {
// b = new StringBuilder(sbCap); b = new StringBuilder(sbCap);
// Map<String, Object> m = getMap(); Map<String, Object> m = getMap();
// m.put(key, b); m.put(key, b);
// } else { } else {
// b.delete(0, b.length()); b.delete(0, b.length());
// } }
// return b; return b;
return getStringBuilder(true);
} }
/** for legacy code. */ /** for legacy code. */

View File

@@ -14,6 +14,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.util; package we.util;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -23,7 +24,7 @@ import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public abstract class Utils { public abstract class Utils {

View File

@@ -14,11 +14,9 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package we.util; package we.util;
import we.flume.clients.log4j2appender.LogService;
import we.filter.FilterResult;
import we.legacy.RespEntity;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -32,11 +30,14 @@ import org.springframework.lang.Nullable;
import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import we.filter.FilterResult;
import we.flume.clients.log4j2appender.LogService;
import we.legacy.RespEntity;
import java.util.*; import java.util.*;
/** /**
* @author lancer * @author hongqiaowei
*/ */
public abstract class WebUtils { public abstract class WebUtils {
@@ -57,7 +58,7 @@ public abstract class WebUtils {
private static final String SERVICE_ID = "serviceId"; private static final String SERVICE_ID = "serviceId";
private static final String xForwardedFor = "X_FORWARDED_FOR"; private static final String xForwardedFor = "X-FORWARDED-FOR";
private static final String unknown = "unknown"; private static final String unknown = "unknown";
@@ -73,8 +74,6 @@ public abstract class WebUtils {
private static final String originIp = "originIp"; private static final String originIp = "originIp";
public static final String CGG = "cgg";
public static String getHeaderValue(ServerWebExchange exchange, String header) { public static String getHeaderValue(ServerWebExchange exchange, String header) {
return exchange.getRequest().getHeaders().getFirst(header); return exchange.getRequest().getHeaders().getFirst(header);
} }
@@ -87,10 +86,6 @@ public abstract class WebUtils {
return exchange.getAttribute(APP_HEADER); return exchange.getAttribute(APP_HEADER);
} }
public static Character getCurrentGatewayGroup(ServerWebExchange exchange) {
return exchange.getAttribute(CGG);
}
public static String getServiceId(ServerWebExchange exchange) { public static String getServiceId(ServerWebExchange exchange) {
String svc = exchange.getAttribute(SERVICE_ID); String svc = exchange.getAttribute(SERVICE_ID);
if (svc == null) { if (svc == null) {