JetLinks物联网平台源码解读

设备接入逻辑

在这里插入图片描述
组件模块里面有两个要重点关注的子模块

  1. 第一个是网关模块
    网关的主要功能是对网络组件产生的消息进行管理并支持发布到总线以支持订阅,对网络组件产生的连接进行认证,对网络组件连接产生的会话进行管理,还有对这些操作进行监控。由于网关的消息处理依赖网络组件,所以网关关于消息处理这部分内容的实现都放到了网络组件里面实现,这里对网关行为进行抽象。但是,一些相关处理,例如监控、发布订阅这里有具体的实现。
  2. 第二个是网络组件模块
    网络组件一般是对一些第三方的网络组件包进行二次封装、提供平台的统一收发消息接口。同时,这里会对每一种类型的网络组件提供一个网关的实现。

MqttServerDeviceGateway

在这里插入图片描述
这个mqtt服务器网关里面组合了几个重要类

  1. MqttServer 是连接、会话、消息产生的源头。
  2. DeviceRegistry 保存在数据库设备在发布后会注册到这里,所以这个类主要是作用获取发布后的设备,并进行操作。
  3. DecodedClientMessageHandler 把转换后的平台消息发布到总线。DeviceMessageConnector是它的实现类。
  4. DeviceGatewayHelper 这个类里面描述了设备消息会话有怎样的影响
  5. DeviceSessionManager 设备会话管理,DeviceSessionManager.compute是经常用来判断是否session该更新还是该创建
    public Mono<DeviceSession> compute(@Nonnull String deviceId, Mono<DeviceSession> creator, Function<DeviceSession, Mono<DeviceSession>> updater) {
        DeviceSessionRef ref = (DeviceSessionRef)this.localSessions.compute(deviceId, (_id, old) -> {
            if (old == null) {
                return creator == null ? null : new DeviceSessionRef(_id, this, creator);
            } else if (updater == null) {
                return old;
            } else {
                old.update((s) -> {
                    return s.flatMap(updater);
                });
                return old;
            }
        });
        return ref == null ? Mono.empty() : ref.ref();
    }

BrokerEventBus

所在包:org.jetlinks.core.event
JetLinks的消息总线,对topic消息体进行发布和订阅,但是直接发给设备的topic是不经过消息总线的。

平台向设备发消息

DefaultDeviceOperator

所在包:org.jetlinks.core.defaults
设备操作器,向设备发送消息是可通过此类获取消息发送器,设备信息等。

public class DefaultDeviceOperator implements DeviceOperator, StorageConfigurable {
    private static final Logger log = LoggerFactory.getLogger(DefaultDeviceOperator.class);
    public static final DeviceStateChecker DEFAULT_STATE_CHECKER = (device) -> {
        return checkState0((DefaultDeviceOperator)device);
    };
    private static final ConfigKey<Long> lastMetadataTimeKey = ConfigKey.of("lst_metadata_time");
    static final List<String> productIdAndVersionKey;
    private static final AtomicReferenceFieldUpdater<DefaultDeviceOperator, DeviceMetadata> METADATA_UPDATER;
    private static final AtomicLongFieldUpdater<DefaultDeviceOperator> METADATA_TIME_UPDATER;
    private final String id;
    private final DeviceOperationBroker handler;
    private final DeviceRegistry registry;
    private final DeviceMessageSender messageSender; // 消息发送器,使用的实现是 DefaultDeviceMessageSender
    private final Mono<ConfigStorage> storageMono;
    private final Mono<ProtocolSupport> protocolSupportMono;
    private final Mono<DeviceMetadata> metadataMono;
    private final DeviceStateChecker stateChecker;
    private final Mono<DeviceProductOperator> parent;
    private volatile long lastMetadataTime;
    private volatile DeviceMetadata metadataCache;
    private ThingRpcSupportChain rpcChain;
    private static final List<String> stateCacheKeys;
    //...省略
}

DefaultDeviceMessageSender

发消息会用到DeviceOperationBroker,使用的实现是EventBusDeviceOperationBroker

