diff --git a/cmd/client/main.go b/cmd/client/main.go index 5673cb2..38cce29 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -1,15 +1,23 @@ package main import ( + "context" "crypto/tls" "crypto/x509" "fmt" + "io" "log" + "net" "os" + "sync" + "time" + "git.qowevisa.me/Qowevisa/gotell/communication" "git.qowevisa.me/Qowevisa/gotell/env" ) +var messageChannel chan ([]byte) + func main() { host, err := env.GetHost() if err != nil { @@ -42,22 +50,49 @@ func main() { defer conn.Close() log.Println("client: connected to: ", conn.RemoteAddr()) + ctx, cancel := context.WithCancel(context.Background()) + wg := &sync.WaitGroup{} + wg.Add(1) + go func(ctx context.Context, wg *sync.WaitGroup) { + defer wg.Done() // Mark this goroutine as done when it exits + buf := make([]byte, 1024) + for { + select { + case <-ctx.Done(): // Check if context cancellation has been requested + return + default: + timeoutDuration := 5 * time.Second + err := conn.SetReadDeadline(time.Now().Add(timeoutDuration)) + if err != nil { + panic(err) + } + n, err := conn.Read(buf) + if err != nil { + if err != io.EOF { + if netErr, ok := err.(net.Error); ok && netErr.Timeout() { + continue + } + panic(err) + } + return + } + messageChannel <- buf[:n] + } + } + }(ctx, wg) + go func() { + for message := range messageChannel { + msg, err := communication.Decode(message) + if err != nil { + log.Printf("ERROR: %v\n", err) + } + switch msg.From { + case communication.FROM_SERVER: - message := "Hello secure Server\n" - n, err := conn.Write([]byte(message)) - if err != nil { - log.Fatalf("client: write: %s", err) - } - - log.Printf("client: wrote %q (%d bytes)", message, n) - - reply := make([]byte, 256) - n, err = conn.Read(reply) - if err != nil { - log.Fatalf("client: read: %s", err) - } - - log.Printf("client: read %q (%d bytes)", string(reply[:n]), n) - - log.Print("client: exiting") + case communication.FROM_CLIENT: + } + } + }() + cancel() + wg.Wait() } diff --git a/cmd/server/main.go b/cmd/server/main.go index 9c00f07..b0e4c27 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -3,16 +3,18 @@ package main import ( "crypto/rand" "crypto/tls" + "encoding/binary" "fmt" "io" "log" "net" - "git.qowevisa.me/Qowevisa/gotell/communication" + com "git.qowevisa.me/Qowevisa/gotell/communication" "git.qowevisa.me/Qowevisa/gotell/env" ) func main() { + userCenter.Init() host, err := env.GetHost() if err != nil { log.Fatal(err) @@ -53,7 +55,7 @@ func main() { func handleClient(conn net.Conn) { defer conn.Close() buf := make([]byte, 512) - ask, err := communication.AskClientNickname() + ask, err := com.ServerAskClientAboutNickname() if err != nil { log.Printf("ERROR: %#v\n", err) } else { @@ -72,18 +74,41 @@ func handleClient(conn net.Conn) { } break } - answer := append([]byte("Hello! I see your message:"), buf[:n]...) - msg, err := communication.JustGetMessage(answer) + msg, err := com.Decode(buf[:n]) if err != nil { log.Printf("ERROR: %#v\n", err) continue } - log.Printf("server: conn: sending %#v\n", msg) - _, err = conn.Write(msg) - if err != nil { - log.Printf("server: conn: write: %s", err) - break + if msg == nil { + log.Printf("ERROR MSG IS NIL\n") + continue } + log.Printf("server: conn: receive %#v\n", *msg) + // Handle + switch msg.ID { + case com.ID_CLIENT_SEND_SERVER_NICKNAME: + id, err := userCenter.AddUser(string(msg.Data)) + if err != nil { + answ, err := com.ServerSendClientDecline() + if err != nil { + log.Printf("ERROR: %v\n", err) + continue + } + conn.Write(answ) + } else { + idBytes := make([]byte, 4) + binary.BigEndian.PutUint32(idBytes, uint32(id)) + answ, err := com.ServerSendClientHisID(idBytes) + if err != nil { + log.Printf("ERROR: %v\n", err) + continue + } + conn.Write(answ) + } + case com.ID_CLIENT_SEND_SERVER_LINK: + default: + } + // Handle } log.Println("server: conn: closed") } diff --git a/cmd/server/users.go b/cmd/server/users.go new file mode 100644 index 0000000..a5c7e6a --- /dev/null +++ b/cmd/server/users.go @@ -0,0 +1,64 @@ +package main + +import ( + "errors" + "math/rand" + "sync" +) + +var ( + userCenter UserCenter +) + +type UserCenter struct { + UsersSTOI map[string]int32 + UsersITOS map[int32]string + Mu sync.Mutex +} + +func (u *UserCenter) Init() { + u.UsersSTOI = make(map[string]int32) + u.UsersITOS = make(map[int32]string) +} + +var ( + ERROR_ALREADY_HAVE = errors.New("Username is already taken") + ERROR_DONT_HAVE = errors.New("Username was not found") +) + +func (u *UserCenter) AddUser(name string) (int32, error) { + u.Mu.Lock() + defer u.Mu.Unlock() + _, alreadyHave := u.UsersSTOI[name] + if alreadyHave { + return -1, ERROR_ALREADY_HAVE + } + var ret int32 + for { + rInt := rand.Int31() + _, taken := u.UsersITOS[rInt] + if !taken { + ret = rInt + break + } + } + u.UsersITOS[ret] = name + u.UsersSTOI[name] = ret + return ret, nil +} + +func (u *UserCenter) GetID(name string) (int32, error) { + id, have := u.UsersSTOI[name] + if !have { + return -1, ERROR_DONT_HAVE + } + return id, nil +} + +func (u *UserCenter) GetName(id int32) (string, error) { + name, have := u.UsersITOS[id] + if !have { + return "", ERROR_DONT_HAVE + } + return name, nil +}