github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edge/pkg/devicetwin/dtmanager/device.go (about)

     1  package dtmanager
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"strings"
     7  	"time"
     8  
     9  	"k8s.io/klog"
    10  
    11  	"github.com/kubeedge/beehive/pkg/core/model"
    12  	"github.com/kubeedge/kubeedge/edge/pkg/common/modules"
    13  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtclient"
    14  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtcommon"
    15  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtcontext"
    16  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dttype"
    17  )
    18  
    19  var (
    20  	//deviceActionCallBack map for action to callback
    21  	deviceActionCallBack map[string]CallBack
    22  )
    23  
    24  //DeviceWorker deal device event
    25  type DeviceWorker struct {
    26  	Worker
    27  	Group string
    28  }
    29  
    30  //Start worker
    31  func (dw DeviceWorker) Start() {
    32  	initDeviceActionCallBack()
    33  	for {
    34  		select {
    35  		case msg, ok := <-dw.ReceiverChan:
    36  			if !ok {
    37  				return
    38  			}
    39  			if dtMsg, isDTMessage := msg.(*dttype.DTMessage); isDTMessage {
    40  				if fn, exist := deviceActionCallBack[dtMsg.Action]; exist {
    41  					_, err := fn(dw.DTContexts, dtMsg.Identity, dtMsg.Msg)
    42  					if err != nil {
    43  						klog.Errorf("DeviceModule deal %s event failed: %v", dtMsg.Action, err)
    44  					}
    45  				} else {
    46  					klog.Errorf("DeviceModule deal %s event failed, not found callback", dtMsg.Action)
    47  				}
    48  			}
    49  		case v, ok := <-dw.HeartBeatChan:
    50  			if !ok {
    51  				return
    52  			}
    53  			if err := dw.DTContexts.HeartBeat(dw.Group, v); err != nil {
    54  				return
    55  			}
    56  		}
    57  	}
    58  }
    59  
    60  func initDeviceActionCallBack() {
    61  	deviceActionCallBack = make(map[string]CallBack)
    62  	deviceActionCallBack[dtcommon.DeviceUpdated] = dealDeviceUpdated
    63  	deviceActionCallBack[dtcommon.DeviceStateUpdate] = dealDeviceStateUpdate
    64  }
    65  
    66  func dealDeviceStateUpdate(context *dtcontext.DTContext, resource string, msg interface{}) (interface{}, error) {
    67  	message, ok := msg.(*model.Message)
    68  	if !ok {
    69  		return nil, errors.New("msg not Message type")
    70  	}
    71  
    72  	updateDevice, err := dttype.UnmarshalDeviceUpdate(message.Content.([]byte))
    73  	if err != nil {
    74  		klog.Errorf("Unmarshal device info failed, err: %#v", err)
    75  		return nil, err
    76  	}
    77  	deviceID := resource
    78  	defer context.Unlock(deviceID)
    79  	context.Lock(deviceID)
    80  	doc, docExist := context.DeviceList.Load(deviceID)
    81  	if !docExist {
    82  		return nil, nil
    83  	}
    84  	device, ok := doc.(*dttype.Device)
    85  	if !ok {
    86  		return nil, nil
    87  	}
    88  	if strings.Compare("online", updateDevice.State) != 0 && strings.Compare("offline", updateDevice.State) != 0 && strings.Compare("unknown", updateDevice.State) != 0 {
    89  		return nil, nil
    90  	}
    91  	lastOnline := time.Now().Format("2006-01-02 15:04:05")
    92  	for i := 1; i <= dtcommon.RetryTimes; i++ {
    93  		err = dtclient.UpdateDeviceField(device.ID, "state", updateDevice.State)
    94  		err = dtclient.UpdateDeviceField(device.ID, "last_online", lastOnline)
    95  		if err == nil {
    96  			break
    97  		}
    98  		time.Sleep(dtcommon.RetryInterval)
    99  	}
   100  	if err != nil {
   101  
   102  	}
   103  	device.State = updateDevice.State
   104  	device.LastOnline = lastOnline
   105  	payload, err := dttype.BuildDeviceState(dttype.BuildBaseMessage(), *device)
   106  	if err != nil {
   107  
   108  	}
   109  	topic := dtcommon.DeviceETPrefix + device.ID + dtcommon.DeviceETStateUpdateSuffix + "/result"
   110  	context.Send(device.ID,
   111  		dtcommon.SendToEdge,
   112  		dtcommon.CommModule,
   113  		context.BuildModelMessage(modules.BusGroup, "", topic, "publish", payload))
   114  
   115  	msgResource := "device/" + device.ID + "/state"
   116  	context.Send(deviceID,
   117  		dtcommon.SendToCloud,
   118  		dtcommon.CommModule,
   119  		context.BuildModelMessage("resource", "", msgResource, "update", string(payload)))
   120  	return nil, nil
   121  }
   122  
   123  func dealDeviceUpdated(context *dtcontext.DTContext, resource string, msg interface{}) (interface{}, error) {
   124  	message, ok := msg.(*model.Message)
   125  	if !ok {
   126  		return nil, errors.New("msg not Message type")
   127  	}
   128  
   129  	updateDevice, err := dttype.UnmarshalDeviceUpdate(message.Content.([]byte))
   130  	if err != nil {
   131  		klog.Errorf("Unmarshal device info failed, err: %#v", err)
   132  		return nil, err
   133  	}
   134  
   135  	deviceID := resource
   136  
   137  	context.Lock(deviceID)
   138  	DeviceUpdated(context, deviceID, updateDevice.Attributes, dttype.BaseMessage{EventID: updateDevice.EventID}, 0)
   139  	context.Unlock(deviceID)
   140  	return nil, nil
   141  }
   142  
   143  //DeviceUpdated update device attributes
   144  func DeviceUpdated(context *dtcontext.DTContext, deviceID string, attributes map[string]*dttype.MsgAttr, baseMessage dttype.BaseMessage, dealType int) (interface{}, error) {
   145  	klog.Infof("Begin to update attributes of the device %s", deviceID)
   146  	var err error
   147  	doc, docExist := context.DeviceList.Load(deviceID)
   148  	if !docExist {
   149  		return nil, nil
   150  	}
   151  	Device, ok := doc.(*dttype.Device)
   152  	if !ok {
   153  		return nil, nil
   154  	}
   155  	dealAttrResult := DealMsgAttr(context, Device.ID, attributes, dealType)
   156  	add, delete, update, result := dealAttrResult.Add, dealAttrResult.Delete, dealAttrResult.Update, dealAttrResult.Result
   157  	if len(add) != 0 || len(delete) != 0 || len(update) != 0 {
   158  		for i := 1; i <= dtcommon.RetryTimes; i++ {
   159  			err = dtclient.DeviceAttrTrans(add, delete, update)
   160  			if err == nil {
   161  				break
   162  			}
   163  			time.Sleep(dtcommon.RetryInterval)
   164  		}
   165  		now := time.Now().UnixNano() / 1e6
   166  		baseMessage.Timestamp = now
   167  
   168  		if err != nil {
   169  			SyncDeviceFromSqlite(context, deviceID)
   170  			klog.Errorf("Update device failed due to writing sql error: %v", err)
   171  
   172  		} else {
   173  			klog.Infof("Send update attributes of device %s event to edge app", deviceID)
   174  			payload, err := dttype.BuildDeviceAttrUpdate(baseMessage, result)
   175  			if err != nil {
   176  				//todo
   177  				klog.Errorf("Build device attribute update failed: %v", err)
   178  			}
   179  			topic := dtcommon.DeviceETPrefix + deviceID + dtcommon.DeviceETUpdatedSuffix
   180  			context.Send(deviceID, dtcommon.SendToEdge, dtcommon.CommModule,
   181  				context.BuildModelMessage(modules.BusGroup, "", topic, "publish", payload))
   182  		}
   183  	}
   184  
   185  	return nil, nil
   186  }
   187  
   188  //DealMsgAttr get diff,0:update, 1:detail
   189  func DealMsgAttr(context *dtcontext.DTContext, deviceID string, msgAttrs map[string]*dttype.MsgAttr, dealType int) dttype.DealAttrResult {
   190  	deviceModel, ok := context.GetDevice(deviceID)
   191  	if !ok {
   192  
   193  	}
   194  	attrs := deviceModel.Attributes
   195  	if attrs == nil {
   196  		deviceModel.Attributes = make(map[string]*dttype.MsgAttr)
   197  		attrs = deviceModel.Attributes
   198  	}
   199  	add := make([]dtclient.DeviceAttr, 0)
   200  	deletes := make([]dtclient.DeviceDelete, 0)
   201  	update := make([]dtclient.DeviceAttrUpdate, 0)
   202  	result := make(map[string]*dttype.MsgAttr)
   203  
   204  	for key, msgAttr := range msgAttrs {
   205  
   206  		if attr, exist := attrs[key]; exist {
   207  			if msgAttr == nil && dealType == 0 {
   208  				if *attr.Optional {
   209  					deletes = append(deletes, dtclient.DeviceDelete{DeviceID: deviceID, Name: key})
   210  					result[key] = nil
   211  					delete(attrs, key)
   212  				}
   213  				continue
   214  			}
   215  			isChange := false
   216  			cols := make(map[string]interface{})
   217  			result[key] = &dttype.MsgAttr{}
   218  			if strings.Compare(attr.Value, msgAttr.Value) != 0 {
   219  				attr.Value = msgAttr.Value
   220  
   221  				cols["value"] = msgAttr.Value
   222  				result[key].Value = msgAttr.Value
   223  
   224  				isChange = true
   225  			}
   226  			if msgAttr.Metadata != nil {
   227  				msgMetaJSON, _ := json.Marshal(msgAttr.Metadata)
   228  				attrMetaJSON, _ := json.Marshal(attr.Metadata)
   229  				if strings.Compare(string(msgMetaJSON), string(attrMetaJSON)) != 0 {
   230  					cols["attr_type"] = msgAttr.Metadata.Type
   231  					meta := dttype.CopyMsgAttr(msgAttr)
   232  					attr.Metadata = meta.Metadata
   233  					msgAttr.Metadata.Type = ""
   234  					metaJSON, _ := json.Marshal(msgAttr.Metadata)
   235  					cols["metadata"] = string(metaJSON)
   236  					msgAttr.Metadata.Type = cols["attr_type"].(string)
   237  					result[key].Metadata = meta.Metadata
   238  					isChange = true
   239  				}
   240  			}
   241  			if msgAttr.Optional != nil {
   242  				if *msgAttr.Optional != *attr.Optional && *attr.Optional {
   243  					optional := *msgAttr.Optional
   244  					cols["optional"] = optional
   245  					attr.Optional = &optional
   246  					result[key].Optional = &optional
   247  					isChange = true
   248  				}
   249  			}
   250  			if isChange {
   251  				update = append(update, dtclient.DeviceAttrUpdate{DeviceID: deviceID, Name: key, Cols: cols})
   252  			} else {
   253  				delete(result, key)
   254  			}
   255  
   256  		} else {
   257  
   258  			deviceAttr := dttype.MsgAttrToDeviceAttr(key, msgAttr)
   259  			deviceAttr.DeviceID = deviceID
   260  			deviceAttr.Value = msgAttr.Value
   261  			if msgAttr.Optional != nil {
   262  				optional := *msgAttr.Optional
   263  				deviceAttr.Optional = optional
   264  			}
   265  			if msgAttr.Metadata != nil {
   266  				//todo
   267  				deviceAttr.AttrType = msgAttr.Metadata.Type
   268  				msgAttr.Metadata.Type = ""
   269  				metaJSON, _ := json.Marshal(msgAttr.Metadata)
   270  				msgAttr.Metadata.Type = deviceAttr.AttrType
   271  				deviceAttr.Metadata = string(metaJSON)
   272  			}
   273  			add = append(add, deviceAttr)
   274  			attrs[key] = msgAttr
   275  			result[key] = msgAttr
   276  		}
   277  	}
   278  	if dealType > 0 {
   279  		for key := range attrs {
   280  			if _, exist := msgAttrs[key]; !exist {
   281  				deletes = append(deletes, dtclient.DeviceDelete{DeviceID: deviceID, Name: key})
   282  				result[key] = nil
   283  			}
   284  		}
   285  		for _, v := range deletes {
   286  			delete(attrs, v.Name)
   287  		}
   288  	}
   289  	return dttype.DealAttrResult{Add: add, Delete: deletes, Update: update, Result: result, Err: nil}
   290  }