Files
mqtt-bridge/engine/engine_helper.go
2022-09-04 00:47:12 +08:00

148 lines
3.7 KiB
Go

package engine
import (
"github.com/pkg/errors"
)
func NewEngineHelper() *EngineHelper {
e := new(EngineHelper)
e.filterMap = make(map[string]*TopicFilter, 10)
e.cliAddrMap = make(map[string]*MqttAddress, 7)
e.routers = make([]*Router, 0, 7)
return e
}
type EngineHelper struct {
cliAddrMap map[string]*MqttAddress // 客户端 key: tag Value: 客户端连接信息
filterMap map[string]*TopicFilter // topic filter key: tag Value: 要操作的 topic
routers []*Router
}
func (e *EngineHelper) AddTopicFilter(tag string, qos byte, filter ...string) error {
v, ok := e.filterMap[tag]
if ok {
return errors.Errorf("already exists tag: %v", tag)
} else {
e.filterMap[tag] = v
}
e.filterMap[tag] = &TopicFilter{
Tag: tag,
Qos: qos,
Filter: filter,
}
return nil
}
type MqttOption func(*MqttAddress)
func (m *EngineHelper) AddClient(tag string, address string, opts ...MqttOption) error {
if _, ok := m.cliAddrMap[tag]; ok {
return errors.Errorf("already exists tag: %v", tag)
}
var it = &MqttAddress{
Address: address,
}
for _, opt := range opts {
opt(it)
}
m.cliAddrMap[tag] = it
return nil
}
func (e *EngineHelper) AddRouting(fromTags, toTags, topicTags []string) {
e.routers = append(e.routers, &Router{
FromTags: fromTags,
ToTags: toTags,
TopicTags: topicTags,
})
}
func (e *EngineHelper) BuildEngine() (*Engine, error) {
var (
cliSubMap = make(map[string][]*SubTopic, 7) // 客户端tag : 订阅的topicFilter
filterTree = NewTopicFilterTree() // filterTree 用于匹配接收的topic
toTopicMap = make(map[string][]string, 7) // 来源tag和topicFilter 对应接收的 tags
)
// 构建 客户端tag : 订阅的topicFilter
for _, router := range e.routers {
var (
fromTags = router.FromTags
topicTags = router.TopicTags
)
for _, cTag := range fromTags {
_, ok := cliSubMap[cTag]
if !ok {
cliSubMap[cTag] = make([]*SubTopic, 0, 7)
}
for _, tTag := range topicTags {
topicFilter, ok := e.filterMap[tTag]
if !ok {
return nil, errors.Errorf("")
}
filters := make([]*SubTopic, 0, len(topicFilter.Filter))
for _, topic := range topicFilter.Filter {
filters = append(filters, &SubTopic{
Topic: topic,
Qos: topicFilter.Qos,
})
}
cliSubMap[cTag] = append(cliSubMap[cTag], filters...)
}
}
}
// 构建 filterTree
// 按 / 作为分割, 将得到的数组组装成树形结构
for _, router := range e.routers { // 1. 循环 处理路由
for _, topicTag := range router.TopicTags { // 2. 循环路由 中 topicTag
tFilters, ok := e.filterMap[topicTag]
if !ok {
return nil, errors.Errorf("routing 未知的 topicTag %s", topicTag)
}
filterTree.AddFilter(tFilters.Filter...)
}
}
// 构建 确定来源和filter 对应的 目标 tags
for _, router := range e.routers { // 1. 循环路由
var (
fromTags = router.FromTags
toTags = router.ToTags
topicTags = router.TopicTags
)
for _, topicTag := range topicTags { // 2. 循环路由中的 topicTag
topicFilter, ok := e.filterMap[topicTag]
if !ok {
return nil, errors.Errorf("routing 未知的 topicTag %s", topicTag)
}
for _, topic := range topicFilter.Filter { // 3. 循环 topicTag 中的 filter
for _, fTag := range fromTags { // 4. 为每一个fromTag 创建 key, 并把路由所有的 toTag 作为 Value
key := fTag + "-" + topic
v, ok := toTopicMap[key]
if !ok {
v = make([]string, 0, 7)
toTopicMap[key] = v
}
toTopicMap[key] = append(toTopicMap[key], toTags...)
}
}
}
}
return &Engine{
cliAddrMap: e.cliAddrMap,
cliSubMap: cliSubMap,
filterTree: filterTree,
toTopicMap: toTopicMap,
MessageChan: make(chan *Message, 1024),
}, nil
}