protohackers/cmd/budgetchat/main.go

86 lines
1.4 KiB
Go

package main
import (
"bufio"
"fmt"
"log"
"net"
"protohackers/pkg/conn"
)
type message struct {
msg []byte
client *client
}
func msg(s string, c *client) message {
return message{[]byte(s), c}
}
var (
room = make([]*client, 0)
messages = make(chan message, 32)
)
func main() {
go broadcast()
err := conn.StartSimple(newUserHandler)
if err != nil {
log.Fatalln(err)
}
}
func broadcast() {
for {
select {
case m := <-messages:
for _, cl := range room {
if m.client == cl {
continue
}
cl.sendMessage(m.msg)
}
}
}
}
func userList() []byte {
m := "* The room contains: "
if len(room) > 0 {
for _, c := range room {
m += fmt.Sprintf("%s, ", c.name)
}
m = m[:len(m)-2]
}
return []byte(m + "\n")
}
func newUserHandler(c net.Conn) {
cl, err := newClient(c)
if err != nil {
return
}
cl.sendMessage(userList())
fmt.Printf("New client %s\n", cl.name)
messages <- msg(fmt.Sprintf("* %s has entered the room\n", cl.name), cl)
room = append(room, cl)
input := bufio.NewScanner(cl.c)
for input.Scan() {
m := fmt.Sprintf("[%s] %s\n", cl.name, input.Text())
messages <- msg(m, cl)
}
for i, p := range room {
if p == cl {
name := cl.name
cl.c.Close()
room = append(room[:i], room[i+1:]...)
fmt.Printf("%s has left", cl.name)
messages <- msg(fmt.Sprintf("* %s has left the room\n", name), cl)
break
}
}
}