package server import ( "log" "net" "go.rctt.net/solec/core" ) type User struct { Name string Conns map[net.Conn]struct{} } func NewUser(conn net.Conn, name string) User { u := User{ Name: name, Conns: make(map[net.Conn]struct{}), } u.Conns[conn] = struct{}{} return u } func (u *User) Send(payload core.Wrapper) error { for c := range u.Conns { if err := core.Send(c, payload); err != nil { return err } } return nil } func (s *Server) handleUserConn(conn net.Conn) { name, err := s.performUserAuth(conn) if err != nil { log.Println("user auth error:", err) return } s.usersMu.Lock() user, ok := s.users[name] if ok { log.Println("next connection from user:", user.Name) user.Conns[conn] = struct{}{} } else { log.Println("initial connection from user:", name) user = NewUser(conn, name) s.users[name] = user } s.usersMu.Unlock() defer func() { s.usersMu.Lock() log.Println("client disconnected: ", user.Name) delete(s.users[user.Name].Conns, conn) if len(s.users[user.Name].Conns) == 0 { log.Println("all connections closed for user:", user.Name) delete(s.users, user.Name) } s.usersMu.Unlock() }() if err := s.readInput(conn); err != nil { log.Println(err) } } func (s *Server) performUserAuth(conn net.Conn) (string, error) { clientPayload, err := core.Decode(conn) if err != nil { return "", err } clientAuth, ok := clientPayload.(core.UserAuth) if !ok { return "", core.ErrUnexpectedPayloadType } // For testing --- if clientAuth.Pass != "valid" { if err := core.Send(conn, core.Error{core.ErrorAuthFailed}); err != nil { log.Println("cannot send auth error:", err) } return "", core.ErrAuthInvalidPassword } // --- if err := core.Send(conn, core.Success{}); err != nil { return "", err } return clientAuth.Name, nil }