aboutsummaryrefslogtreecommitdiffstats
path: root/whisper/topic.go
diff options
context:
space:
mode:
Diffstat (limited to 'whisper/topic.go')
-rw-r--r--whisper/topic.go117
1 files changed, 109 insertions, 8 deletions
diff --git a/whisper/topic.go b/whisper/topic.go
index a965c7cc2..b2a264e29 100644
--- a/whisper/topic.go
+++ b/whisper/topic.go
@@ -27,6 +27,26 @@ func NewTopics(data ...[]byte) []Topic {
return topics
}
+// NewTopicFilter creates a 2D topic array used by whisper.Filter from binary
+// data elements.
+func NewTopicFilter(data ...[][]byte) [][]Topic {
+ filter := make([][]Topic, len(data))
+ for i, condition := range data {
+ filter[i] = NewTopics(condition...)
+ }
+ return filter
+}
+
+// NewTopicFilterFlat creates a 2D topic array used by whisper.Filter from flat
+// binary data elements.
+func NewTopicFilterFlat(data ...[]byte) [][]Topic {
+ filter := make([][]Topic, len(data))
+ for i, element := range data {
+ filter[i] = []Topic{NewTopic(element)}
+ }
+ return filter
+}
+
// NewTopicFromString creates a topic using the binary data contents of the
// specified string.
func NewTopicFromString(data string) Topic {
@@ -43,19 +63,100 @@ func NewTopicsFromStrings(data ...string) []Topic {
return topics
}
+// NewTopicFilterFromStrings creates a 2D topic array used by whisper.Filter
+// from textual data elements.
+func NewTopicFilterFromStrings(data ...[]string) [][]Topic {
+ filter := make([][]Topic, len(data))
+ for i, condition := range data {
+ filter[i] = NewTopicsFromStrings(condition...)
+ }
+ return filter
+}
+
+// NewTopicFilterFromStringsFlat creates a 2D topic array used by whisper.Filter from flat
+// binary data elements.
+func NewTopicFilterFromStringsFlat(data ...string) [][]Topic {
+ filter := make([][]Topic, len(data))
+ for i, element := range data {
+ filter[i] = []Topic{NewTopicFromString(element)}
+ }
+ return filter
+}
+
// String converts a topic byte array to a string representation.
func (self *Topic) String() string {
return string(self[:])
}
-// TopicSet represents a hash set to check if a topic exists or not.
-type topicSet map[string]struct{}
+// topicMatcher is a filter expression to verify if a list of topics contained
+// in an arriving message matches some topic conditions. The topic matcher is
+// built up of a list of conditions, each of which must be satisfied by the
+// corresponding topic in the message. Each condition may require: a) an exact
+// topic match; b) a match from a set of topics; or c) a wild-card matching all.
+//
+// If a message contains more topics than required by the matcher, those beyond
+// the condition count are ignored and assumed to match.
+//
+// Consider the following sample topic matcher:
+// sample := {
+// {TopicA1, TopicA2, TopicA3},
+// {TopicB},
+// nil,
+// {TopicD1, TopicD2}
+// }
+// In order for a message to pass this filter, it should enumerate at least 4
+// topics, the first any of [TopicA1, TopicA2, TopicA3], the second mandatory
+// "TopicB", the third is ignored by the filter and the fourth either "TopicD1"
+// or "TopicD2". If the message contains further topics, the filter will match
+// them too.
+type topicMatcher struct {
+ conditions []map[Topic]struct{}
+}
+
+// newTopicMatcher create a topic matcher from a list of topic conditions.
+func newTopicMatcher(topics ...[]Topic) *topicMatcher {
+ matcher := make([]map[Topic]struct{}, len(topics))
+ for i, condition := range topics {
+ matcher[i] = make(map[Topic]struct{})
+ for _, topic := range condition {
+ matcher[i][topic] = struct{}{}
+ }
+ }
+ return &topicMatcher{conditions: matcher}
+}
+
+// newTopicMatcherFromBinary create a topic matcher from a list of binary conditions.
+func newTopicMatcherFromBinary(data ...[][]byte) *topicMatcher {
+ topics := make([][]Topic, len(data))
+ for i, condition := range data {
+ topics[i] = NewTopics(condition...)
+ }
+ return newTopicMatcher(topics...)
+}
+
+// newTopicMatcherFromStrings creates a topic matcher from a list of textual
+// conditions.
+func newTopicMatcherFromStrings(data ...[]string) *topicMatcher {
+ topics := make([][]Topic, len(data))
+ for i, condition := range data {
+ topics[i] = NewTopicsFromStrings(condition...)
+ }
+ return newTopicMatcher(topics...)
+}
-// NewTopicSet creates a topic hash set from a slice of topics.
-func newTopicSet(topics []Topic) topicSet {
- set := make(map[string]struct{})
- for _, topic := range topics {
- set[topic.String()] = struct{}{}
+// Matches checks if a list of topics matches this particular condition set.
+func (self *topicMatcher) Matches(topics []Topic) bool {
+ // Mismatch if there aren't enough topics
+ if len(self.conditions) > len(topics) {
+ return false
+ }
+ // Check each topic condition for existence (skip wild-cards)
+ for i := 0; i < len(topics) && i < len(self.conditions); i++ {
+ if len(self.conditions[i]) > 0 {
+ if _, ok := self.conditions[i][topics[i]]; !ok {
+ return false
+ }
+ }
}
- return topicSet(set)
+ return true
}