aboutsummaryrefslogtreecommitdiff
path: root/hotline/client_manager.go
blob: ab6372c05cfedcacdf79d0977fbbcd3c1e754b9d (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
package hotline

import (
	"cmp"
	"encoding/binary"
	"github.com/stretchr/testify/mock"
	"slices"
	"sync"
	"sync/atomic"
)

type ClientID [2]byte

type ClientManager interface {
	List() []*ClientConn // Returns list of sorted clients
	Get(id ClientID) *ClientConn
	Add(cc *ClientConn)
	Delete(id ClientID)
}

type MockClientMgr struct {
	mock.Mock
}

func (m *MockClientMgr) List() []*ClientConn {
	args := m.Called()

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

func (m *MockClientMgr) Get(id ClientID) *ClientConn {
	args := m.Called(id)

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

func (m *MockClientMgr) Add(cc *ClientConn) {
	m.Called(cc)
}
func (m *MockClientMgr) Delete(id ClientID) {
	m.Called(id)
}

type MemClientMgr struct {
	clients map[ClientID]*ClientConn

	mu           sync.Mutex
	nextClientID atomic.Uint32
}

func NewMemClientMgr() *MemClientMgr {
	return &MemClientMgr{
		clients: make(map[ClientID]*ClientConn),
	}
}

// List returns slice of sorted clients.
func (cm *MemClientMgr) List() []*ClientConn {
	cm.mu.Lock()
	defer cm.mu.Unlock()

	var clients []*ClientConn
	for _, client := range cm.clients {
		clients = append(clients, client)
	}

	slices.SortFunc(clients, func(a, b *ClientConn) int {
		return cmp.Compare(
			binary.BigEndian.Uint16(a.ID[:]),
			binary.BigEndian.Uint16(b.ID[:]),
		)
	})

	return clients
}

func (cm *MemClientMgr) Get(id ClientID) *ClientConn {
	cm.mu.Lock()
	defer cm.mu.Unlock()

	return cm.clients[id]
}

func (cm *MemClientMgr) Add(cc *ClientConn) {
	cm.mu.Lock()
	defer cm.mu.Unlock()

	cm.nextClientID.Add(1)
	binary.BigEndian.PutUint16(cc.ID[:], uint16(cm.nextClientID.Load()))

	cm.clients[cc.ID] = cc
}

func (cm *MemClientMgr) Delete(id ClientID) {
	cm.mu.Lock()
	defer cm.mu.Unlock()

	delete(cm.clients, id)
}