-
Notifications
You must be signed in to change notification settings - Fork 3
/
unsubscribe.go
114 lines (98 loc) · 2.8 KB
/
unsubscribe.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package packets1
import (
"encoding/binary"
"fmt"
pkts "github.com/energomonitor/bisquitt/packets"
)
const unsubscribeHeaderLength uint16 = 3
type Unsubscribe struct {
pkts.Header
// Flags
TopicIDType uint8
// Fields
MessageIDProperty
TopicID uint16
TopicName string
}
// NOTE: Packet length is initialized in this constructor and recomputed in m.Write().
func NewUnsubscribe(topicName string, topicID uint16, topicIDType uint8) *Unsubscribe {
p := &Unsubscribe{
Header: *pkts.NewHeader(pkts.UNSUBSCRIBE, 0),
TopicIDType: topicIDType,
TopicID: topicID,
TopicName: topicName,
}
p.computeLength()
return p
}
func (p *Unsubscribe) computeLength() {
var topicLength uint16
switch p.TopicIDType {
case TIT_STRING:
topicLength = uint16(len(p.TopicName))
case TIT_PREDEFINED, TIT_SHORT:
topicLength = 2
}
p.Header.SetVarPartLength(unsubscribeHeaderLength + topicLength)
}
func (p *Unsubscribe) encodeFlags() byte {
var b byte
b |= p.TopicIDType & flagsTopicIDTypeBits
return b
}
func (p *Unsubscribe) decodeFlags(b byte) {
p.TopicIDType = b & flagsTopicIDTypeBits
}
func (p *Unsubscribe) Pack() ([]byte, error) {
p.computeLength()
buf := p.Header.PackToBuffer()
_ = buf.WriteByte(p.encodeFlags())
_, _ = buf.Write(pkts.EncodeUint16(p.messageID))
switch p.TopicIDType {
case TIT_STRING:
_, _ = buf.Write([]byte(p.TopicName))
case TIT_PREDEFINED, TIT_SHORT:
_, _ = buf.Write(pkts.EncodeUint16(p.TopicID))
}
return buf.Bytes(), nil
}
func (p *Unsubscribe) Unpack(buf []byte) error {
if len(buf) <= int(unsubscribeHeaderLength) {
return fmt.Errorf("bad UNSUBSCRIBE packet length: expected >%d, got %d",
unsubscribeHeaderLength, len(buf))
}
p.decodeFlags(buf[0])
p.messageID = binary.BigEndian.Uint16(buf[1:3])
switch p.TopicIDType {
case TIT_STRING:
p.TopicID = 0
p.TopicName = string(buf[3:])
case TIT_PREDEFINED, TIT_SHORT:
if len(buf) != int(unsubscribeHeaderLength+2) {
return fmt.Errorf("bad UNSUBSCRIBE packet length: expected %d, got %d",
unsubscribeHeaderLength+2, len(buf))
}
p.TopicName = ""
p.TopicID = binary.BigEndian.Uint16(buf[3:5])
default:
return fmt.Errorf("invalid TopicIDType: %d", p.TopicIDType)
}
return nil
}
func (p Unsubscribe) String() string {
switch p.TopicIDType {
case TIT_STRING:
return fmt.Sprintf("UNSUBSCRIBE(TopicName=%#v, MessageID=%d)",
string(p.TopicName), p.messageID)
case TIT_PREDEFINED:
return fmt.Sprintf("UNSUBSCRIBE(TopicID(p)=%d, MessageID=%d)",
p.TopicID, p.messageID)
case TIT_SHORT:
topicName := pkts.DecodeShortTopic(p.TopicID)
return fmt.Sprintf("UNSUBSCRIBE(TopicName(s)=%#v, MessageID=%d)",
topicName, p.messageID)
default:
return fmt.Sprintf("UNSUBSCRIBE(TopicName=%#v, TopicID=%d, TopicIDType=%d (INVALID!), MessageID=%d)",
p.TopicName, p.TopicID, p.TopicIDType, p.messageID)
}
}