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  }