2014-12-08 05:43:33 -06:00
|
|
|
package whisper
|
|
|
|
|
|
|
|
import (
|
2014-12-08 06:16:50 -06:00
|
|
|
"bytes"
|
2014-12-09 17:03:50 -06:00
|
|
|
"errors"
|
2014-12-08 07:25:52 -06:00
|
|
|
"fmt"
|
2014-12-08 05:43:33 -06:00
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/p2p"
|
|
|
|
"gopkg.in/fatih/set.v0"
|
|
|
|
)
|
|
|
|
|
|
|
|
// MOVE ME
|
|
|
|
type Hash struct {
|
|
|
|
hash string
|
|
|
|
}
|
|
|
|
|
|
|
|
var EmptyHash Hash
|
|
|
|
|
|
|
|
func H(hash []byte) Hash {
|
|
|
|
return Hash{string(hash)}
|
|
|
|
}
|
|
|
|
func HS(hash string) Hash {
|
|
|
|
return Hash{hash}
|
|
|
|
}
|
|
|
|
|
2014-12-08 06:16:50 -06:00
|
|
|
func (self Hash) Compare(other Hash) int {
|
|
|
|
return bytes.Compare([]byte(self.hash), []byte(other.hash))
|
|
|
|
}
|
|
|
|
|
2014-12-08 05:43:33 -06:00
|
|
|
// MOVE ME END
|
|
|
|
|
|
|
|
const (
|
|
|
|
statusMsg = 0x0
|
|
|
|
envelopesMsg = 0x01
|
|
|
|
)
|
|
|
|
|
2014-12-09 17:03:50 -06:00
|
|
|
const DefaultTtl = 50 * time.Second
|
2014-12-08 07:25:52 -06:00
|
|
|
|
2014-12-08 05:43:33 -06:00
|
|
|
type Whisper struct {
|
|
|
|
pub, sec []byte
|
|
|
|
protocol p2p.Protocol
|
|
|
|
|
|
|
|
mmu sync.RWMutex
|
|
|
|
messages map[Hash]*Envelope
|
2014-12-09 17:03:50 -06:00
|
|
|
expiry map[uint32]*set.SetNonTS
|
2014-12-08 05:43:33 -06:00
|
|
|
|
|
|
|
quit chan struct{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(pub, sec []byte) *Whisper {
|
|
|
|
whisper := &Whisper{
|
|
|
|
pub: pub,
|
|
|
|
sec: sec,
|
|
|
|
messages: make(map[Hash]*Envelope),
|
2014-12-09 17:03:50 -06:00
|
|
|
expiry: make(map[uint32]*set.SetNonTS),
|
2014-12-08 05:43:33 -06:00
|
|
|
quit: make(chan struct{}),
|
|
|
|
}
|
|
|
|
go whisper.update()
|
|
|
|
|
2014-12-09 17:03:50 -06:00
|
|
|
msg := NewMessage([]byte(fmt.Sprintf("Hello world. This is whisper-go. Incase you're wondering; the time is %v", time.Now())))
|
|
|
|
envelope, _ := msg.Seal(DefaultPow, Opts{
|
|
|
|
Ttl: DefaultTtl,
|
|
|
|
})
|
|
|
|
if err := whisper.Send(envelope); err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
}
|
2014-12-08 07:25:52 -06:00
|
|
|
|
2014-12-08 05:43:33 -06:00
|
|
|
// p2p whisper sub protocol handler
|
|
|
|
whisper.protocol = p2p.Protocol{
|
|
|
|
Name: "shh",
|
|
|
|
Version: 2,
|
|
|
|
Length: 2,
|
|
|
|
Run: whisper.msgHandler,
|
|
|
|
}
|
|
|
|
|
|
|
|
return whisper
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *Whisper) Stop() {
|
|
|
|
close(self.quit)
|
|
|
|
}
|
|
|
|
|
2014-12-09 17:03:50 -06:00
|
|
|
func (self *Whisper) Send(envelope *Envelope) error {
|
|
|
|
return self.add(envelope)
|
2014-12-08 05:43:33 -06:00
|
|
|
}
|
|
|
|
|
2014-12-08 06:16:50 -06:00
|
|
|
// Main handler for passing whisper messages to whisper peer objects
|
2014-12-08 05:43:33 -06:00
|
|
|
func (self *Whisper) msgHandler(peer *p2p.Peer, ws p2p.MsgReadWriter) error {
|
|
|
|
wpeer := NewPeer(self, peer, ws)
|
2014-12-09 17:03:50 -06:00
|
|
|
// initialise whisper peer (handshake/status)
|
2014-12-08 05:43:33 -06:00
|
|
|
if err := wpeer.init(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2014-12-08 06:16:50 -06:00
|
|
|
// kick of the main handler for broadcasting/managing envelopes
|
2014-12-08 05:43:33 -06:00
|
|
|
go wpeer.start()
|
2014-12-08 06:16:50 -06:00
|
|
|
defer wpeer.stop()
|
2014-12-08 05:43:33 -06:00
|
|
|
|
2014-12-08 06:16:50 -06:00
|
|
|
// Main *read* loop. Writing is done by the peer it self.
|
2014-12-08 05:43:33 -06:00
|
|
|
for {
|
|
|
|
msg, err := ws.ReadMsg()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
envelope, err := NewEnvelopeFromReader(msg.Payload)
|
|
|
|
if err != nil {
|
|
|
|
peer.Infoln(err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2014-12-09 17:03:50 -06:00
|
|
|
if err := self.add(envelope); err != nil {
|
|
|
|
// TODO Punish peer here. Invalid envelope.
|
|
|
|
peer.Infoln(err)
|
|
|
|
}
|
2014-12-08 07:25:52 -06:00
|
|
|
wpeer.addKnown(envelope)
|
2014-12-08 05:43:33 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-08 06:16:50 -06:00
|
|
|
// takes care of adding envelopes to the messages pool. At this moment no sanity checks are being performed.
|
2014-12-09 17:03:50 -06:00
|
|
|
func (self *Whisper) add(envelope *Envelope) error {
|
|
|
|
if !envelope.valid() {
|
|
|
|
return errors.New("invalid pow for envelope")
|
|
|
|
}
|
|
|
|
|
2014-12-08 05:43:33 -06:00
|
|
|
self.mmu.Lock()
|
|
|
|
defer self.mmu.Unlock()
|
|
|
|
|
2014-12-09 17:03:50 -06:00
|
|
|
hash := envelope.Hash()
|
|
|
|
self.messages[hash] = envelope
|
2014-12-08 05:43:33 -06:00
|
|
|
if self.expiry[envelope.Expiry] == nil {
|
|
|
|
self.expiry[envelope.Expiry] = set.NewNonTS()
|
|
|
|
}
|
2014-12-09 17:03:50 -06:00
|
|
|
|
|
|
|
if !self.expiry[envelope.Expiry].Has(hash) {
|
|
|
|
self.expiry[envelope.Expiry].Add(hash)
|
|
|
|
// TODO notify listeners (given that we had any ...)
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println("add", envelope)
|
|
|
|
|
|
|
|
return nil
|
2014-12-08 05:43:33 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (self *Whisper) update() {
|
|
|
|
expire := time.NewTicker(800 * time.Millisecond)
|
|
|
|
out:
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-expire.C:
|
|
|
|
self.expire()
|
|
|
|
case <-self.quit:
|
|
|
|
break out
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-12-08 06:16:50 -06:00
|
|
|
|
2014-12-08 05:43:33 -06:00
|
|
|
func (self *Whisper) expire() {
|
|
|
|
self.mmu.Lock()
|
|
|
|
defer self.mmu.Unlock()
|
|
|
|
|
2014-12-09 17:03:50 -06:00
|
|
|
now := uint32(time.Now().Unix())
|
2014-12-08 05:43:33 -06:00
|
|
|
for then, hashSet := range self.expiry {
|
|
|
|
if then > now {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
hashSet.Each(func(v interface{}) bool {
|
|
|
|
delete(self.messages, v.(Hash))
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
self.expiry[then].Clear()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *Whisper) envelopes() (envelopes []*Envelope) {
|
|
|
|
self.mmu.RLock()
|
|
|
|
defer self.mmu.RUnlock()
|
|
|
|
|
|
|
|
envelopes = make([]*Envelope, len(self.messages))
|
|
|
|
i := 0
|
|
|
|
for _, envelope := range self.messages {
|
|
|
|
envelopes[i] = envelope
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *Whisper) Protocol() p2p.Protocol {
|
|
|
|
return self.protocol
|
|
|
|
}
|