protohackers/cmd/budgetchat/client.go

97 lines
1.6 KiB
Go

package main
import (
"errors"
"fmt"
"log"
"net"
"regexp"
"strings"
)
type client struct {
c net.Conn
name string
}
func isValidName(name string) bool {
pattern := "^[a-zA-Z0-9]+$"
nameReg, err := regexp.Compile(pattern)
if err != nil {
log.Fatalln(err)
}
return nameReg.MatchString(name)
}
func cleanString(buf []byte) string {
s := string(buf)
idx := strings.Index(s, "\n")
if idx != -1 {
s = s[:idx]
}
return s
}
func newClient(c net.Conn) (*client, error) {
cl := &client{
c: c,
name: "",
}
cl.sendMessageString("Welcome to budgetchat! What shall I call you?")
r := make(chan string, 1)
var err error = nil
go func() {
for {
buf := make([]byte, 32)
_, err = c.Read(buf)
if err != nil {
c.Close()
r <- ""
return
}
name := cleanString(buf)
// Check legality
if !isValidName(name) {
cl.sendMessageString("The name %s is invalid", string(name))
err = errors.New("name invalid")
c.Close()
r <- name
return
}
// Check for duplicate name
for _, cls := range room {
if cls.name == name {
cl.sendMessageString("The name %s is already taken", string(name))
err = errors.New("name already taken")
c.Close()
r <- name
return
}
}
r <- name
return
}
}()
cl.name = <-r
if err != nil {
return nil, err
}
return cl, nil
}
func (cl *client) sendMessage(m []byte) {
_, err := cl.c.Write(m)
if err != nil {
log.Fatalln(err)
}
}
func (cl *client) sendMessageString(m string, vars ...any) {
cl.sendMessage([]byte(fmt.Sprintf(m, vars...) + "\n"))
}