public class DefaultDeviceMessageSender implements DeviceMessageSender {
    private static final Logger log = LoggerFactory.getLogger(DefaultDeviceMessageSender.class);
    private final DeviceOperationBroker handler; // 实际发送消息是用的这个类,使用的实现是EventBusDeviceOperationBroker
    private final DeviceOperator operator;
    private final DeviceRegistry registry;
    private static final long DEFAULT_TIMEOUT;
    private long defaultTimeout;
    private final DeviceMessageSenderInterceptor globalInterceptor;
    //...省略
}
    public <R extends DeviceMessage> Flux<R> send(Publisher<? extends DeviceMessage> message, Function<Object, R> replyMapping) {
        return Mono.zip(this.operator.getConnectionServerId().switchIfEmpty(this.refreshAndGetConnectionServerId()).defaultIfEmpty(""), this.operator.getProtocol().flatMap(ProtocolSupport::getSenderInterceptor).defaultIfEmpty(DeviceMessageSenderInterceptor.DO_NOTING), this.operator.getSelfConfig(DeviceConfigKey.parentGatewayId).defaultIfEmpty("")).flatMapMany((serverAndInterceptor) -> {
            DeviceMessageSenderInterceptor interceptor = ((DeviceMessageSenderInterceptor)serverAndInterceptor.getT2()).andThen(this.globalInterceptor);
            String server = (String)serverAndInterceptor.getT1();
            String parentGatewayId = (String)serverAndInterceptor.getT3();
            return StringUtils.isEmpty(server) && StringUtils.hasText(parentGatewayId) ? Flux.from(message).flatMap((msg) -> {
                return interceptor.preSend(this.operator, msg);
            }).flatMap((msg) -> {
                return (Flux)this.sendToParentDevice(parentGatewayId, msg).as((flux) -> {
                    return interceptor.afterSent(this.operator, msg, interceptor.doSend(this.operator, msg, flux));
                });
            }).map((r) -> {
                return r;
            }) : Flux.from(message).flatMap((msg) -> {
                return interceptor.preSend(this.operator, msg);
            }).concatMap((msg) -> {
                return (Flux)Flux.defer(() -> {
                    DeviceMessageTracer.trace(msg, "send.before");
                    if (StringUtils.isEmpty(server)) {
                        return interceptor.afterSent(this.operator, msg, Flux.error(new DeviceOperationException(ErrorCode.CLIENT_OFFLINE)));
                    } else {
                        boolean forget = (Boolean)msg.getHeader(Headers.sendAndForget).orElse(false);
                        Flux<R> replyStream = forget ? Flux.empty() : ((Flux)this.handler.handleReply(msg.getDeviceId(), msg.getMessageId(), Duration.ofMillis((Long)msg.getHeader(Headers.timeout).orElse(this.defaultTimeout))).map(replyMapping).onErrorResume(DeviceOperationException.class, (error) -> {
                            return error.getCode() == ErrorCode.CLIENT_OFFLINE ? this.operator.checkState().then(Mono.error(error)) : Mono.error(error);
                        }).onErrorMap(TimeoutException.class, (timeout) -> {
                            return new DeviceOperationException(ErrorCode.TIME_OUT, timeout);
                        }).as((flux) -> {
                            return this.logReply(msg, flux);
                        })).cache();
                        // 发送消息的逻辑在这里
                        return this.handler.send(server, Mono.just(msg)).defaultIfEmpty(-1).flatMapMany((len) -> {
                            if (len == 0) {
                                return this.operator.checkState().flatMapMany((state) -> {
                                    if (1 != state) {
                                        return interceptor.afterSent(this.operator, msg, Flux.error(new DeviceOperationException(ErrorCode.CLIENT_OFFLINE)));
                                    } else if (StringUtils.hasText(parentGatewayId)) {
                                        log.debug("Device [{}] Cached Server [{}] Not Available,Dispatch To Parent [{}]", new Object[]{this.operator.getDeviceId(), server, parentGatewayId});
                                        return interceptor.afterSent(this.operator, msg, this.sendToParentDevice(parentGatewayId, msg)).map((r) -> {
                                            return r;
                                        });
                                    } else {
                                        log.warn("Device [{}] Cached Server [{}] Not Available", this.operator.getDeviceId(), server);
                                        return interceptor.afterSent(this.operator, msg, Flux.error(new DeviceOperationException(ErrorCode.SERVER_NOT_AVAILABLE)));
                                    }
                                });
                            } else if (len == -1) {
                                return interceptor.afterSent(this.operator, msg, Flux.error(new DeviceOperationException(ErrorCode.CLIENT_OFFLINE)));
                            } else {
                                log.debug("send device[{}] message complete", this.operator.getDeviceId());
                                return interceptor.afterSent(this.operator, msg, replyStream);
                            }
                        }).doOnNext((r) -> {
                            DeviceMessageTracer.trace(r, "send.reply");
                        });
                    }
                }).as((flux) -> {
                    return interceptor.doSend(this.operator, msg, flux.cast(DeviceMessage.class)).map((_resp) -> {
                        return _resp;
                    });
                });
            });
        });
    }

