github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/whisper/whisperv2/filter.go (about) 1 // Copyright 2014 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The Spectrum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Contains the message filter for fine grained subscriptions. 18 19 package whisperv2 20 21 import ( 22 "crypto/ecdsa" 23 24 "github.com/SmartMeshFoundation/Spectrum/event/filter" 25 ) 26 27 // Filter is used to subscribe to specific types of whisper messages. 28 type Filter struct { 29 To *ecdsa.PublicKey // Recipient of the message 30 From *ecdsa.PublicKey // Sender of the message 31 Topics [][]Topic // Topics to filter messages with 32 Fn func(msg *Message) // Handler in case of a match 33 } 34 35 // NewFilterTopics creates a 2D topic array used by whisper.Filter from binary 36 // data elements. 37 func NewFilterTopics(data ...[][]byte) [][]Topic { 38 filter := make([][]Topic, len(data)) 39 for i, condition := range data { 40 // Handle the special case of condition == [[]byte{}] 41 if len(condition) == 1 && len(condition[0]) == 0 { 42 filter[i] = []Topic{} 43 continue 44 } 45 // Otherwise flatten normally 46 filter[i] = NewTopics(condition...) 47 } 48 return filter 49 } 50 51 // NewFilterTopicsFlat creates a 2D topic array used by whisper.Filter from flat 52 // binary data elements. 53 func NewFilterTopicsFlat(data ...[]byte) [][]Topic { 54 filter := make([][]Topic, len(data)) 55 for i, element := range data { 56 // Only add non-wildcard topics 57 filter[i] = make([]Topic, 0, 1) 58 if len(element) > 0 { 59 filter[i] = append(filter[i], NewTopic(element)) 60 } 61 } 62 return filter 63 } 64 65 // NewFilterTopicsFromStrings creates a 2D topic array used by whisper.Filter 66 // from textual data elements. 67 func NewFilterTopicsFromStrings(data ...[]string) [][]Topic { 68 filter := make([][]Topic, len(data)) 69 for i, condition := range data { 70 // Handle the special case of condition == [""] 71 if len(condition) == 1 && condition[0] == "" { 72 filter[i] = []Topic{} 73 continue 74 } 75 // Otherwise flatten normally 76 filter[i] = NewTopicsFromStrings(condition...) 77 } 78 return filter 79 } 80 81 // NewFilterTopicsFromStringsFlat creates a 2D topic array used by whisper.Filter from flat 82 // binary data elements. 83 func NewFilterTopicsFromStringsFlat(data ...string) [][]Topic { 84 filter := make([][]Topic, len(data)) 85 for i, element := range data { 86 // Only add non-wildcard topics 87 filter[i] = make([]Topic, 0, 1) 88 if element != "" { 89 filter[i] = append(filter[i], NewTopicFromString(element)) 90 } 91 } 92 return filter 93 } 94 95 // filterer is the internal, fully initialized filter ready to match inbound 96 // messages to a variety of criteria. 97 type filterer struct { 98 to string // Recipient of the message 99 from string // Sender of the message 100 matcher *topicMatcher // Topics to filter messages with 101 fn func(data interface{}) // Handler in case of a match 102 } 103 104 // Compare checks if the specified filter matches the current one. 105 func (self filterer) Compare(f filter.Filter) bool { 106 filter := f.(filterer) 107 108 // Check the message sender and recipient 109 if len(self.to) > 0 && self.to != filter.to { 110 return false 111 } 112 if len(self.from) > 0 && self.from != filter.from { 113 return false 114 } 115 // Check the topic filtering 116 topics := make([]Topic, len(filter.matcher.conditions)) 117 for i, group := range filter.matcher.conditions { 118 // Message should contain a single topic entry, extract 119 for topics[i] = range group { 120 break 121 } 122 } 123 return self.matcher.Matches(topics) 124 } 125 126 // Trigger is called when a filter successfully matches an inbound message. 127 func (self filterer) Trigger(data interface{}) { 128 self.fn(data) 129 }