|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|