Set.Each, also builtin Channel broadcast goroutine

This commit is contained in:
Andrey Petrov 2014-12-22 21:47:07 -08:00
parent 7beb7f99bb
commit a1d5cc6735
4 changed files with 31 additions and 26 deletions

View File

@ -3,6 +3,7 @@ package chat
import "fmt" import "fmt"
const historyLen = 20 const historyLen = 20
const channelBuffer = 10
// Channel definition, also a Set of User Items // Channel definition, also a Set of User Items
type Channel struct { type Channel struct {
@ -10,19 +11,35 @@ type Channel struct {
topic string topic string
history *History history *History
users *Set users *Set
broadcast chan<- Message broadcast chan Message
} }
func NewChannel(id string, broadcast chan<- Message) *Channel { // Create new channel and start broadcasting goroutine.
func NewChannel(id string) *Channel {
broadcast := make(chan Message, channelBuffer)
ch := Channel{ ch := Channel{
id: id, id: id,
broadcast: broadcast, broadcast: broadcast,
history: NewHistory(historyLen), history: NewHistory(historyLen),
users: NewSet(), users: NewSet(),
} }
go func() {
for m := range broadcast {
ch.users.Each(func(u Item) {
u.(*User).Send(m)
})
}
}()
return &ch return &ch
} }
func (ch *Channel) Close() {
close(ch.broadcast)
}
func (ch *Channel) Send(m Message) { func (ch *Channel) Send(m Message) {
ch.broadcast <- m ch.broadcast <- m
} }

View File

@ -8,20 +8,12 @@ import (
func TestChannel(t *testing.T) { func TestChannel(t *testing.T) {
var expected, actual []byte var expected, actual []byte
out := make(chan Message)
defer close(out)
s := &MockScreen{} s := &MockScreen{}
u := NewUser("foo") u := NewUser("foo")
go func() { ch := NewChannel("")
for msg := range out { defer ch.Close()
t.Logf("Broadcasted: ", msg.String())
u.Send(msg)
}
}()
ch := NewChannel("", out)
err := ch.Join(u) err := ch.Join(u)
if err != nil { if err != nil {
t.Error(err) t.Error(err)

View File

@ -24,18 +24,5 @@ func (h *Host) broadcast(ch *Channel, m Message) {
} }
func (h *Host) CreateChannel(id string) *Channel { func (h *Host) CreateChannel(id string) *Channel {
out := make(chan Message, 20) return NewChannel(id)
ch := NewChannel(id, out)
go func() {
for msg := range out {
if msg.IsCommand() {
go h.handleCommand(msg)
continue
}
h.broadcast(ch, msg)
}
}()
return ch
} }

View File

@ -87,6 +87,15 @@ func (s *Set) Remove(item Item) error {
return nil return nil
} }
// Loop over every item while holding a read lock and apply fn
func (s *Set) Each(fn func(item Item)) {
s.RLock()
for _, item := range s.lookup {
fn(item)
}
s.RUnlock()
}
// List users by prefix, case insensitive // List users by prefix, case insensitive
func (s *Set) ListPrefix(prefix string) []Item { func (s *Set) ListPrefix(prefix string) []Item {
r := []Item{} r := []Item{}