mirror of
https://github.com/yuelwish/mqtt-bridge.git
synced 2025-09-27 04:36:10 +08:00
148 lines
3.7 KiB
Go
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
|
|
}
|