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 } }