summaryrefslogtreecommitdiffstats
path: root/server/user.go
blob: 5d2731c68f5fcc436db27d48c2b415cb1e13fb88 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
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
}