whisper: refactored message processing

This commit is contained in:
Vlad 2016-12-07 15:28:40 +01:00
parent 2dcf75a722
commit e47820d164
5 changed files with 74 additions and 12 deletions

View file

@ -55,6 +55,22 @@ func APIs() []rpc.API {
} }
} }
// Start starts the Whisper worker threads.
func (api *PublicWhisperAPI) Start() error {
if api.whisper == nil {
return whisperOffLineErr
}
return api.whisper.Start(nil)
}
// Stop stops the Whisper worker threads.
func (api *PublicWhisperAPI) Stop() error {
if api.whisper == nil {
return whisperOffLineErr
}
return api.whisper.Stop()
}
// Version returns the Whisper version this node offers. // Version returns the Whisper version this node offers.
func (api *PublicWhisperAPI) Version() (*rpc.HexNumber, error) { func (api *PublicWhisperAPI) Version() (*rpc.HexNumber, error) {
if api.whisper == nil { if api.whisper == nil {

View file

@ -277,6 +277,9 @@ func TestIntegrationAsym(t *testing.T) {
t.Fatalf("failed to create API.") t.Fatalf("failed to create API.")
} }
api.Start()
defer api.Stop()
sig, err := api.NewIdentity() sig, err := api.NewIdentity()
if err != nil { if err != nil {
t.Fatalf("failed NewIdentity: %s.", err) t.Fatalf("failed NewIdentity: %s.", err)
@ -375,6 +378,9 @@ func TestIntegrationSym(t *testing.T) {
t.Fatalf("failed to create API.") t.Fatalf("failed to create API.")
} }
api.Start()
defer api.Stop()
keyname := "schluessel" keyname := "schluessel"
err := api.GenerateSymKey(keyname) err := api.GenerateSymKey(keyname)
if err != nil { if err != nil {
@ -471,6 +477,9 @@ func TestIntegrationSymWithFilter(t *testing.T) {
t.Fatalf("failed to create API.") t.Fatalf("failed to create API.")
} }
api.Start()
defer api.Stop()
keyname := "schluessel" keyname := "schluessel"
err := api.GenerateSymKey(keyname) err := api.GenerateSymKey(keyname)
if err != nil { if err != nil {

View file

@ -76,6 +76,10 @@ func (fs *Filters) Get(i uint32) *Filter {
} }
func (fs *Filters) NotifyWatchers(env *Envelope, messageCode uint64) { func (fs *Filters) NotifyWatchers(env *Envelope, messageCode uint64) {
if env == nil {
return
}
fs.mutex.RLock() fs.mutex.RLock()
var msg *ReceivedMessage var msg *ReceivedMessage
for _, watcher := range fs.watchers { for _, watcher := range fs.watchers {

View file

@ -118,6 +118,7 @@ func initialize(t *testing.T) {
var node TestNode var node TestNode
node.shh = NewWhisper(nil) node.shh = NewWhisper(nil)
node.shh.test = true node.shh.test = true
node.shh.Start(nil)
topics := make([]TopicType, 0) topics := make([]TopicType, 0)
topics = append(topics, sharedTopic) topics = append(topics, sharedTopic)
f := Filter{KeySym: sharedKey, Topics: topics} f := Filter{KeySym: sharedKey, Topics: topics}
@ -166,6 +167,7 @@ func stopServers() {
n := nodes[i] n := nodes[i]
if n != nil { if n != nil {
n.shh.Unwatch(n.filerId) n.shh.Unwatch(n.filerId)
n.shh.Stop()
n.server.Stop() n.server.Stop()
} }
} }

View file

@ -22,6 +22,7 @@ import (
crand "crypto/rand" crand "crypto/rand"
"crypto/sha256" "crypto/sha256"
"fmt" "fmt"
"runtime"
"sync" "sync"
"time" "time"
@ -35,6 +36,11 @@ import (
set "gopkg.in/fatih/set.v0" set "gopkg.in/fatih/set.v0"
) )
type QueueItem struct {
hash common.Hash
code uint64
}
// Whisper represents a dark communication interface through the Ethereum // Whisper represents a dark communication interface through the Ethereum
// network, using its very own P2P communication layer. // network, using its very own P2P communication layer.
type Whisper struct { type Whisper struct {
@ -55,7 +61,9 @@ type Whisper struct {
mailServer MailServer mailServer MailServer
quit chan struct{} messageQueue chan QueueItem
quit chan struct{}
test bool test bool
} }
@ -63,14 +71,15 @@ type Whisper struct {
// Param s should be passed if you want to implement mail server, otherwise nil. // Param s should be passed if you want to implement mail server, otherwise nil.
func NewWhisper(server MailServer) *Whisper { func NewWhisper(server MailServer) *Whisper {
whisper := &Whisper{ whisper := &Whisper{
privateKeys: make(map[string]*ecdsa.PrivateKey), privateKeys: make(map[string]*ecdsa.PrivateKey),
symKeys: make(map[string][]byte), symKeys: make(map[string][]byte),
envelopes: make(map[common.Hash]*Envelope), envelopes: make(map[common.Hash]*Envelope),
messages: make(map[common.Hash]*ReceivedMessage), messages: make(map[common.Hash]*ReceivedMessage),
expirations: make(map[uint32]*set.SetNonTS), expirations: make(map[uint32]*set.SetNonTS),
peers: make(map[*Peer]struct{}), peers: make(map[*Peer]struct{}),
mailServer: server, mailServer: server,
quit: make(chan struct{}), messageQueue: make(chan QueueItem, 1024),
quit: make(chan struct{}),
} }
whisper.filters = NewFilters(whisper) whisper.filters = NewFilters(whisper)
@ -270,6 +279,12 @@ func (w *Whisper) Send(envelope *Envelope) error {
func (w *Whisper) Start(*p2p.Server) error { func (w *Whisper) Start(*p2p.Server) error {
glog.V(logger.Info).Infoln("Whisper started") glog.V(logger.Info).Infoln("Whisper started")
go w.update() go w.update()
numCPU := runtime.NumCPU()
for i := 0; i < numCPU; i++ {
go w.processQueue()
}
return nil return nil
} }
@ -444,14 +459,30 @@ func (wh *Whisper) add(envelope *Envelope) error {
return nil return nil
} }
// postEvent delivers the message to the watchers. // postEvent queues the message for further processing.
func (w *Whisper) postEvent(envelope *Envelope, messageCode uint64) { func (w *Whisper) postEvent(envelope *Envelope, messageCode uint64) {
// if the version of incoming message is higher than // if the version of incoming message is higher than
// currently supported version, we can not decrypt it, // currently supported version, we can not decrypt it,
// and therefore just ignore this message // and therefore just ignore this message
if envelope.Ver() <= EnvelopeVersion { if envelope.Ver() <= EnvelopeVersion {
// todo: review if you need an additional thread here i := QueueItem{hash: envelope.Hash(), code: messageCode}
go w.filters.NotifyWatchers(envelope, messageCode) w.messageQueue <- i
}
}
// processQueue delivers the messages to the watchers during the lifetime of the whisper node.
func (w *Whisper) processQueue() {
for {
select {
case <-w.quit:
return
case i := <-w.messageQueue:
w.poolMu.Lock()
e := w.envelopes[i.hash]
w.poolMu.Unlock()
w.filters.NotifyWatchers(e, i.code)
}
} }
} }