-
Notifications
You must be signed in to change notification settings - Fork 318
/
topic.go
144 lines (130 loc) · 3.59 KB
/
topic.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package common
import (
"strings"
)
type subject interface {
getValue() string
}
// normalSubject
type normalSubject struct {
value string
}
// singleWildcardSubject
type singleWildcardSubject struct {
value string
}
// multipleWildcardSubject
type multipleWildcardSubject struct {
value string
}
func (n normalSubject) getValue() string {
return n.value
}
func (s singleWildcardSubject) getValue() string {
return s.value
}
func (m multipleWildcardSubject) getValue() string {
return m.value
}
// getTopicSubjects convert topic to []subject by subject kind
func getTopicSubjects(topic string) []subject {
var subjectList []subject
var topicList = strings.Split(topic, "/")
for _, value := range topicList {
switch value {
case SingleWildCard:
subjectList = append(subjectList, interface{}(singleWildcardSubject{value}).(subject))
case MultipleWildCard:
subjectList = append(subjectList, interface{}(multipleWildcardSubject{value}).(subject))
default:
subjectList = append(subjectList, interface{}(normalSubject{value}).(subject))
}
}
return subjectList
}
// TopicIsMatch check the given topicRule is matched the given topic or not
func TopicIsMatch(topic string, topicRule string) bool {
topicSubjects := getTopicSubjects(topic)
topicRuleSubjects := getTopicSubjects(topicRule)
topicSubjectsLength := len(topicSubjects)
topicRuleSubjectsLength := len(topicRuleSubjects)
var minLength int
if topicSubjectsLength < topicRuleSubjectsLength {
minLength = topicSubjectsLength
} else {
minLength = topicRuleSubjectsLength
}
for i := 0; i < minLength; i++ {
topicSubject := topicSubjects[i]
topicRuleSubject := topicRuleSubjects[i]
if strings.Compare(topicRuleSubject.getValue(), MultipleWildCard) == 0 {
return true
}
if strings.Compare(topicRuleSubject.getValue(), SingleWildCard) != 0 &&
strings.Compare(topicRuleSubject.getValue(), topicSubject.getValue()) != 0 {
return false
}
}
if topicSubjectsLength > minLength {
return false
}
if topicRuleSubjectsLength > minLength &&
strings.Compare(topicRuleSubjects[minLength].getValue(), MultipleWildCard) != 0 {
return false
}
return true
}
// ContainsWildcard check topic contains wildCard("#" or "+") or not
func ContainsWildcard(topic string) bool {
return strings.Contains(topic, SingleWildCard) || strings.Contains(topic, MultipleWildCard)
}
// isSysTopic check topic is SysTopic or not
func isSysTopic(topic string) bool {
return strings.HasPrefix(topic, SysCmdPrefix)
}
// PubTopicValidate validate MQTT publish topic
func PubTopicValidate(topic string) bool {
if topic == "" {
return false
}
if len(topic) > MaxTopicNameLen || strings.Contains(topic, "\u0000") ||
strings.Count(topic, TopicSeparator) > MaxSlashCount {
return false
}
if ContainsWildcard(topic) {
return false
}
if isSysTopic(topic) {
return false
}
return true
}
// SubTopicValidate validate MQTT subscribe topic
func SubTopicValidate(topic string) bool {
if topic == "" {
return false
}
if len(topic) > MaxTopicNameLen || strings.Contains(topic, "\u0000") ||
strings.Count(topic, TopicSeparator) > MaxSlashCount {
return false
}
if isSysTopic(topic) {
return false
}
splited := strings.Split(topic, TopicSeparator)
for index := 0; index < len(splited); index++ {
s := splited[index]
if strings.EqualFold(s, MultipleWildCard) {
// check that multi is the last symbol
if index != len(splited)-1 {
return false
}
} else if strings.Contains(s, MultipleWildCard) {
return false
} else if !strings.EqualFold(s, SingleWildCard) &&
strings.Contains(s, SingleWildCard) {
return false
}
}
return true
}