org.jetlinks.supports.cluster.ClusterDeviceRegistry Maven / Gradle / Ivy
The newest version!
package org.jetlinks.supports.cluster;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.Setter;
import org.jetlinks.core.ProtocolSupports;
import org.jetlinks.core.cache.Caches;
import org.jetlinks.core.cluster.ClusterManager;
import org.jetlinks.core.cluster.ClusterSet;
import org.jetlinks.core.config.ConfigStorage;
import org.jetlinks.core.config.ConfigStorageManager;
import org.jetlinks.core.defaults.DefaultDeviceOperator;
import org.jetlinks.core.defaults.DefaultDeviceProductOperator;
import org.jetlinks.core.device.*;
import org.jetlinks.core.message.interceptor.DeviceMessageSenderInterceptor;
import org.jetlinks.core.things.ThingRpcSupportChain;
import org.jetlinks.supports.config.ClusterConfigStorageManager;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
import java.time.Duration;
import java.util.*;
public class ClusterDeviceRegistry implements DeviceRegistry {
//全局拦截器
private final CompositeDeviceMessageSenderInterceptor interceptor = new CompositeDeviceMessageSenderInterceptor();
//配置管理器
private final ConfigStorageManager manager;
//缓存
private final Cache> operatorCache;
//产品
private final Map productOperatorMap = Caches.newCache();
//协议支持
private final ProtocolSupports supports;
//设备操作
private final DeviceOperationBroker handler;
//集群管理
private final ClusterManager clusterManager;
//状态检查器
private final CompositeDeviceStateChecker stateChecker = new CompositeDeviceStateChecker();
@Setter
private ThingRpcSupportChain rpcChain;
@Deprecated
public ClusterDeviceRegistry(ProtocolSupports supports,
ClusterManager clusterManager,
DeviceOperationBroker handler) {
this(supports, clusterManager, handler, CacheBuilder
.newBuilder()
.softValues()
.expireAfterAccess(Duration.ofMinutes(30))
.build());
}
public ClusterDeviceRegistry(ProtocolSupports supports,
ConfigStorageManager storageManager,
ClusterManager clusterManager,
DeviceOperationBroker handler,
Cache> cache) {
this.supports = supports;
this.handler = handler;
this.manager = storageManager;
this.operatorCache = cache;
this.clusterManager = clusterManager;
this.addStateChecker(DefaultDeviceOperator.DEFAULT_STATE_CHECKER);
}
@Deprecated
public ClusterDeviceRegistry(ProtocolSupports supports,
ClusterManager clusterManager,
DeviceOperationBroker handler,
Cache> cache) {
this.supports = supports;
this.handler = handler;
this.manager = new ClusterConfigStorageManager(clusterManager);
this.operatorCache = cache;
this.clusterManager = clusterManager;
this.addStateChecker(DefaultDeviceOperator.DEFAULT_STATE_CHECKER);
}
@Override
public Flux checkDeviceState(Flux extends Collection> id) {
return id.flatMap(list -> Flux
.fromIterable(list)
.flatMap(this::getDevice)
.flatMap(device -> device
.getConnectionServerId()
.defaultIfEmpty("__")
.zipWith(Mono.just(device)))
.groupBy(Tuple2::getT1, Tuple2::getT2)
.flatMap(group -> {
if (!StringUtils.hasText(group.key()) || "__".equals(group.key())) {
return group.flatMap(operator -> operator
.getState()
.map(state -> new DeviceStateInfo(operator.getDeviceId(), state)));
}
return group
.map(DeviceOperator::getDeviceId)
.collectList()
.flatMapMany(deviceIdList -> handler.getDeviceState(group.key(), deviceIdList));
}));
}
@Override
public Mono getDevice(String deviceId) {
if (ObjectUtils.isEmpty(deviceId)) {
return Mono.empty();
}
{
Mono deviceOperator = operatorCache.getIfPresent(deviceId);
if (null != deviceOperator) {
return deviceOperator;
}
}
DeviceOperator deviceOperator = createOperator(deviceId);
return deviceOperator
//有productId说明是存在的设备
.getSelfConfig(DeviceConfigKey.productId)
.doOnNext(r -> operatorCache.put(deviceId, deviceOperator
.getSelfConfig(DeviceConfigKey.productId)
.map(ignore -> deviceOperator)
//设备被注销了?则移除之
.switchIfEmpty(Mono.fromRunnable(() -> operatorCache.invalidate(deviceId)))
))
.map(ignore -> deviceOperator);
}
@Override
public Mono getProduct(String productId) {
if (ObjectUtils.isEmpty(productId)) {
return Mono.empty();
}
{
DeviceProductOperator operator = productOperatorMap.get(productId);
if (null != operator) {
return Mono.just(operator);
}
}
DefaultDeviceProductOperator deviceOperator = createProductOperator(productId);
return deviceOperator
.getConfig(DeviceConfigKey.protocol)
.doOnNext(r -> productOperatorMap.put(productId, deviceOperator))
.map((r) -> deviceOperator);
}
private String createProductCacheKey(String productId, String version) {
return StringUtils.hasText(version) ? productId + ":" + version : productId;
}
@Override
public Mono getProduct(String productId, String version) {
if (ObjectUtils.isEmpty(productId)) {
return Mono.empty();
}
if (ObjectUtils.isEmpty(version)) {
return getProduct(productId);
}
String cacheId = createProductCacheKey(productId, version);
{
DeviceProductOperator operator = productOperatorMap.get(cacheId);
if (null != operator) {
return Mono.just(operator);
}
}
DefaultDeviceProductOperator operator = createProductOperator(productId, version);
return operator
.getConfig(DeviceConfigKey.protocol)
.doOnNext(r -> productOperatorMap.put(cacheId, operator))
.map((r) -> operator);
}
private DefaultDeviceOperator createOperator(String deviceId) {
DefaultDeviceOperator device = new DefaultDeviceOperator(deviceId, supports, manager, handler, this, interceptor, stateChecker);
if (rpcChain != null) {
device.setRpcChain(rpcChain);
}
return device;
}
private DefaultDeviceProductOperator createProductOperator(String id) {
return new DefaultDeviceProductOperator(id,
supports,
manager,
() -> getProductBind(id, null).values().flatMap(this::getDevice));
}
private DefaultDeviceProductOperator createProductOperator(String id, String version) {
if (StringUtils.isEmpty(version)) {
return createProductOperator(id);
}
String storageId = String.join(":", "device-product", id, version);
return new DefaultDeviceProductOperator(id,
supports,
manager.getStorage(storageId),
() -> getProductBind(id, version).values().flatMap(this::getDevice));
}
private ClusterSet getProductBind(String id, String version) {
return clusterManager
.getSet(StringUtils.isEmpty(version) ? "device-product-bind:" + id : "device-product-bind:" + id + ":" + version);
}
@Override
public Mono register(DeviceInfo deviceInfo) {
return Mono.defer(() -> {
DefaultDeviceOperator operator = createOperator(deviceInfo.getId());
operatorCache.put(operator.getDeviceId(), Mono
.just(operator)
.filterWhen(device -> device.getSelfConfig(DeviceConfigKey.productId).hasElement()));
Map configs = new HashMap<>();
Optional.ofNullable(deviceInfo.getConfiguration())
.ifPresent(configs::putAll);
Optional.ofNullable(deviceInfo.getMetadata())
.ifPresent(conf -> configs.put(DeviceConfigKey.metadata.getKey(), conf));
Optional.ofNullable(deviceInfo.getProtocol())
.ifPresent(conf -> configs.put(DeviceConfigKey.protocol.getKey(), conf));
Optional.ofNullable(deviceInfo.getProductId())
.ifPresent(conf -> configs.put(DeviceConfigKey.productId.getKey(), conf));
Optional.ofNullable(deviceInfo.getProductVersion())
.ifPresent(conf -> configs.put(DeviceConfigKey.productVersion.getKey(), conf));
return operator
.setConfigs(configs)
.then(operator.getProtocol())
.flatMap(protocol -> protocol.onDeviceRegister(operator))
//绑定设备到产品
.then(getProductBind(deviceInfo.getProductId(), deviceInfo.getProductVersion()).add(deviceInfo.getId()))
.thenReturn(operator);
});
}
@Override
public Mono register(ProductInfo productInfo) {
return Mono.defer(() -> {
DefaultDeviceProductOperator operator = createProductOperator(productInfo.getId(), productInfo.getVersion());
String cacheId = createProductCacheKey(productInfo.getId(), productInfo.getVersion());
productOperatorMap.put(cacheId, operator);
Map configs = new HashMap<>();
Optional.ofNullable(productInfo.getConfiguration())
.ifPresent(configs::putAll);
Optional.ofNullable(productInfo.getMetadata())
.ifPresent(conf -> configs.put(DeviceConfigKey.metadata.getKey(), conf));
Optional.ofNullable(productInfo.getProtocol())
.ifPresent(conf -> configs.put(DeviceConfigKey.protocol.getKey(), conf));
Optional.ofNullable(productInfo.getVersion())
.ifPresent(conf -> configs.put(DeviceConfigKey.productVersion.getKey(), conf));
return operator
.setConfigs(configs)
.then(operator.getProtocol())
.flatMap(protocol -> protocol.onProductRegister(operator))
.thenReturn(operator);
});
}
@Override
public Mono unregisterDevice(String deviceId) {
return this
.getDevice(deviceId)
.flatMap(this::doUnregister)
.doFinally(r -> operatorCache.invalidate(deviceId))
.then();
}
@Override
public Mono unregisterProduct(String productId) {
return this
.getProduct(productId)
.flatMap(this::doUnregister)
.doFinally(r -> productOperatorMap.remove(createProductCacheKey(productId, null)));
}
@Override
public Mono unregisterProduct(String productId, String version) {
return this
.getProduct(productId, version)
.flatMap(this::doUnregister)
.doFinally(r -> productOperatorMap.remove(createProductCacheKey(productId, version)));
}
protected Mono doUnregister(DeviceProductOperator product) {
return product
.getProtocol()
.flatMap(protocol -> protocol.onProductUnRegister(product))
.then(
product
.unwrap(DefaultDeviceProductOperator.class)
.getReactiveStorage()
.flatMap(ConfigStorage::clear)
)
.then();
}
protected Mono doUnregister(DeviceOperator device) {
return device
.getProtocol()
.flatMap(protocol -> protocol.onDeviceUnRegister(device))
.then(
device
.unwrap(DefaultDeviceOperator.class)
.getReactiveStorage()
.flatMap(ConfigStorage::clear)
)
.then();
}
public void addInterceptor(DeviceMessageSenderInterceptor interceptor) {
this.interceptor.addInterceptor(interceptor);
}
public void addStateChecker(DeviceStateChecker deviceStateChecker) {
this.stateChecker.addDeviceStateChecker(deviceStateChecker);
}
public void addRpcChain(ThingRpcSupportChain chain) {
if (this.rpcChain == null) {
this.rpcChain = chain;
} else {
this.rpcChain = this.rpcChain.composite(Collections.singleton(chain));
}
}
}