aboutsummaryrefslogtreecommitdiff
path: root/inform/inform.go
diff options
context:
space:
mode:
Diffstat (limited to 'inform/inform.go')
-rw-r--r--inform/inform.go133
1 files changed, 133 insertions, 0 deletions
diff --git a/inform/inform.go b/inform/inform.go
new file mode 100644
index 0000000..b159084
--- /dev/null
+++ b/inform/inform.go
@@ -0,0 +1,133 @@
1package inform
2
3import (
4 "bytes"
5 "encoding/json"
6 "errors"
7 "fmt"
8 "github.com/mitchellh/mapstructure"
9)
10
11const (
12 PROTOCOL_MAGIC int32 = 1414414933 // TNBU
13 INFORM_VERSION int32 = 0
14 DATA_VERSION int32 = 1
15
16 ENCRYPTED_FLAG = 1
17 COMPRESSED_FLAG = 2
18)
19
20// Wrapper around an inform message, serializes directly into the wire
21// protocol
22type InformWrapper struct {
23 Version int32
24 MacAddr []byte
25 Flags int16
26 DataVersion int32
27 Payload []byte
28}
29
30// Create InformWrapper with sane defaults
31func NewInformWrapper() *InformWrapper {
32 return &InformWrapper{
33 Version: INFORM_VERSION,
34 MacAddr: make([]byte, 6),
35 Flags: 0,
36 DataVersion: DATA_VERSION,
37 }
38}
39
40// Update the payload data with JSON value
41func (i *InformWrapper) UpdatePayload(v interface{}) error {
42 if d, err := json.Marshal(v); err != nil {
43 return err
44 } else {
45 i.Payload = d
46 return nil
47 }
48}
49
50// Format Mac address bytes as lowercase string with colons
51func (i *InformWrapper) FormattedMac() string {
52 return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x",
53 i.MacAddr[0], i.MacAddr[1], i.MacAddr[2],
54 i.MacAddr[3], i.MacAddr[4], i.MacAddr[5])
55}
56
57func (i *InformWrapper) String() string {
58 b := &bytes.Buffer{}
59
60 fmt.Fprintf(b, "Version: \t%d\n", i.Version)
61 fmt.Fprintf(b, "Mac Addr: \t%s\n", i.FormattedMac())
62 fmt.Fprintf(b, "Flags: \t%d\n", i.Flags)
63 fmt.Fprintf(b, " Encrypted: \t%t\n", i.IsEncrypted())
64 fmt.Fprintf(b, " Compressed: \t%t\n", i.IsCompressed())
65 fmt.Fprintf(b, "Data Version: \t%d\n", i.DataVersion)
66 fmt.Fprintf(b, "Payload: \t%q\n", i.Payload)
67
68 return b.String()
69}
70
71func (i *InformWrapper) IsEncrypted() bool {
72 return i.Flags&ENCRYPTED_FLAG != 0
73}
74
75func (i *InformWrapper) SetEncrypted(e bool) {
76 if e {
77 i.Flags |= ENCRYPTED_FLAG
78 } else {
79 i.Flags &= ENCRYPTED_FLAG
80 }
81}
82
83func (i *InformWrapper) IsCompressed() bool {
84 return i.Flags&COMPRESSED_FLAG != 0
85}
86
87func (i *InformWrapper) SetCompressed(c bool) {
88 if c {
89 i.Flags |= COMPRESSED_FLAG
90 } else {
91 i.Flags &= COMPRESSED_FLAG
92 }
93}
94
95// Decode payload to a map and try to determine the inform type
96func (i *InformWrapper) decodePayload() (map[string]interface{}, string, error) {
97 var m map[string]interface{}
98
99 if err := json.Unmarshal(i.Payload, &m); err != nil {
100 return nil, "", err
101 }
102
103 t, ok := m["_type"]
104 if !ok {
105 return nil, "", errors.New("Message contains no type")
106 }
107
108 st, ok := t.(string)
109 if !ok {
110 return nil, "", errors.New("Message type is not a string")
111 }
112
113 return m, st, nil
114}
115
116// Decode payload JSON as a inform message
117func (i *InformWrapper) JsonMessage() (interface{}, error) {
118 msg, t, err := i.decodePayload()
119 if err != nil {
120 return nil, err
121 }
122
123 switch t {
124 case "noop":
125 var o NoopMessage
126 if err := mapstructure.Decode(msg, &o); err != nil {
127 return nil, err
128 }
129 return o, nil
130 }
131
132 return nil, errors.New(fmt.Sprintf("Message type %s is invalid", t))
133}