package peer
|
|
|
|
import (
|
|
. "github.com/tendermint/tendermint/binary"
|
|
"github.com/tendermint/tendermint/merkle"
|
|
"sync"
|
|
"io"
|
|
)
|
|
|
|
/* Client */
|
|
type Client struct {
|
|
listener *Listener
|
|
addrBook AddrBook
|
|
strategies map[String]*FilterStrategy
|
|
targetNumPeers int
|
|
|
|
peersMtx sync.Mutex
|
|
peers merkle.Tree // addr -> *Peer
|
|
|
|
filtersMtx sync.Mutex
|
|
filters merkle.Tree // channelName -> Filter (objects that I know of)
|
|
}
|
|
|
|
func NewClient(protocol string, laddr string) *Client {
|
|
// XXX set the handler
|
|
listener := NewListener(protocol, laddr, nil)
|
|
c := &Client{
|
|
listener: listener,
|
|
peers: merkle.NewIAVLTree(nil),
|
|
filters: merkle.NewIAVLTree(nil),
|
|
}
|
|
return c
|
|
}
|
|
|
|
func (c *Client) Start() (<-chan *IncomingMsg) {
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) Stop() {
|
|
c.listener.Close()
|
|
}
|
|
|
|
func (c *Client) LocalAddress() *NetAddress {
|
|
return c.listener.LocalAddress()
|
|
}
|
|
|
|
func (c *Client) ConnectTo(addr *NetAddress) (*Peer, error) {
|
|
|
|
conn, err := addr.Dial()
|
|
if err != nil { return nil, err }
|
|
peer := NewPeer(conn)
|
|
|
|
// lock
|
|
c.peersMtx.Lock()
|
|
c.peers.Put(addr, peer)
|
|
c.peersMtx.Unlock()
|
|
// unlock
|
|
|
|
return peer, nil
|
|
}
|
|
|
|
func (c *Client) Broadcast(channel String, msg Binary) {
|
|
for v := range c.peersCopy().Values() {
|
|
peer, ok := v.(*Peer)
|
|
if !ok { panic("Expected peer but got something else") }
|
|
peer.Queue(channel, msg)
|
|
}
|
|
}
|
|
|
|
// Updates the client's filter for a channel & broadcasts it.
|
|
func (c *Client) UpdateFilter(channel String, filter Filter) {
|
|
c.filtersMtx.Lock()
|
|
c.filters.Put(channel, filter)
|
|
c.filtersMtx.Unlock()
|
|
|
|
c.Broadcast("", &NewFilterMsg{
|
|
Channel: channel,
|
|
Filter: filter,
|
|
})
|
|
}
|
|
|
|
func (c *Client) peersCopy() merkle.Tree {
|
|
c.peersMtx.Lock(); defer c.peersMtx.Unlock()
|
|
return c.peers.Copy()
|
|
}
|
|
|
|
|
|
/* Channel */
|
|
type Channel struct {
|
|
Name String
|
|
Filter Filter
|
|
//Stats Stats
|
|
}
|
|
|
|
|
|
/* Peer */
|
|
type Peer struct {
|
|
Conn *Connection
|
|
Channels map[String]*Channel
|
|
}
|
|
|
|
func NewPeer(conn *Connection) *Peer {
|
|
return &Peer{
|
|
Conn: conn,
|
|
Channels: nil,
|
|
}
|
|
}
|
|
|
|
// Must be quick and nonblocking.
|
|
func (p *Peer) Queue(channel String, msg Binary) {}
|
|
|
|
func (p *Peer) WriteTo(w io.Writer) (n int64, err error) {
|
|
return 0, nil // TODO
|
|
}
|
|
|
|
|
|
/* IncomingMsg */
|
|
type IncomingMsg struct {
|
|
SPeer *Peer
|
|
SChan *Channel
|
|
|
|
Time Time
|
|
|
|
Msg Binary
|
|
}
|
|
|
|
|
|
/* Filter
|
|
|
|
A Filter could be a bloom filter for lossy filtering, or could be a lossless filter.
|
|
Either way, it's used to keep track of what a peer knows of.
|
|
*/
|
|
type Filter interface {
|
|
Binary
|
|
Add(ByteSlice)
|
|
Has(ByteSlice) bool
|
|
}
|
|
|
|
/* FilterStrategy
|
|
|
|
Defines how filters are generated per peer, and whether they need to get refreshed occasionally.
|
|
*/
|
|
type FilterStrategy interface {
|
|
LoadFilter(ByteSlice) Filter
|
|
}
|
|
|
|
/* NewFilterMsg */
|
|
type NewFilterMsg struct {
|
|
Channel String
|
|
Filter Filter
|
|
}
|
|
|
|
func (m *NewFilterMsg) WriteTo(w io.Writer) (int64, error) {
|
|
return 0, nil // TODO
|
|
}
|