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