EventBusDeviceOperationBroker

  • send:发送消息给设备会先发一条 /_sys/msg-broker/ 消息到消息总线,再由消息总线统一发送消息给设备。
  • handleSendToDeviceMessage: 系统启动的时候会订阅 /_sys/msg-broker/ 消息
    public Mono<Integer> send(String deviceGatewayServerId, Publisher<? extends Message> message) {
        return this.eventBus.publish("/_sys/msg-broker/" + deviceGatewayServerId, messageCodec, Flux.from(message).doOnNext((msg) -> {
            msg.addHeader(Headers.sendFrom, this.serverId);
        })).map(Long::intValue);
    }
    public Flux<Message> handleSendToDeviceMessage(String serverId) {
        Subscription subscription = Subscription.of("device-message-broker", new String[]{"/_sys/msg-broker/" + serverId}, new Subscription.Feature[]{Feature.local, Feature.broker});
        return this.eventBus.subscribe(subscription, messageCodec).doOnNext((message) -> {
            if (message instanceof RepayableDeviceMessage && !(Boolean)message.getHeader(Headers.sendAndForget).orElse(false)) {
                boolean isSameServer = (Boolean)message.getHeader(Headers.sendFrom).map((sendFrom) -> {
                    return sendFrom.equals(serverId);
                }).orElse(false);
                if (!isSameServer) {
                    this.awaits.put(this.getAwaitReplyKey((RepayableDeviceMessage)message), (RepayableDeviceMessage)message);
                }
            }

        });
    }

DefaultSendToDeviceMessageHandler

启动的时候会订阅 /_sys/msg-broker/ 消息,并注册消费者发送消息给设备

public class DefaultSendToDeviceMessageHandler {
    private static final Logger log = LoggerFactory.getLogger(DefaultSendToDeviceMessageHandler.class);
    private final String serverId;
    private final DeviceSessionManager sessionManager;
    private final MessageHandler handler; // 使用的实现是 EventBusDeviceOperationBroker
    private final DeviceRegistry registry;
    private final DecodedClientMessageHandler decodedClientMessageHandler;

    public void startup() {
        // 启动的时候会调用这里的逻辑
        // this.handler.handleSendToDeviceMessage 是向EventBus里面增加一个订阅/_sys/msg-broker/的订阅
        // 然后注册订阅者,订阅者会调用handleDeviceMessage()方法,该方法获取DeviceSession后发送消息
        this.handler.handleSendToDeviceMessage(this.serverId).subscribe((message) -> {
            try {
                if (message instanceof DeviceMessage) {
                    this.handleDeviceMessage((DeviceMessage)message);
                }
            } catch (Throwable var3) {
                log.error("handle send to device message error {}", message, var3);
            }

        });
        this.handler.handleGetDeviceState(this.serverId, (deviceId) -> {
            return Flux.from(deviceId).map((id) -> {
                return new DeviceStateInfo(id, (byte)(this.sessionManager.sessionIsAlive(id) ? 1 : -1));
            });
        });
    }

    protected void handleDeviceMessage(DeviceMessage message) {
        String deviceId = message.getDeviceId();
        DeviceSession session = this.sessionManager.getSession(deviceId);
        if (session != null) {
            this.doSend(message, session);
        }
        // ...省略
    }

真正的设备消息发送逻辑

//TODO

        DeviceSession deviceSession;
        MqttConnectionSession mqttConnectionSession; // DeviceSession 的实现
        MqttEndpoint mqttEndpoint;
        MqttConnection mqttConnection;
        VertxMqttConnection vertxMqttConnection; // MqttConnection  的实现

使用webscoket订阅平台消息

//TODO

