/
queue.go
94 lines (78 loc) · 1.84 KB
/
queue.go
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
package gateway
import (
"errors"
"sync"
"github.com/andersfylling/disgord/internal/gateway/opcode"
)
func newClientPktQueue(limit int) clientPktQueue {
if limit == 0 {
limit = -1 // no limit
}
return clientPktQueue{
limit: limit,
}
}
// clientPktQueue is an ordered queue. Entries are not removed unless they are successfully written to the websocket.
type clientPktQueue struct {
sync.RWMutex
messages []*clientPacket
limit int
}
func (c *clientPktQueue) IsEmpty() bool {
c.RLock()
defer c.RUnlock()
return len(c.messages) == 0
}
func (c *clientPktQueue) AddByOverwrite(msg *clientPacket) error {
c.Lock()
defer c.Unlock()
for i := range c.messages {
if c.messages[i].Op == msg.Op {
c.messages[i] = msg
return nil
}
}
return errors.New("no entry with existing operation code")
}
func (c *clientPktQueue) Add(msg *clientPacket) error {
if msg.Op == opcode.EventStatusUpdate {
if err := c.AddByOverwrite(msg); err == nil {
return nil
}
}
c.Lock()
defer c.Unlock()
if len(c.messages) == c.limit {
return errors.New("can not send anymore messages, queue is full")
}
c.messages = append(c.messages, msg)
return nil
}
func (c *clientPktQueue) Try(cb func(msg *clientPacket) error) error {
c.Lock()
defer c.Unlock()
if len(c.messages) == 0 {
return nil // nothing to try, this avoid a potential race as well
}
next := c.messages[0]
if err := cb(next); err != nil {
return err
}
// shift to avoid re-allocations
for i := 0; i < len(c.messages)-1; i++ {
c.messages[i] = c.messages[i+1]
}
c.messages = c.messages[:len(c.messages)-1]
return nil
}
func (c *clientPktQueue) Steal() (m []*clientPacket) {
c.Lock()
defer c.Unlock()
m = make([]*clientPacket, len(c.messages))
copy(m, c.messages)
for i := range c.messages {
c.messages[i] = nil // redundant?
}
c.messages = c.messages[:0]
return m
}