|
package main |
|
|
|
import ( |
|
"fmt" |
|
"net" |
|
"strings" |
|
"sync" |
|
) |
|
|
|
type message struct { |
|
user []byte |
|
body []byte |
|
} |
|
|
|
type client struct { |
|
user []byte |
|
client net.Conn |
|
close chan struct{} |
|
} |
|
type room struct { |
|
m chan message |
|
clients []*client |
|
clientsMutex sync.Mutex // RWMutex might make more sense. Maybe. |
|
} |
|
|
|
func (c *client) sendMsg(b []byte) { |
|
fmt.Fprintf(c.client, "%s %s\n", c.user, b) |
|
} |
|
|
|
func (c *client) hear(msg message) { |
|
fmt.Fprintf(c.client, "%s: %s", msg.user, msg.body) |
|
} |
|
|
|
func (r *room) handleConnection(conn net.Conn) { |
|
|
|
reqLen, err := fmt.Fprintf(conn, "Username: ") |
|
if err != nil { |
|
fmt.Println(err) |
|
} |
|
|
|
buf := make([]byte, 1024) |
|
reqLen, err = conn.Read(buf) |
|
user := client{ |
|
user: ([]byte)(strings.TrimSpace(string(buf[0:reqLen]))), |
|
client: conn, |
|
} |
|
|
|
r.addClient(user) |
|
fmt.Fprintf(conn, "You've logged on as %s\n", user.user) |
|
for { |
|
reqLen, err := conn.Read(buf) |
|
if err != nil { |
|
fmt.Println(err) |
|
} |
|
if strings.TrimSpace(string(buf[0:reqLen])) == "/quit" { |
|
|
|
conn.Close() |
|
return // can't write to this connection any more |
|
} |
|
m := message{ |
|
user: user.user, |
|
body: buf[0:(reqLen - 1)], |
|
} |
|
r.m <- m |
|
} |
|
} |
|
|
|
func (r *room) addClient(c client) { |
|
//r.clientsMutex.Lock() |
|
//defer r.clientsMutex.Unlock() |
|
for i := range r.clients { |
|
fmt.Fprintf(r.clients[i].client, "%s has joined \n", c.user) |
|
} |
|
fmt.Fprintf(c.client, "Participants: %#v.\n", r.clients) |
|
r.clients = append(r.clients, &c) |
|
} |
|
|
|
func (r *room) broadcastMsg(m message) { |
|
for i := range r.clients { |
|
r.clients[i].hear(m) |
|
} |
|
} |
|
|
|
func (r *room) broadcast() { |
|
for { |
|
select { |
|
case i := <-r.m: |
|
r.broadcastMsg(i) |
|
} |
|
} |
|
} |
|
|
|
func (r *room) listener() { |
|
ln, err := net.Listen("tcp", ":9000") |
|
if err != nil { |
|
fmt.Println(err) |
|
} |
|
go r.broadcast() |
|
for { |
|
conn, err := ln.Accept() |
|
if err != nil { |
|
fmt.Println(err) |
|
continue |
|
} |
|
go r.handleConnection(conn) |
|
} |
|
|
|
} |
|
|
|
func main() { |
|
oneRoomToRuleThemAll := room{ |
|
m: make(chan message), |
|
} |
|
oneRoomToRuleThemAll.listener() |
|
} |
https://gist.github.com/anachronistic/4046c54ce1c46e2f0ddd