        DefaultMessagingManager defaultMessagingManager; // 保存所有平台的订阅信息
        WebSocketMessagingHandler webSocketMessagingHandler; // 向DefaultMessagingManager注册消费者,获取所有消息并推送给websocket客户端
  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JetLinks开源物联网平台基于Java8、Spring Boot 2.x、WebFlux、Netty、Vert.x、Reactor等开发,是一个开箱即用,可二次开发的企业物联网基础平台。平台实现了物联网相关的众多基础功能,能帮助你快速建立物联网相关业务系统。 JetLinks开源物联网平台核心特性: 支持统一物模型管理,多种设备,多种厂家,统一管理。 统一设备连接管理,多协议适配(TCP、MQTT、UDP、CoAP、HTTP等),屏蔽网络编程复杂性,灵活接入不同厂家不同协议的设备。 灵活的规则引擎,设备告警,消息通知,数据转发。可基于SQL进行复杂的数据处理逻辑。 地理位置:统一管理地理位置信息,支持区域搜索。 数据可视化:实现拖拽配置数据图表,设备组态等。 JetLinks开源物联网平台技术栈: Spring Boot 2.2.x Spring WebFlux 响应式Web支持 R2DBC 响应式关系型数据库驱动 Project Reactor 响应式编程框架 Netty、Vert.x 高性能网络编程框架 ElasticSearch 全文检索,日志,时序数据存储 PostgreSQL 业务功能数据管理 hsweb framework 4 业务功能基础框架     JetLinks开源物联网平台 更新日志: v1.9 1、增加设备独立物模型支持,可给单独的设备配置物模型. 2、基本实现GB28181国标视频设备接入,支持直播,云台控制,级联操作.(选配模块) 3、RabbitMQ增加routeKey配置,可在配置文件中指定device.message.writer.rabbitmq.consumer-route-key和device.message.writer.rabbitmq.producer-route-key.(Pro) 4、当设置了device.message.writer.rabbitmq.consumer=false时,不创建MQ消费者.(Pro) 5、设备支持独立物模型,可单独配置设备的物模型. 6、适配tdengine 2.0.16.0,优化sql长度策略. (pro) 7、优化规则引擎编辑器,实现组件模块化动态加载.(Pro) 8、修复启动服务时,如果某个产品物模型发布失败,导致后面的产品终止发布的问题. 9、增加ignoreLatest消息头,message.addHeader("ignoreLatest",true) 忽略记录最新数据到数据库. 10、修复租户下操作设备告警提示无权限.(Pro) 11、优化租户在解绑成员时,同时解绑成员的资产信息.(Pro) 12、优化子设备消息回复处理 13、物模型属性增加存储方式功能,可配置部分属性不存储. 14、增加虚拟属性功能,可通过规则来计算出虚拟属性值.(Pro) 15、增加租户成员绑定(TenantMemberBindEvent),解绑(TenantMemberUnBindEvent)事件.可通过spring-event订阅处理此事件.(Pro) 16、优化子设备状态检查,当检查子设备状态时,将会尝试发送ChildDeviceMessage<DeviceStateCheckMessage>给网关,处理后返回ChildDeviceMessageReply<DeviceStateCheckMessageReply>. 17、增加ClickHouse设备数据存储策略支持.(Pro) 18、增加权限过滤功能,可配置禁止赋予自己没有的权限给其他用户.hsweb.permission.filter相关配置 19、设备和产品的租户绑定逻辑优化: 绑定设备时,自动绑定产品.解绑产品时,自动解绑设备.(Pro) 20、用户管理增加租户权限控制.(Pro) 21、当向keepOnline的设备发送消息时,如果原始连接已断开,将返回CONNECTION_LOST错误. 22、设置keepOnline的会话将被持久化,重启服务后自动恢复.(Pro) 23、默认关闭设备最新数据存储,通过jetlinks.device.storage.enable-last-data-in-db=true开启.(Pro) 24、属性物模型增加属性值来源,配置为手动时,在发送修改属性指令(WritePropertyMessage)时,将直接生效,不会发送到设备. 25、优化租户资产解绑逻辑,当删除数据时,解绑资产全部的绑定关系.(Pro) 26、用户管理,机构管理增加租户端支持,租户可以自己管理自己的用户和机构.(Pro)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值