github.com/stampzilla/stampzilla-go@v2.0.0-rc9+incompatible/nodes/stampzilla-server/models/devices/device.go (about) 1 package devices 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strings" 7 "sync" 8 ) 9 10 type ID struct { 11 Node string 12 ID string 13 } 14 15 // ErrWrongIDFormat is returned if the new ID is not in the correct format 16 var ErrWrongIDFormat = fmt.Errorf("wrong ID format. Expected nodeuuid.deviceid") 17 18 func NewIDFromString(id string) (ID, error) { 19 tmp := strings.SplitN(string(id), ".", 2) 20 if len(tmp) != 2 { 21 return ID{}, ErrWrongIDFormat 22 } 23 return ID{Node: tmp[0], ID: tmp[1]}, nil 24 } 25 26 func (id ID) String() string { 27 return strings.Join([]string{id.Node, id.ID}, ".") 28 } 29 30 func (id ID) IsZero() bool { 31 return id == ID{} 32 } 33 34 func (id ID) Bytes() []byte { 35 return []byte(strings.Join([]string{id.Node, id.ID}, ".")) 36 } 37 func (id ID) MarshalText() (text []byte, err error) { 38 text = id.Bytes() 39 return 40 } 41 42 func (id *ID) UnmarshalText(text []byte) error { 43 tmp := strings.SplitN(string(text), ".", 2) 44 if len(tmp) != 2 { 45 return ErrWrongIDFormat 46 } 47 id.Node = tmp[0] 48 id.ID = tmp[1] 49 return nil 50 51 } 52 53 type Device struct { 54 Type string `json:"type"` 55 ID ID `json:"id"` 56 Name string `json:"name,omitempty"` 57 Alias string `json:"alias,omitempty"` 58 Online bool `json:"online"` 59 State State `json:"state"` 60 Traits []string `json:"traits"` 61 sync.RWMutex 62 } 63 64 //NewDevice initializes a new device with needed maps 65 func NewDevice() *Device { 66 return &Device{ 67 State: make(State), 68 } 69 } 70 71 //SetOnline set online state 72 func (d *Device) SetOnline(v bool) { 73 d.Lock() 74 d.Online = v 75 d.Unlock() 76 } 77 78 // Copy copies a device 79 func (d *Device) Copy() *Device { 80 d.Lock() 81 newTraits := make([]string, len(d.Traits)) 82 newState := d.State.Clone() 83 84 copy(newTraits, d.Traits) 85 86 newD := &Device{ 87 Type: d.Type, 88 //Node: d.Node, 89 ID: ID{ 90 ID: d.ID.ID, 91 Node: d.ID.Node, 92 }, 93 Name: d.Name, 94 Online: d.Online, 95 State: newState, 96 Traits: d.Traits, 97 } 98 d.Unlock() 99 return newD 100 } 101 102 type DeviceMap map[ID]*Device 103 104 type List struct { 105 devices DeviceMap 106 sync.RWMutex 107 } 108 109 func NewList() *List { 110 return &List{ 111 devices: make(DeviceMap), 112 } 113 } 114 115 // Len return how many devices there are in the list. 116 func (d *List) Len() int { 117 d.Lock() 118 defer d.Unlock() 119 return len(d.devices) 120 } 121 122 // Add adds a device to the list 123 func (d *List) Add(dev *Device) { 124 d.Lock() 125 d.devices[dev.ID] = dev 126 d.Unlock() 127 } 128 129 // Update the state of a device 130 func (d *List) SetState(id ID, state State) error { 131 d.Lock() 132 defer d.Unlock() 133 if dev, ok := d.devices[id]; ok { 134 dev.State = state 135 return nil 136 } 137 138 return fmt.Errorf("Node not found (%s)", id.String()) 139 } 140 141 // Get returns a device 142 func (d *List) Get(id ID) *Device { 143 d.RLock() 144 defer d.RUnlock() 145 return d.devices[id] 146 } 147 148 //func (d *List) GetUnique(id string) *Device { 149 //d.RLock() 150 //defer d.RUnlock() 151 //return d.devices[id] 152 //} 153 154 // All get all devices 155 func (d *List) All() DeviceMap { 156 d.RLock() 157 defer d.RUnlock() 158 return d.devices 159 } 160 161 // Copy copies a list of devices 162 func (d *List) Copy() *List { 163 164 newD := &List{ 165 devices: make(DeviceMap), 166 } 167 d.RLock() 168 for _, v := range d.devices { 169 newD.Add(v.Copy()) 170 } 171 d.RUnlock() 172 173 return newD 174 } 175 176 func (d *List) MarshalJSON() ([]byte, error) { 177 d.RLock() 178 defer d.RUnlock() 179 return json.Marshal(d.devices) 180 } 181 182 func (d *List) UnmarshalJSON(b []byte) error { 183 var devices DeviceMap 184 if err := json.Unmarshal(b, &devices); err != nil { 185 return err 186 } 187 188 for _, dev := range devices { 189 d.Add(dev) 190 } 191 return nil 192 } 193 194 // Flatten can be used for metrics export and logic rules 195 func (d *List) Flatten() map[string]interface{} { 196 197 devmap := make(map[string]interface{}) 198 for k, v := range d.All() { 199 v.Lock() 200 for stateKey, s := range v.State { 201 key := fmt.Sprintf("%s.%s", k, stateKey) 202 devmap[key] = s 203 } 204 v.Unlock() 205 } 206 return devmap 207 } 208 209 // StateGroupedByNode get state from all devices grouped by node uuid 210 func (d *List) StateGroupedByNode() map[string]map[ID]State { 211 d.RLock() 212 devicesByNode := make(map[string]map[ID]State) 213 for id, state := range d.devices { 214 if devicesByNode[id.Node] == nil { 215 devicesByNode[id.Node] = make(map[ID]State) 216 } 217 devicesByNode[id.Node][id] = state.State 218 } 219 d.RUnlock() 220 return devicesByNode 221 }