Rename Dict to GlobalResource

This commit is contained in:
hongqiaowei
2021-10-12 20:04:54 +08:00
parent 6128c78d86
commit 0190ac2c31
7 changed files with 217 additions and 190 deletions

View File

@@ -22,7 +22,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import we.dict.DictService;
import we.global_resource.GlobalResourceService;
import we.plugin.auth.ApiConfigService;
import we.plugin.auth.ApiConifg2appsService;
import we.plugin.auth.AppService;
@@ -56,7 +56,7 @@ public class CacheCheckController {
private ApiConifg2appsService apiConifg2appsService;
@Resource
private DictService dictService;
private GlobalResourceService globalResourceService;
@GetMapping("/gatewayGroups")
public Mono<String> gatewayGroups(ServerWebExchange exchange) {
@@ -88,8 +88,8 @@ public class CacheCheckController {
return Mono.just(JacksonUtils.writeValueAsString(apiConifg2appsService.getApiConfig2appsMap()));
}
@GetMapping("/dicts")
@GetMapping("/globalResources")
public Mono<String> dicts(ServerWebExchange exchange) {
return Mono.just(JacksonUtils.writeValueAsString(dictService.getDictMap()));
return Mono.just(JacksonUtils.writeValueAsString(globalResourceService.getResourceMap()));
}
}

View File

@@ -1,152 +0,0 @@
/*
* Copyright (C) 2020 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.dict;
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.FizzAppContext;
import we.config.AggregateRedisConfig;
import we.util.JacksonUtils;
import we.util.ReactiveResult;
import we.util.Result;
import we.util.Utils;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* @author hongqiaowei
*/
@Service
public class DictService {
private static final Logger log = LoggerFactory.getLogger(DictService.class);
private Map<String, Dict> dictMap = new HashMap<>(64);
@Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
private ReactiveStringRedisTemplate rt;
@PostConstruct
public void init() throws Throwable {
initDict().subscribe(
r -> {
if (r.code == ReactiveResult.SUCC) {
lsnInitChange().subscribe(
res -> {
if (res.code == ReactiveResult.FAIL) {
log.error(res.toString());
if (res.t == null) {
throw Utils.runtimeExceptionWithoutStack("lsn dict error");
}
throw new RuntimeException(res.t);
}
}
);
} else {
log.error(r.toString());
if (r.t == null) {
throw Utils.runtimeExceptionWithoutStack("init dict error");
}
throw new RuntimeException(r.t);
}
}
);
}
private Mono<Result<?>> initDict() {
Flux<Map.Entry<Object, Object>> dicts = rt.opsForHash().entries("fizz_dict");
dicts.collectList()
.defaultIfEmpty(Collections.emptyList())
.flatMap(
es -> {
if (FizzAppContext.appContext != null) {
for (Map.Entry<Object, Object> e : es) {
String json = (String) e.getValue();
Dict dict = JacksonUtils.readValue(json, Dict.class);
dictMap.put(dict.key, dict);
log.info("init dict: {}", dict);
}
}
return Mono.empty();
}
)
.doOnError(
t -> {
log.error("init dict", t);
}
)
.block();
return Mono.just(Result.succ());
}
private Mono<Result<?>> lsnInitChange() {
Result<?> result = Result.succ();
String channel = "fizz_dict_channel";
rt.listenToChannel(channel)
.doOnError(
t -> {
result.code = ReactiveResult.FAIL;
result.t = t;
log.error("lsn {}", channel, t);
}
)
.doOnSubscribe(
s -> {
log.info("success to lsn on {}", channel);
}
)
.doOnNext(
msg -> {
if (FizzAppContext.appContext != null) {
String message = msg.getMessage();
try {
Dict dict = JacksonUtils.readValue(message, Dict.class);
if (dict.isDeleted == Dict.DELETED) {
dictMap.remove(dict.key);
log.info("remove dict {}", dict.key);
} else {
Dict put = dictMap.put(dict.key, dict);
log.info("update dict {} with {}", put, dict);
}
} catch (Throwable t) {
log.error("message: {}", message, t);
}
}
}
)
.subscribe();
return Mono.just(result);
}
public Map<String, Dict> getDictMap() {
return dictMap;
}
public Dict get(String key) {
return dictMap.get(key);
}
}

View File

@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package we.dict;
package we.global_resource;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -26,10 +26,11 @@ import java.util.List;
import java.util.Map;
/**
* just a dict.
* @author hongqiaowei
*/
public class Dict {
public class GlobalResource {
public static final int BOOLEAN = 1;
public static final int STRING = 2;
@@ -46,7 +47,9 @@ public class Dict {
public int type;
public String value;
public String val;
public Object originalVal; /** for aggregate use mainly */
public boolean booleanVal;
@@ -73,7 +76,7 @@ public class Dict {
public long update;
@JsonCreator
public Dict(
public GlobalResource(
@JsonProperty("isDeleted") int isDeleted,
@JsonProperty("id") int id,
@JsonProperty("key") String key,
@@ -87,29 +90,38 @@ public class Dict {
this.id = id;
this.key = key;
this.type = type;
this.value = value;
this.val = value;
this.create = create;
this.update = update;
if (type == BOOLEAN) {
booleanVal = Boolean.parseBoolean(value);
booleanVal = Boolean.parseBoolean(value);
originalVal = booleanVal;
} else if (type == STRING) {
stringVal = value;
stringVal = value;
originalVal = stringVal;
} else if (type == NUMBER) {
numberVal = new BigDecimal(value);
if (value.indexOf('.') == -1) {
intVal = numberVal.intValue();
longVal = numberVal.longValue();
intVal = numberVal.intValue();
longVal = numberVal.longValue();
originalVal = longVal;
} else {
floatVal = numberVal.floatValue();
doubleVal = numberVal.doubleValue();
floatVal = numberVal.floatValue();
doubleVal = numberVal.doubleValue();
originalVal = doubleVal;
}
} else { // JSON
jsonVal = value;
if (value.startsWith("{")) {
valMap = JacksonUtils.readValue(jsonVal, Map.class);
valMap = JacksonUtils.readValue(jsonVal, Map.class);
originalVal = valMap;
} else {
valList = JacksonUtils.readValue(jsonVal, List.class);
valList = JacksonUtils.readValue(jsonVal, List.class);
originalVal = valList;
}
}
}

View File

@@ -0,0 +1,168 @@
/*
* 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.global_resource;
import org.noear.snack.ONode;
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.Fizz;
import we.config.AggregateRedisConfig;
import we.fizz.input.PathMapping;
import we.util.JacksonUtils;
import we.util.ReactiveResult;
import we.util.Result;
import we.util.Utils;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* @author hongqiaowei
*/
@Service
public class GlobalResourceService {
private static final Logger log = LoggerFactory.getLogger(GlobalResourceService.class);
public static ONode resNode;
private Map<String, GlobalResource> resourceMap = new HashMap<>(64);
private Map<String, Object> objectMap = new HashMap<>(64);
@Resource(name = AggregateRedisConfig.AGGREGATE_REACTIVE_REDIS_TEMPLATE)
private ReactiveStringRedisTemplate rt;
@PostConstruct
public void init() throws Throwable {
initGlobalResource().subscribe(
r -> {
if (r.code == ReactiveResult.SUCC) {
lsnGlobalResourceChange().subscribe(
res -> {
if (res.code == ReactiveResult.FAIL) {
log.error(res.toString());
if (res.t == null) {
throw Utils.runtimeExceptionWithoutStack("lsn global resource error");
}
throw new RuntimeException(res.t);
}
updateResNode();
}
);
} else {
log.error(r.toString());
if (r.t == null) {
throw Utils.runtimeExceptionWithoutStack("init global resource error");
}
throw new RuntimeException(r.t);
}
}
);
}
private void updateResNode() {
resNode = PathMapping.toONode(objectMap);
log.info("new object map: {}", JacksonUtils.writeValueAsString(objectMap));
}
private Mono<Result<?>> initGlobalResource() {
Flux<Map.Entry<Object, Object>> dicts = rt.opsForHash().entries("fizz_global_resource");
dicts.collectList()
.defaultIfEmpty(Collections.emptyList())
.flatMap(
es -> {
if (Fizz.context != null) {
for (Map.Entry<Object, Object> e : es) {
String json = (String) e.getValue();
GlobalResource r = JacksonUtils.readValue(json, GlobalResource.class);
resourceMap.put(r.key, r);
objectMap.put(r.key, r.originalVal);
log.info("init global resource: {}", r);
}
}
return Mono.empty();
}
)
.doOnError(
t -> {
log.error("init global resource", t);
}
)
.block();
return Mono.just(Result.succ());
}
private Mono<Result<?>> lsnGlobalResourceChange() {
Result<?> result = Result.succ();
String channel = "fizz_global_resource_channel";
rt.listenToChannel(channel)
.doOnError(
t -> {
result.code = ReactiveResult.FAIL;
result.t = t;
log.error("lsn {}", channel, t);
}
)
.doOnSubscribe(
s -> {
log.info("success to lsn on {}", channel);
}
)
.doOnNext(
msg -> {
if (Fizz.context != null) {
String message = msg.getMessage();
try {
GlobalResource r = JacksonUtils.readValue(message, GlobalResource.class);
if (r.isDeleted == GlobalResource.DELETED) {
resourceMap.remove(r.key);
objectMap.remove(r.key);
log.info("remove global resource {}", r.key);
} else {
GlobalResource put = resourceMap.put(r.key, r);
objectMap.put(r.key, r);
log.info("update global resource {} with {}", put, r);
}
updateResNode();
} catch (Throwable t) {
log.error("message: {}", message, t);
}
}
}
)
.subscribe();
return Mono.just(result);
}
public Map<String, GlobalResource> getResourceMap() {
return resourceMap;
}
public GlobalResource get(String key) {
return resourceMap.get(key);
}
}

View File

@@ -86,7 +86,7 @@ public final class FizzPluginFilterChain {
}
}
@Deprecated
// @Deprecated
public static Mono<Void> next(ServerWebExchange exchange, List<PluginConfig> pcs) {
Iterator<PluginConfig> it = pcs.iterator();
Map<String, Object> attris = exchange.getAttributes();

View File

@@ -58,8 +58,8 @@ public class Route {
public long retryInterval = 0;
public Route type(byte t) {
type = t;
public Route type(int t) {
type = (byte) t;
return this;
}

View File

@@ -1,4 +1,4 @@
package we.dict;
package we.global_resource;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.junit.jupiter.api.BeforeEach;
@@ -8,9 +8,8 @@ import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import we.Fizz;
import we.FizzAppContext;
import we.plugin.auth.ApiConfigService;
import we.plugin.auth.ApiConfigServiceProperties;
import we.redis.RedisProperties;
import we.redis.RedisServerConfiguration;
import we.redis.RedisTemplateConfiguration;
@@ -27,7 +26,7 @@ import java.util.Map;
@TestPropertySource("/application.properties")
@SpringJUnitConfig(classes = {RedisProperties.class, RedisTemplateConfiguration.class, RedisServerConfiguration.class})
public class DictTests {
public class GlobalResourceTests {
@Resource
StringRedisTemplate stringRedisTemplate;
@@ -35,34 +34,34 @@ public class DictTests {
@Resource
ReactiveStringRedisTemplate reactiveStringRedisTemplate;
DictService dictService;
GlobalResourceService globalResourceService;
@BeforeEach
void beforeEach() throws NoSuchFieldException {
dictService = new DictService();
ReflectionUtils.set(dictService, "rt", reactiveStringRedisTemplate);
globalResourceService = new GlobalResourceService();
ReflectionUtils.set(globalResourceService, "rt", reactiveStringRedisTemplate);
}
@Test
void constructTest() throws JsonProcessingException {
String json = "{\"id\":1,\"key\":\"key\",\"type\":4,\"value\":\"{\\\"a0\\\":\\\"v0\\\",\\\"a1\\\":66}\",\"create\":1633756859538,\"update\":1633756859538,\"isDeleted\":1}";
Dict dict = JacksonUtils.readValue(json, Dict.class);
// assertEquals(96.12347, dict.numberVal.doubleValue());
// assertEquals("96.12347", dict.numberVal.toPlainString());
// System.err.println(dict.toString());
GlobalResource globalResource = JacksonUtils.readValue(json, GlobalResource.class);
// assertEquals(96.12347, globalResource.numberVal.doubleValue());
// assertEquals("96.12347", globalResource.numberVal.toPlainString());
// System.err.println(globalResource.toString());
}
@Test
void initTest() throws Throwable {
FizzAppContext.appContext = new GenericApplicationContext();
FizzAppContext.appContext.refresh();
Fizz.context = new GenericApplicationContext();
Fizz.context.refresh();
Map<String, String> dictsMap = new HashMap<>();
dictsMap.put("key0", "{\"id\":1,\"key\":\"key0\",\"type\":2,\"value\":\"val0\",\"create\":1633756859538,\"update\":1633756859538,\"isDeleted\":1}");
dictsMap.put("key1", "{\"id\":1,\"key\":\"key1\",\"type\":2,\"value\":\"val1\",\"create\":1633756859538,\"update\":1633756859538,\"isDeleted\":1}");
stringRedisTemplate.opsForHash().putAll("fizz_dict", dictsMap);
Map<String, String> resourceMap = new HashMap<>();
resourceMap.put("key0", "{\"id\":1,\"key\":\"key0\",\"type\":2,\"value\":\"val0\",\"create\":1633756859538,\"update\":1633756859538,\"isDeleted\":1}");
resourceMap.put("key1", "{\"id\":1,\"key\":\"key1\",\"type\":2,\"value\":\"val1\",\"create\":1633756859538,\"update\":1633756859538,\"isDeleted\":1}");
stringRedisTemplate.opsForHash().putAll("fizz_global_resource", resourceMap);
dictService.init();
globalResourceService.init();
}
}