-
Notifications
You must be signed in to change notification settings - Fork 0
/
device.go
117 lines (94 loc) · 3.03 KB
/
device.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
115
116
117
// Copyright © 2017 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.
package device
import (
"reflect"
"time"
"github.com/TheThingsNetwork/ttn/core/types"
"github.com/fatih/structs"
)
const currentDBVersion = "2.4.1"
type DevNonce [2]byte
type AppNonce [3]byte
// Options for the device
type Options struct {
ActivationConstraints string `json:"activation_constraints,omitempty"` // Activation Constraints (public/local/private)
DisableFCntCheck bool `json:"disable_fcnt_check,omitemtpy"` // Disable Frame counter check (insecure)
Uses32BitFCnt bool `json:"uses_32_bit_fcnt,omitemtpy"` // Use 32-bit Frame counters
}
// Device contains the state of a device
type Device struct {
old *Device
DevEUI types.DevEUI `redis:"dev_eui"`
AppEUI types.AppEUI `redis:"app_eui"`
AppID string `redis:"app_id"`
DevID string `redis:"dev_id"`
Description string `redis:"description"`
Latitude float32 `redis:"latitude"`
Longitude float32 `redis:"longitude"`
Altitude int32 `redis:"altitude"`
Options Options `redis:"options"`
AppKey types.AppKey `redis:"app_key"`
UsedDevNonces []DevNonce `redis:"used_dev_nonces"`
UsedAppNonces []AppNonce `redis:"used_app_nonces"`
DevAddr types.DevAddr `redis:"dev_addr"`
NwkSKey types.NwkSKey `redis:"nwk_s_key"`
AppSKey types.AppSKey `redis:"app_s_key"`
FCntUp uint32 `redis:"f_cnt_up"` // Only used to detect retries
CurrentDownlink *types.DownlinkMessage `redis:"current_downlink"`
CreatedAt time.Time `redis:"created_at"`
UpdatedAt time.Time `redis:"updated_at"`
Attributes map[string]string `redis:"attributes"`
}
// StartUpdate stores the state of the device
func (d *Device) StartUpdate() {
old := *d
d.old = &old
}
// Clone the device
func (d *Device) Clone() *Device {
n := new(Device)
*n = *d
n.old = nil
if d.CurrentDownlink != nil {
n.CurrentDownlink = new(types.DownlinkMessage)
*n.CurrentDownlink = *d.CurrentDownlink
}
return n
}
// DBVersion of the model
func (d *Device) DBVersion() string {
return currentDBVersion
}
// ChangedFields returns the names of the changed fields since the last call to StartUpdate
func (d Device) ChangedFields() (changed []string) {
new := structs.New(d)
fields := new.Names()
if d.old == nil {
return fields
}
old := structs.New(*d.old)
for _, field := range new.Fields() {
if !field.IsExported() || field.Name() == "old" {
continue
}
if !reflect.DeepEqual(field.Value(), old.Field(field.Name()).Value()) {
changed = append(changed, field.Name())
if field.Kind() == reflect.Struct {
oldSubField := structs.New(old.Field(field.Name()).Value())
for _, subField := range field.Fields() {
if !subField.IsExported() {
continue
}
if !reflect.DeepEqual(subField.Value(), oldSubField.Field(subField.Name()).Value()) {
changed = append(changed, field.Name()+"."+subField.Name())
}
}
}
}
}
if len(changed) == 1 && changed[0] == "UpdatedAt" {
return []string{}
}
return
}