aboutsummaryrefslogtreecommitdiff
path: root/inform/inform.go
blob: ac3b57df278834ee29e7026abc8e5d6f26638df7 (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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package inform

import (
	"bytes"
	"encoding/json"
	"fmt"
)

const (
	PROTOCOL_MAGIC int32 = 1414414933 // UBNT
	INFORM_VERSION int32 = 0
	DATA_VERSION   int32 = 1

	ENCRYPTED_FLAG  = 1
	COMPRESSED_FLAG = 2
)

// Wrapper around an inform message, serializes directly into the wire
// protocol
type InformWrapper struct {
	Version     int32
	MacAddr     []byte
	Flags       int16
	DataVersion int32
	Payload     []byte
}

// Create InformWrapper with sane defaults
func NewInformWrapper() *InformWrapper {
	w := &InformWrapper{
		Version:     INFORM_VERSION,
		MacAddr:     make([]byte, 6),
		Flags:       0,
		DataVersion: DATA_VERSION,
	}

	// Almost all messages are encrypted outside of provisioning so default
	// this and make users explicitly disable it.
	w.SetEncrypted(true)

	return w
}

// Create an InformWrapper that is a response to an incoming wrapper. Copies
// all necessary data for a response so callers can just set a payload
func NewInformWrapperResponse(msg *InformWrapper) *InformWrapper {
	w := NewInformWrapper()
	copy(w.MacAddr, msg.MacAddr)
	return w
}

// Update the payload data with JSON value
func (i *InformWrapper) UpdatePayload(v interface{}) error {
	if d, err := json.Marshal(v); err != nil {
		return err
	} else {
		i.Payload = d
		return nil
	}
}

// Unmarshal a payload body that we received from a device. Does not work for
// user-set messages
func (i *InformWrapper) UnmarshalPayload() (*DeviceMessage, error) {
	var m DeviceMessage

	err := json.Unmarshal(i.Payload, &m)
	if err != nil {
		return nil, err
	}

	return &m, nil
}

// Format Mac address bytes as lowercase string with colons
func (i *InformWrapper) FormattedMac() string {
	return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x",
		i.MacAddr[0], i.MacAddr[1], i.MacAddr[2],
		i.MacAddr[3], i.MacAddr[4], i.MacAddr[5])
}

func (i *InformWrapper) String() string {
	b := &bytes.Buffer{}

	fmt.Fprintf(b, "Version:      \t%d\n", i.Version)
	fmt.Fprintf(b, "Mac Addr:     \t%s\n", i.FormattedMac())
	fmt.Fprintf(b, "Flags:        \t%d\n", i.Flags)
	fmt.Fprintf(b, " Encrypted:   \t%t\n", i.IsEncrypted())
	fmt.Fprintf(b, " Compressed:  \t%t\n", i.IsCompressed())
	fmt.Fprintf(b, "Data Version: \t%d\n", i.DataVersion)
	fmt.Fprintf(b, "Payload:      \t%q\n", i.Payload)

	return b.String()
}

func (i *InformWrapper) IsEncrypted() bool {
	return i.Flags&ENCRYPTED_FLAG != 0
}

func (i *InformWrapper) SetEncrypted(e bool) {
	if e {
		i.Flags |= ENCRYPTED_FLAG
	} else {
		i.Flags &= ENCRYPTED_FLAG
	}
}

func (i *InformWrapper) IsCompressed() bool {
	return i.Flags&COMPRESSED_FLAG != 0
}

func (i *InformWrapper) SetCompressed(c bool) {
	if c {
		i.Flags |= COMPRESSED_FLAG
	} else {
		i.Flags &= COMPRESSED_FLAG
	}
}