ICCSREST 设计与实现
ICCSREST
A RESTful interface for Tango.
一、概述
ICCSREST是基于现代WEB标准的 Tango WEB 服务。
它提供了用于订阅 attribute 的 websocket 通信,以及对 Tango 设备服务进行常规操作的 RESTful 接口。
目前支持的功能有:
- 支持对于 attribute 的订阅,包括 CHANGE、PERIODIC、ARCHIVE、ALARM、USER、DATA_READY、ATTR_CONF、INTERFACE_CHANGE 八种模式
- 支持对于 Tango 设备服务的基本信息以及 attribute、command、property 的常规操作
- 支持用户认证和对 Tango hosts 的访问控制
二、整体架构
ICCSREST主要分为3个模块,2个功能模块HTTP Controllers,事件订阅和1个支撑模块设备代理缓存。每个主模块下有一些小的功能模块。
HTTP Controllers包含多个HTTP Controller,一种类别的API则抽象为一个控制器,例如设备的property的相关api就抽象为一个单独的控制器。每个控制器主要包含下列几个子模块:过滤器(权限控制和简单的参数过滤),路由匹配,数据处理。
事件订阅模块主要包含三个子模块:1.websocket控制器,用于管理websocket连接的生命周期包括建立,消息接收发送,终止。 2.事件处理器,继承自callback类,订阅TANGO事件触发时的回调对象。 3.drogon提供给我们的一个订阅-发布工具,用于向用户分发事件触发的数据
设备代理缓存管理模块是一个设备工厂的单例类,通过LRU-K算法进行缓存队列的淘汰管理
三、HTTP Controllers
上图是调用RESTful API时的一个时序图,大致的处理流程就是:
- 用户 -> Filters过滤,剔除非法请求 -> 控制器进行路由匹配调用相关的处理函数 -> 处理函数向TANGO获取真实的数据,对数据进行处理后返回给用户
四、事件订阅
在websocket控制器中,每个websocket连接会维护一个结构体DrogonSubscriber
,保存用户、连接的名称和每个连接订阅的事件。
以一个用户订阅CHANGE事件为例:
- websocket建立后,用户发送特定格式的json消息给websocket控制器
- websocket控制器解析无误后,判断相应事件的事件处理器(TangoEventHandler)是否存在,不存在就要创建一个对应的事件处理器,创建时TANGO事件对应的subscribe_id会保存在TangoEventHandler内部
- 随后需要通过PubSubService订阅这个事件,这个事件的SubscriberID会保存在DrogonSubscriber中用于后续订阅的取消
- 当事件触发时,TangoEventHandler中的push_event函数就会触发,在这个函数内部我们会对数据进行处理,然后通过PubSubService分发给所有订阅了该事件的用户
五、设备代理缓存管理
其他模块请求设备代理都是通过DeviceFactory
这个单例类,DeviceFactory主要包含3个数据结构,一个hash表,2个队列。哈希表中的K/V对象为设备名称和一个结构体DeviceEntry
,DeviceEntry
包含历史访问次数,是否可驱逐标记,队列位置信息以及设备代理对象。2个队列的存储对象都是设备名称。
LRU-K算法的主要流程如图所示:
- 首先从哈希表中判断相应设备代理是否存在,如果存在则返回并调整相应的设备代理的位置,调整策略:
-
hit_count
自增1,如果hit_count
小于k则不做调整;如果hit_count
等于k,则将设备名称从history_list
移动自cache_list
的队头;如果大于k,则将设备名称从cache_list
的任意位置移动到其队头
- 如果设备代理不存在,则需要创建一个设备代理并将入到哈希表中,并且将其名称推送到
history_list
的队头,如果此时的缓存容量已经超出了最大容量,则需要剔除掉一个设备代理,剔除策略: -
- 依次从
history_list
和cache_list
的队尾向队头查找,第一个可驱逐的对象就会淘汰。
- 依次从