aboutsummaryrefslogtreecommitdiff
path: root/hotline/chat.go
blob: 00ae8eafe2c6bd441ea4f51a14db703b7ded46db (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
package hotline

import (
	"crypto/rand"
	"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
}