You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

182 lines
3.7 KiB

package peer
import (
"atomic"
"sync"
)
/* Peer */
type Peer struct {
outgoing bool
conn *Connection
channels map[String]*Channel
mtx sync.Mutex
quit chan struct{}
stopped uint32
}
func (p *Peer) Start(peerInQueues map[String]chan *InboundMsg ) {
for chName, _ := range p.channels {
go p.inHandler(chName, peerInQueues[chName])
go p.outHandler(chName)
}
}
func (p *Peer) Stop() {
// lock
p.mtx.Lock()
if atomic.CompareAndSwapUint32(&p.stopped, 0, 1) {
close(p.quit)
p.conn.Stop()
}
p.mtx.Unlock()
// unlock
}
func (p *Peer) LocalAddress() *NetAddress {
return p.conn.LocalAddress()
}
func (p *Peer) RemoteAddress() *NetAddress {
return p.conn.RemoteAddress()
}
func (p *Peer) Channel(chName String) *Channel {
return p.channels[chName]
}
// If msg isn't already in the peer's filter, then
// queue the msg for output.
// If the queue is full, just return false.
func (p *Peer) TryQueueOut(chName String, msg Msg) bool {
channel := p.Channel(chName)
outQueue := channel.OutQueue()
// just return if already in filter
if channel.Filter().Has(msg) {
return true
}
// lock & defer
p.mtx.Lock(); defer p.mtx.Unlock()
if p.stopped == 1 { return false }
select {
case outQueue <- msg:
return true
default: // buffer full
return false
}
// unlock deferred
}
func (p *Peer) WriteTo(w io.Writer) (n int64, err error) {
return p.RemoteAddress().WriteTo(w)
}
func (p *Peer) inHandler(chName String, inboundMsgQueue chan<- *InboundMsg) {
channel := p.channels[chName]
inQueue := channel.InQueue()
FOR_LOOP:
for {
select {
case <-quit:
break FOR_LOOP
case msg := <-inQueue:
// add to channel filter
channel.Filter().Add(msg)
// send to inboundMsgQueue
inboundMsg := &InboundMsg{
Peer: p,
Channel: channel,
Time: Time(time.Now()),
Msg: msg,
}
select {
case <-quit:
break FOR_LOOP
case inboundMsgQueue <- inboundMsg:
continue
}
}
}
// cleanup
// (none)
}
func (p *Peer) outHandler(chName String) {
outQueue := p.channels[chName].OutQueue()
FOR_LOOP:
for {
select {
case <-quit:
break FOR_LOOP
case msg := <-outQueue:
// blocks until the connection is Stop'd,
// which happens when this peer is Stop'd.
p.conn.QueueOut(msg.Bytes)
}
}
// cleanup
// (none)
}
/* Channel */
type Channel struct {
name String
mtx sync.Mutex
filter Filter
inQueue chan Msg
outQueue chan Msg
//stats Stats
}
func NewChannel(name String, filter Filter, in, out chan Msg) *Channel {
return &Channel{
name: name,
filter: filter,
inQueue: in,
outQueue: out,
}
}
func (c *Channel) InQueue() <-chan Msg {
return c.inQueue
}
func (c *Channel) OutQueue() chan<- Msg {
return c.outQueue
}
func (c *Channel) Add(msg Msg) {
c.Filter().Add(msg)
}
func (c *Channel) Has(msg Msg) bool {
return c.Filter().Has(msg)
}
// TODO: maybe don't expose this
func (c *Channel) Filter() Filter {
// lock & defer
c.mtx.Lock(); defer c.mtx.Unlock()
return c.filter
// unlock deferred
}
// TODO: maybe don't expose this
func (c *Channel) UpdateFilter(filter Filter) {
// lock
c.mtx.Lock()
c.filter = filter
c.mtx.Unlock()
// unlock
}