aboutsummaryrefslogtreecommitdiff
path: root/hotline/chat.go
blob: dcde1d3a2466e6baaee4505812598f0cdaca0b46 (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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package hotline

import (
	"crypto/rand"
	"github.com/stretchr/testify/mock"
	"slices"
	"sync"
)

type PrivateChat struct {
	Subject    string
	ClientConn map[[2]byte]*ClientConn
}

type ChatID [4]byte

type ChatManager interface {
	New(cc *ClientConn) ChatID
	GetSubject(id ChatID) string
	Join(id ChatID, cc *ClientConn)
	Leave(id ChatID, clientID [2]byte)
	SetSubject(id ChatID, subject string)
	Members(id ChatID) []*ClientConn
}

type MemChatManager struct {
	chats map[ChatID]*PrivateChat

	mu sync.Mutex
}

func NewMemChatManager() *MemChatManager {
	return &MemChatManager{
		chats: make(map[ChatID]*PrivateChat),
	}
}

func (cm *MemChatManager) New(cc *ClientConn) ChatID {
	cm.mu.Lock()
	defer cm.mu.Unlock()

	var randID [4]byte
	_, _ = rand.Read(randID[:])

	cm.chats[randID] = &PrivateChat{ClientConn: make(map[[2]byte]*ClientConn)}

	cm.chats[randID].ClientConn[cc.ID] = cc

	return randID
}

func (cm *MemChatManager) Join(id ChatID, cc *ClientConn) {
	cm.mu.Lock()
	defer cm.mu.Unlock()

	chat := cm.chats[id]
	chat.ClientConn[cc.ID] = cc
}

func (cm *MemChatManager) Leave(id ChatID, clientID [2]byte) {
	cm.mu.Lock()
	defer cm.mu.Unlock()

	privChat, ok := cm.chats[id]
	if !ok {
		return
	}

	delete(privChat.ClientConn, clientID)
}

func (cm *MemChatManager) GetSubject(id ChatID) string {
	cm.mu.Lock()
	defer cm.mu.Unlock()

	return cm.chats[id].Subject
}

func (cm *MemChatManager) Members(id ChatID) []*ClientConn {
	cm.mu.Lock()
	defer cm.mu.Unlock()

	chat := cm.chats[id]

	var members []*ClientConn
	for _, cc := range chat.ClientConn {
		members = append(members, cc)
	}

	slices.SortFunc(members, clientConnSortFunc)

	return members
}

func (cm *MemChatManager) SetSubject(id ChatID, subject string) {
	cm.mu.Lock()
	defer cm.mu.Unlock()

	chat := cm.chats[id]

	chat.Subject = subject
}

type MockChatManager struct {
	mock.Mock
}

func (m *MockChatManager) New(cc *ClientConn) ChatID {
	args := m.Called(cc)

	return args.Get(0).(ChatID)
}

func (m *MockChatManager) GetSubject(id ChatID) string {
	args := m.Called(id)

	return args.String(0)
}

func (m *MockChatManager) Join(id ChatID, cc *ClientConn) {
	m.Called(id, cc)
}

func (m *MockChatManager) Leave(id ChatID, clientID [2]byte) {
	m.Called(id, clientID)
}

func (m *MockChatManager) SetSubject(id ChatID, subject string) {
	m.Called(id, subject)

}

func (m *MockChatManager) Members(id ChatID) []*ClientConn {
	args := m.Called(id)

	return args.Get(0).([]*ClientConn)
}