diff options
Diffstat (limited to 'inform/inform.go')
-rw-r--r-- | inform/inform.go | 133 |
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 @@ | |||
1 | package inform | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/json" | ||
6 | "errors" | ||
7 | "fmt" | ||
8 | "github.com/mitchellh/mapstructure" | ||
9 | ) | ||
10 | |||
11 | const ( | ||
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 | ||
22 | type 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 | ||
31 | func 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 | ||
41 | func (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 | ||
51 | func (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 | |||
57 | func (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 | |||
71 | func (i *InformWrapper) IsEncrypted() bool { | ||
72 | return i.Flags&ENCRYPTED_FLAG != 0 | ||
73 | } | ||
74 | |||
75 | func (i *InformWrapper) SetEncrypted(e bool) { | ||
76 | if e { | ||
77 | i.Flags |= ENCRYPTED_FLAG | ||
78 | } else { | ||
79 | i.Flags &= ENCRYPTED_FLAG | ||
80 | } | ||
81 | } | ||
82 | |||
83 | func (i *InformWrapper) IsCompressed() bool { | ||
84 | return i.Flags&COMPRESSED_FLAG != 0 | ||
85 | } | ||
86 | |||
87 | func (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 | ||
96 | func (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 | ||
117 | func (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 | } | ||