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

103 lines
1.6 KiB
Go

package cm
import (
"net"
"strings"
)
type Manager struct {
active map[net.Conn]bool
connect chan net.Conn
disconnect chan net.Conn
write chan writeOp
}
func New() *Manager {
m := &Manager{
active: make(map[net.Conn]bool, 10),
connect: make(chan net.Conn),
disconnect: make(chan net.Conn),
write: make(chan writeOp),
}
go m.run()
return m
}
func (m *Manager) run() {
for {
select {
case conn := <-m.connect:
m.active[conn] = true
case conn := <-m.disconnect:
conn.Close()
delete(m.active, conn)
case op := <-m.write:
m.broadcast(op)
}
}
}
func (m *Manager) broadcast(op writeOp) {
var res writeResponse
for conn, _ := range m.active {
res.add(conn.Write(op.data))
}
op.reply <- res
}
func (m *Manager) Add(conn net.Conn) {
m.connect <- conn
}
func (m *Manager) Remove(conn net.Conn) {
m.disconnect <- conn
}
func (m *Manager) Write(b []byte) (int, error) {
op := *newWriteOp(b)
m.write <- op
res := <-op.reply
return res.i, res.e
}
type multiError []error
func (e multiError) add(err error) {
if e == nil {
e = make([]error, 0, 4)
}
e = append(e, err)
}
func (e multiError) Error() string {
messages := make([]string, len(e))
for i, _ := range e {
messages[i] = e[i].Error()
}
return strings.Join(messages, " | ")
}
type writeResponse struct {
i int
e multiError
}
func (res writeResponse) add(n int, e error) {
if e != nil {
res.e.add(e)
}
res.i += n
}
type writeOp struct {
data []byte
reply chan writeResponse
}
func newWriteOp(b []byte) *writeOp {
return &writeOp{
data: b,
reply: make(chan writeResponse),
}
}