97 lines
1.6 KiB
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"))
|
|
}
|