diff --git a/chat/channel.go b/chat/channel.go index f26dbf2..180dada 100644 --- a/chat/channel.go +++ b/chat/channel.go @@ -3,6 +3,7 @@ package chat import "fmt" const historyLen = 20 +const channelBuffer = 10 // Channel definition, also a Set of User Items type Channel struct { @@ -10,19 +11,35 @@ type Channel struct { topic string history *History 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{ id: id, broadcast: broadcast, history: NewHistory(historyLen), users: NewSet(), } + + go func() { + for m := range broadcast { + ch.users.Each(func(u Item) { + u.(*User).Send(m) + }) + } + }() + return &ch } +func (ch *Channel) Close() { + close(ch.broadcast) +} + func (ch *Channel) Send(m Message) { ch.broadcast <- m } diff --git a/chat/channel_test.go b/chat/channel_test.go index 5ff2fb4..f261081 100644 --- a/chat/channel_test.go +++ b/chat/channel_test.go @@ -8,20 +8,12 @@ import ( func TestChannel(t *testing.T) { var expected, actual []byte - out := make(chan Message) - defer close(out) - s := &MockScreen{} u := NewUser("foo") - go func() { - for msg := range out { - t.Logf("Broadcasted: ", msg.String()) - u.Send(msg) - } - }() + ch := NewChannel("") + defer ch.Close() - ch := NewChannel("", out) err := ch.Join(u) if err != nil { t.Error(err) diff --git a/chat/host.go b/chat/host.go index ce8c905..9834ed4 100644 --- a/chat/host.go +++ b/chat/host.go @@ -24,18 +24,5 @@ func (h *Host) broadcast(ch *Channel, m Message) { } func (h *Host) CreateChannel(id string) *Channel { - out := make(chan Message, 20) - ch := NewChannel(id, out) - - go func() { - for msg := range out { - if msg.IsCommand() { - go h.handleCommand(msg) - continue - } - h.broadcast(ch, msg) - } - }() - - return ch + return NewChannel(id) } diff --git a/chat/set.go b/chat/set.go index d4442d7..8c01f87 100644 --- a/chat/set.go +++ b/chat/set.go @@ -87,6 +87,15 @@ func (s *Set) Remove(item Item) error { 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 func (s *Set) ListPrefix(prefix string) []Item { r := []Item{}