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

     1  package dtmanager
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  	"sync"
     9  	"time"
    10  
    11  	"k8s.io/klog"
    12  
    13  	"github.com/kubeedge/beehive/pkg/core/model"
    14  	"github.com/kubeedge/kubeedge/edge/pkg/common/modules"
    15  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtclient"
    16  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtcommon"
    17  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dtcontext"
    18  	"github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dttype"
    19  )
    20  
    21  const (
    22  	//RestDealType update from mqtt
    23  	RestDealType = 0
    24  	//SyncDealType update form cloud sync
    25  	SyncDealType = 1
    26  	//DetailDealType detail update from cloud
    27  	DetailDealType = 2
    28  	//SyncTwinDeleteDealType twin delete when sync
    29  	SyncTwinDeleteDealType = 3
    30  	//DealActual deal actual
    31  	DealActual = 1
    32  	//DealExpected deal exepected
    33  	DealExpected = 0
    34  )
    35  
    36  var (
    37  	//twinActionCallBack map for action to callback
    38  	twinActionCallBack         map[string]CallBack
    39  	initTwinActionCallBackOnce sync.Once
    40  )
    41  
    42  //TwinWorker deal twin event
    43  type TwinWorker struct {
    44  	Worker
    45  	Group string
    46  }
    47  
    48  //Start worker
    49  func (tw TwinWorker) Start() {
    50  	initTwinActionCallBack()
    51  	for {
    52  		select {
    53  		case msg, ok := <-tw.ReceiverChan:
    54  			if !ok {
    55  				return
    56  			}
    57  			if dtMsg, isDTMessage := msg.(*dttype.DTMessage); isDTMessage {
    58  				if fn, exist := twinActionCallBack[dtMsg.Action]; exist {
    59  					_, err := fn(tw.DTContexts, dtMsg.Identity, dtMsg.Msg)
    60  					if err != nil {
    61  						klog.Errorf("TwinModule deal %s event failed", dtMsg.Action)
    62  					}
    63  				} else {
    64  					klog.Errorf("TwinModule deal %s event failed, not found callback", dtMsg.Action)
    65  				}
    66  			}
    67  
    68  		case v, ok := <-tw.HeartBeatChan:
    69  			if !ok {
    70  				return
    71  			}
    72  			if err := tw.DTContexts.HeartBeat(tw.Group, v); err != nil {
    73  				return
    74  			}
    75  		}
    76  	}
    77  }
    78  
    79  func initTwinActionCallBack() {
    80  	initTwinActionCallBackOnce.Do(func() {
    81  		twinActionCallBack = make(map[string]CallBack)
    82  		twinActionCallBack[dtcommon.TwinUpdate] = dealTwinUpdate
    83  		twinActionCallBack[dtcommon.TwinGet] = dealTwinGet
    84  		twinActionCallBack[dtcommon.TwinCloudSync] = dealTwinSync
    85  	})
    86  }
    87  
    88  func dealTwinSync(context *dtcontext.DTContext, resource string, msg interface{}) (interface{}, error) {
    89  	klog.Infof("Twin Sync EVENT")
    90  	message, ok := msg.(*model.Message)
    91  	if !ok {
    92  		return nil, errors.New("msg not Message type")
    93  	}
    94  	result := []byte("")
    95  	content, ok := message.Content.([]byte)
    96  	if !ok {
    97  		return nil, errors.New("invalid message content")
    98  	}
    99  
   100  	msgTwin, err := dttype.UnmarshalDeviceTwinUpdate(content)
   101  	if err != nil {
   102  		klog.Errorf("Unmarshal update request body failed, err: %#v", err)
   103  		dealUpdateResult(context, "", "", dtcommon.BadRequestCode, errors.New("Unmarshal update request body failed, Please check the request"), result)
   104  		return nil, err
   105  	}
   106  
   107  	klog.Infof("Begin to update twin of the device %s", resource)
   108  	eventID := msgTwin.EventID
   109  	context.Lock(resource)
   110  	DealDeviceTwin(context, resource, eventID, msgTwin.Twin, SyncDealType)
   111  	context.Unlock(resource)
   112  	//todo send ack
   113  	return nil, nil
   114  }
   115  
   116  func dealTwinGet(context *dtcontext.DTContext, resource string, msg interface{}) (interface{}, error) {
   117  	klog.Infof("Twin Get EVENT")
   118  	message, ok := msg.(*model.Message)
   119  	if !ok {
   120  		return nil, errors.New("msg not Message type")
   121  	}
   122  
   123  	content, ok := message.Content.([]byte)
   124  	if !ok {
   125  		return nil, errors.New("invalid message content")
   126  	}
   127  
   128  	DealGetTwin(context, resource, content)
   129  	return nil, nil
   130  }
   131  
   132  func dealTwinUpdate(context *dtcontext.DTContext, resource string, msg interface{}) (interface{}, error) {
   133  	klog.Infof("Twin Update EVENT")
   134  	message, ok := msg.(*model.Message)
   135  	if !ok {
   136  		return nil, errors.New("msg not Message type")
   137  	}
   138  
   139  	content, ok := message.Content.([]byte)
   140  	if !ok {
   141  		return nil, errors.New("invalid message content")
   142  	}
   143  
   144  	context.Lock(resource)
   145  	Updated(context, resource, content)
   146  	context.Unlock(resource)
   147  	return nil, nil
   148  }
   149  
   150  // Updated update the snapshot
   151  func Updated(context *dtcontext.DTContext, deviceID string, payload []byte) {
   152  	result := []byte("")
   153  	msg, err := dttype.UnmarshalDeviceTwinUpdate(payload)
   154  	if err != nil {
   155  		klog.Errorf("Unmarshal update request body failed, err: %#v", err)
   156  		dealUpdateResult(context, "", "", dtcommon.BadRequestCode, err, result)
   157  		return
   158  	}
   159  	klog.Infof("Begin to update twin of the device %s", deviceID)
   160  	eventID := msg.EventID
   161  	DealDeviceTwin(context, deviceID, eventID, msg.Twin, RestDealType)
   162  }
   163  
   164  //DealDeviceTwin deal device twin
   165  func DealDeviceTwin(context *dtcontext.DTContext, deviceID string, eventID string, msgTwin map[string]*dttype.MsgTwin, dealType int) error {
   166  	klog.Infof("Begin to deal device twin of the device %s", deviceID)
   167  	now := time.Now().UnixNano() / 1e6
   168  	result := []byte("")
   169  	deviceModel, isExist := context.GetDevice(deviceID)
   170  	if !isExist {
   171  		klog.Errorf("Update twin rejected due to the device %s is not existed", deviceID)
   172  		dealUpdateResult(context, deviceID, eventID, dtcommon.NotFoundCode, errors.New("Update rejected due to the device is not existed"), result)
   173  		return errors.New("Update rejected due to the device is not existed")
   174  	}
   175  	content := msgTwin
   176  	var err error
   177  	if content == nil {
   178  		klog.Errorf("Update twin of device %s error, the update request body not have key:twin", deviceID)
   179  		err = errors.New("Update twin error, the update request body not have key:twin")
   180  		dealUpdateResult(context, deviceID, eventID, dtcommon.BadRequestCode, err, result)
   181  		return err
   182  	}
   183  	dealTwinResult := DealMsgTwin(context, deviceID, content, dealType)
   184  
   185  	add, deletes, update := dealTwinResult.Add, dealTwinResult.Delete, dealTwinResult.Update
   186  	if dealType == RestDealType && dealTwinResult.Err != nil {
   187  		SyncDeviceFromSqlite(context, deviceID)
   188  		err = dealTwinResult.Err
   189  		updateResult, _ := dttype.BuildDeviceTwinResult(dttype.BaseMessage{EventID: eventID, Timestamp: now}, dealTwinResult.Result, 0)
   190  		dealUpdateResult(context, deviceID, eventID, dtcommon.BadRequestCode, err, updateResult)
   191  		return err
   192  	}
   193  	if len(add) != 0 || len(deletes) != 0 || len(update) != 0 {
   194  		for i := 1; i <= dtcommon.RetryTimes; i++ {
   195  			err = dtclient.DeviceTwinTrans(add, deletes, update)
   196  			if err == nil {
   197  				break
   198  			}
   199  			time.Sleep(dtcommon.RetryInterval)
   200  		}
   201  		if err != nil {
   202  			SyncDeviceFromSqlite(context, deviceID)
   203  			klog.Errorf("Update device twin failed due to writing sql error: %v", err)
   204  		}
   205  	}
   206  
   207  	if err != nil && dealType == RestDealType {
   208  		updateResult, _ := dttype.BuildDeviceTwinResult(dttype.BaseMessage{EventID: eventID, Timestamp: now}, dealTwinResult.Result, dealType)
   209  		dealUpdateResult(context, deviceID, eventID, dtcommon.InternalErrorCode, err, updateResult)
   210  		return err
   211  	}
   212  	if dealType == RestDealType {
   213  		updateResult, _ := dttype.BuildDeviceTwinResult(dttype.BaseMessage{EventID: eventID, Timestamp: now}, dealTwinResult.Result, dealType)
   214  		dealUpdateResult(context, deviceID, eventID, dtcommon.InternalErrorCode, nil, updateResult)
   215  	}
   216  	if len(dealTwinResult.Document) > 0 {
   217  		dealDocument(context, deviceID, dttype.BaseMessage{EventID: eventID, Timestamp: now}, dealTwinResult.Document)
   218  	}
   219  
   220  	delta, ok := dttype.BuildDeviceTwinDelta(dttype.BuildBaseMessage(), deviceModel.Twin)
   221  	if ok {
   222  		dealDelta(context, deviceID, delta)
   223  	}
   224  
   225  	if len(dealTwinResult.SyncResult) > 0 {
   226  		dealSyncResult(context, deviceID, dttype.BuildBaseMessage(), dealTwinResult.SyncResult)
   227  	}
   228  	return nil
   229  }
   230  
   231  //dealUpdateResult build update result and send result, if success send the current state
   232  func dealUpdateResult(context *dtcontext.DTContext, deviceID string, eventID string, code int, err error, payload []byte) error {
   233  	klog.Infof("Deal update result of device %s: Build and send result", deviceID)
   234  
   235  	topic := dtcommon.DeviceETPrefix + deviceID + dtcommon.TwinETUpdateResultSuffix
   236  	reason := ""
   237  	para := dttype.Parameter{
   238  		EventID: eventID,
   239  		Code:    code,
   240  		Reason:  reason}
   241  	result := []byte("")
   242  	var jsonErr error
   243  	if err == nil {
   244  		result = payload
   245  	} else {
   246  		para.Reason = err.Error()
   247  		result, jsonErr = dttype.BuildErrorResult(para)
   248  		if jsonErr != nil {
   249  			klog.Errorf("Unmarshal error result of device %s error, err: %v", deviceID, jsonErr)
   250  			return jsonErr
   251  		}
   252  	}
   253  	klog.Infof("Deal update result of device %s: send result", deviceID)
   254  	return context.Send("",
   255  		dtcommon.SendToEdge,
   256  		dtcommon.CommModule,
   257  		context.BuildModelMessage(modules.BusGroup, "", topic, "publish", result))
   258  }
   259  
   260  // dealDelta  send delta
   261  func dealDelta(context *dtcontext.DTContext, deviceID string, payload []byte) error {
   262  	topic := dtcommon.DeviceETPrefix + deviceID + dtcommon.TwinETDeltaSuffix
   263  	klog.Infof("Deal delta of device %s: send delta", deviceID)
   264  	return context.Send("",
   265  		dtcommon.SendToEdge,
   266  		dtcommon.CommModule,
   267  		context.BuildModelMessage(modules.BusGroup, "", topic, "publish", payload))
   268  }
   269  
   270  // dealSyncResult build and send sync result, is delta update
   271  func dealSyncResult(context *dtcontext.DTContext, deviceID string, baseMessage dttype.BaseMessage, twin map[string]*dttype.MsgTwin) error {
   272  
   273  	klog.Infof("Deal sync result of device %s: sync with cloud", deviceID)
   274  	resource := "device/" + deviceID + "/twin/edge_updated"
   275  	return context.Send("",
   276  		dtcommon.SendToCloud,
   277  		dtcommon.CommModule,
   278  		context.BuildModelMessage("resource", "", resource, "update", dttype.DeviceTwinResult{BaseMessage: baseMessage, Twin: twin}))
   279  }
   280  
   281  //dealDocument build document and save current state as last state, update sqlite
   282  func dealDocument(context *dtcontext.DTContext, deviceID string, baseMessage dttype.BaseMessage, twinDocument map[string]*dttype.TwinDoc) error {
   283  
   284  	klog.Infof("Deal document of device %s: build and send document", deviceID)
   285  	payload, _ := dttype.BuildDeviceTwinDocument(baseMessage, twinDocument)
   286  	topic := dtcommon.DeviceETPrefix + deviceID + dtcommon.TwinETDocumentSuffix
   287  	klog.Infof("Deal document of device %s: send document", deviceID)
   288  	return context.Send("",
   289  		dtcommon.SendToEdge,
   290  		dtcommon.CommModule,
   291  		context.BuildModelMessage(modules.BusGroup, "", topic, "publish", payload))
   292  }
   293  
   294  // DealGetTwin deal get twin event
   295  func DealGetTwin(context *dtcontext.DTContext, deviceID string, payload []byte) error {
   296  
   297  	klog.Info("Deal the event of getting twin")
   298  	msg := []byte("")
   299  	para := dttype.Parameter{}
   300  	edgeGet, err := dttype.UnmarshalBaseMessage(payload)
   301  	if err != nil {
   302  		klog.Errorf("Unmarshal twin info %s failed , err: %#v", string(payload), err)
   303  		para.Code = dtcommon.BadRequestCode
   304  		para.Reason = fmt.Sprintf("Unmarshal twin info %s failed , err: %#v", string(payload), err)
   305  		var jsonErr error
   306  		msg, jsonErr = dttype.BuildErrorResult(para)
   307  		if jsonErr != nil {
   308  			klog.Errorf("Unmarshal error result error, err: %v", jsonErr)
   309  			return jsonErr
   310  		}
   311  	} else {
   312  		para.EventID = edgeGet.EventID
   313  		doc, exist := context.GetDevice(deviceID)
   314  		if !exist {
   315  			klog.Errorf("Device %s not found while getting twin", deviceID)
   316  			para.Code = dtcommon.NotFoundCode
   317  			para.Reason = fmt.Sprintf("Device %s not found while getting twin", deviceID)
   318  			var jsonErr error
   319  			msg, jsonErr = dttype.BuildErrorResult(para)
   320  			if jsonErr != nil {
   321  				klog.Errorf("Unmarshal error result error, err: %v", jsonErr)
   322  				return jsonErr
   323  			}
   324  		} else {
   325  			now := time.Now().UnixNano() / 1e6
   326  			var err error
   327  			msg, err = dttype.BuildDeviceTwinResult(dttype.BaseMessage{EventID: edgeGet.EventID, Timestamp: now}, doc.Twin, RestDealType)
   328  			if err != nil {
   329  				klog.Errorf("Build state while deal get twin err: %#v", err)
   330  				para.Code = dtcommon.InternalErrorCode
   331  				para.Reason = fmt.Sprintf("Build state while deal get twin err: %#v", err)
   332  				var jsonErr error
   333  				msg, jsonErr = dttype.BuildErrorResult(para)
   334  				if jsonErr != nil {
   335  					klog.Errorf("Unmarshal error result error, err: %v", jsonErr)
   336  					return jsonErr
   337  				}
   338  			}
   339  		}
   340  	}
   341  	topic := dtcommon.DeviceETPrefix + deviceID + dtcommon.TwinETGetResultSuffix
   342  	klog.Infof("Deal the event of getting twin of device %s: send result ", deviceID)
   343  	return context.Send("",
   344  		dtcommon.SendToEdge,
   345  		dtcommon.CommModule,
   346  		context.BuildModelMessage(modules.BusGroup, "", topic, "publish", msg))
   347  }
   348  
   349  //dealtype 0:update ,2:cloud_update,1:detail result,3:deleted
   350  func dealVersion(version *dttype.TwinVersion, reqVesion *dttype.TwinVersion, dealType int) (bool, error) {
   351  	if dealType == RestDealType {
   352  		version.EdgeVersion = version.EdgeVersion + 1
   353  	} else if dealType >= SyncDealType {
   354  		if reqVesion == nil {
   355  			if dealType == SyncTwinDeleteDealType {
   356  				return true, nil
   357  			}
   358  			return false, errors.New("Version not allowed be nil while syncing")
   359  		}
   360  		if version.CloudVersion > reqVesion.CloudVersion {
   361  			return false, errors.New("Version not allowed")
   362  		}
   363  		if version.EdgeVersion > reqVesion.EdgeVersion {
   364  			return false, errors.New("Not allowed to sync due to version conflict")
   365  		}
   366  		version.CloudVersion = reqVesion.CloudVersion
   367  		version.EdgeVersion = reqVesion.EdgeVersion
   368  	}
   369  	return true, nil
   370  }
   371  
   372  func dealTwinDelete(returnResult *dttype.DealTwinResult, deviceID string, key string, twin *dttype.MsgTwin, msgTwin *dttype.MsgTwin, dealType int) error {
   373  	document := returnResult.Document
   374  	document[key] = &dttype.TwinDoc{}
   375  	copytwin := dttype.CopyMsgTwin(twin, true)
   376  	document[key].LastState = &copytwin
   377  	cols := make(map[string]interface{})
   378  	syncResult := returnResult.SyncResult
   379  	syncResult[key] = &dttype.MsgTwin{}
   380  	update := returnResult.Update
   381  	isChange := false
   382  	if msgTwin == nil && dealType == RestDealType && *twin.Optional || dealType >= SyncDealType && strings.Compare(msgTwin.Metadata.Type, "deleted") == 0 {
   383  		if twin.Metadata != nil && strings.Compare(twin.Metadata.Type, "deleted") == 0 {
   384  			return nil
   385  		}
   386  		if dealType != RestDealType {
   387  			dealType = SyncTwinDeleteDealType
   388  		}
   389  		hasTwinExpected := true
   390  		if twin.ExpectedVersion == nil {
   391  			twin.ExpectedVersion = &dttype.TwinVersion{}
   392  			hasTwinExpected = false
   393  		}
   394  		if hasTwinExpected {
   395  			expectedVersion := twin.ExpectedVersion
   396  
   397  			var msgTwinExpectedVersion *dttype.TwinVersion
   398  			if dealType != RestDealType {
   399  				msgTwinExpectedVersion = msgTwin.ExpectedVersion
   400  			}
   401  			ok, _ := dealVersion(expectedVersion, msgTwinExpectedVersion, dealType)
   402  			if !ok {
   403  				if dealType != RestDealType {
   404  					copySync := dttype.CopyMsgTwin(twin, false)
   405  					syncResult[key] = &copySync
   406  					delete(document, key)
   407  					returnResult.SyncResult = syncResult
   408  					return nil
   409  				}
   410  			} else {
   411  				expectedVersionJSON, _ := json.Marshal(expectedVersion)
   412  				cols["expected_version"] = string(expectedVersionJSON)
   413  				cols["attr_type"] = "deleted"
   414  				cols["expected_meta"] = nil
   415  				cols["expected"] = nil
   416  				if twin.Expected == nil {
   417  					twin.Expected = &dttype.TwinValue{}
   418  				}
   419  				twin.Expected.Value = nil
   420  				twin.Expected.Metadata = nil
   421  				twin.ExpectedVersion = expectedVersion
   422  				twin.Metadata = &dttype.TypeMetadata{Type: "deleted"}
   423  				if dealType == RestDealType {
   424  					copySync := dttype.CopyMsgTwin(twin, false)
   425  					syncResult[key] = &copySync
   426  				}
   427  				document[key].CurrentState = nil
   428  				isChange = true
   429  			}
   430  		}
   431  		hasTwinActual := true
   432  
   433  		if twin.ActualVersion == nil {
   434  			twin.ActualVersion = &dttype.TwinVersion{}
   435  			hasTwinActual = false
   436  		}
   437  		if hasTwinActual {
   438  			actualVersion := twin.ActualVersion
   439  			var msgTwinActualVersion *dttype.TwinVersion
   440  			if dealType != RestDealType {
   441  				msgTwinActualVersion = msgTwin.ActualVersion
   442  			}
   443  			ok, _ := dealVersion(actualVersion, msgTwinActualVersion, dealType)
   444  			if !ok {
   445  				if dealType != RestDealType {
   446  					copySync := dttype.CopyMsgTwin(twin, false)
   447  					syncResult[key] = &copySync
   448  					delete(document, key)
   449  					returnResult.SyncResult = syncResult
   450  					return nil
   451  				}
   452  			} else {
   453  				actualVersionJSON, _ := json.Marshal(actualVersion)
   454  
   455  				cols["actual_version"] = string(actualVersionJSON)
   456  				cols["attr_type"] = "deleted"
   457  				cols["actual_meta"] = nil
   458  				cols["actual"] = nil
   459  				if twin.Actual == nil {
   460  					twin.Actual = &dttype.TwinValue{}
   461  				}
   462  				twin.Actual.Value = nil
   463  				twin.Actual.Metadata = nil
   464  				twin.ActualVersion = actualVersion
   465  				twin.Metadata = &dttype.TypeMetadata{Type: "deleted"}
   466  				if dealType == RestDealType {
   467  					copySync := dttype.CopyMsgTwin(twin, false)
   468  					syncResult[key] = &copySync
   469  				}
   470  				document[key].CurrentState = nil
   471  				isChange = true
   472  			}
   473  		}
   474  	}
   475  
   476  	if isChange {
   477  		update = append(update, dtclient.DeviceTwinUpdate{DeviceID: deviceID, Name: key, Cols: cols})
   478  		returnResult.Update = update
   479  		if dealType == RestDealType {
   480  			returnResult.Result[key] = nil
   481  			returnResult.SyncResult = syncResult
   482  		} else {
   483  			delete(syncResult, key)
   484  		}
   485  		returnResult.Document = document
   486  	} else {
   487  		delete(document, key)
   488  		delete(syncResult, key)
   489  
   490  	}
   491  
   492  	return nil
   493  }
   494  
   495  //0:expected ,1 :actual
   496  func isTwinValueDiff(twin *dttype.MsgTwin, msgTwin *dttype.MsgTwin, dealType int) (bool, error) {
   497  	hasTwin := false
   498  	hasMsgTwin := false
   499  	twinValue := twin.Expected
   500  	msgTwinValue := msgTwin.Expected
   501  
   502  	if dealType == DealActual {
   503  		twinValue = twin.Actual
   504  		msgTwinValue = msgTwin.Actual
   505  	}
   506  	if twinValue != nil {
   507  		hasTwin = true
   508  	}
   509  	if msgTwinValue != nil {
   510  		hasMsgTwin = true
   511  	}
   512  	valueType := "string"
   513  	if strings.Compare(twin.Metadata.Type, "deleted") == 0 {
   514  		if msgTwin.Metadata != nil {
   515  			valueType = msgTwin.Metadata.Type
   516  		}
   517  	} else {
   518  		valueType = twin.Metadata.Type
   519  	}
   520  	if hasMsgTwin {
   521  		if hasTwin {
   522  
   523  			err := dtcommon.ValidateValue(valueType, *msgTwinValue.Value)
   524  			if err != nil {
   525  				return false, err
   526  			}
   527  			return true, nil
   528  		}
   529  		return true, nil
   530  	}
   531  	return false, nil
   532  }
   533  
   534  func dealTwinCompare(returnResult *dttype.DealTwinResult, deviceID string, key string, twin *dttype.MsgTwin, msgTwin *dttype.MsgTwin, dealType int) error {
   535  	klog.Info("dealtwincompare")
   536  	now := time.Now().UnixNano() / 1e6
   537  
   538  	document := returnResult.Document
   539  	document[key] = &dttype.TwinDoc{}
   540  	copytwin := dttype.CopyMsgTwin(twin, true)
   541  	document[key].LastState = &copytwin
   542  	if strings.Compare(twin.Metadata.Type, "deleted") == 0 {
   543  		document[key].LastState = nil
   544  	}
   545  
   546  	cols := make(map[string]interface{})
   547  
   548  	syncResult := returnResult.SyncResult
   549  	syncResult[key] = &dttype.MsgTwin{}
   550  	update := returnResult.Update
   551  	isChange := false
   552  	isSyncAllow := true
   553  	if msgTwin == nil {
   554  		return nil
   555  	}
   556  	expectedOk, expectedErr := isTwinValueDiff(twin, msgTwin, DealExpected)
   557  	if expectedOk {
   558  		value := msgTwin.Expected.Value
   559  		meta := dttype.ValueMetadata{Timestamp: now}
   560  		if twin.ExpectedVersion == nil {
   561  			twin.ExpectedVersion = &dttype.TwinVersion{}
   562  		}
   563  		version := twin.ExpectedVersion
   564  		var msgTwinExpectedVersion *dttype.TwinVersion
   565  		if dealType != RestDealType {
   566  			msgTwinExpectedVersion = msgTwin.ExpectedVersion
   567  		}
   568  		ok, err := dealVersion(version, msgTwinExpectedVersion, dealType)
   569  		if !ok {
   570  			// if reject the sync,  set the syncResult and then send the edge_updated msg
   571  			if dealType != RestDealType {
   572  				syncResult[key].Expected = &dttype.TwinValue{Value: twin.Expected.Value, Metadata: twin.Expected.Metadata}
   573  				syncResult[key].ExpectedVersion = &dttype.TwinVersion{CloudVersion: twin.ExpectedVersion.CloudVersion, EdgeVersion: twin.ExpectedVersion.EdgeVersion}
   574  
   575  				syncOptional := *twin.Optional
   576  				syncResult[key].Optional = &syncOptional
   577  
   578  				metaJSON, _ := json.Marshal(twin.Metadata)
   579  				var meta dttype.TypeMetadata
   580  				json.Unmarshal(metaJSON, &meta)
   581  				syncResult[key].Metadata = &meta
   582  
   583  				isSyncAllow = false
   584  			} else {
   585  				returnResult.Err = err
   586  				return err
   587  			}
   588  		} else {
   589  			metaJSON, _ := json.Marshal(meta)
   590  			versionJSON, _ := json.Marshal(version)
   591  			cols["expected"] = value
   592  			cols["expected_meta"] = string(metaJSON)
   593  			cols["expected_version"] = string(versionJSON)
   594  			if twin.Expected == nil {
   595  				twin.Expected = &dttype.TwinValue{}
   596  			}
   597  			twin.Expected.Value = value
   598  			twin.Expected.Metadata = &meta
   599  			twin.ExpectedVersion = version
   600  			// if rest update, set the syncResult and send the edge_updated msg
   601  			if dealType == RestDealType {
   602  				syncResult[key].Expected = &dttype.TwinValue{Value: value, Metadata: &meta}
   603  				syncResult[key].ExpectedVersion = &dttype.TwinVersion{CloudVersion: version.CloudVersion, EdgeVersion: version.EdgeVersion}
   604  				syncOptional := *twin.Optional
   605  				syncResult[key].Optional = &syncOptional
   606  				metaJSON, _ := json.Marshal(twin.Metadata)
   607  				var meta dttype.TypeMetadata
   608  				json.Unmarshal(metaJSON, &meta)
   609  				syncResult[key].Metadata = &meta
   610  			}
   611  			isChange = true
   612  		}
   613  	} else {
   614  		if expectedErr != nil && dealType == RestDealType {
   615  			returnResult.Err = expectedErr
   616  			return expectedErr
   617  		}
   618  	}
   619  	actualOk, actualErr := isTwinValueDiff(twin, msgTwin, DealActual)
   620  	if actualOk && isSyncAllow {
   621  		value := msgTwin.Actual.Value
   622  		meta := dttype.ValueMetadata{Timestamp: now}
   623  		if twin.ActualVersion == nil {
   624  			twin.ActualVersion = &dttype.TwinVersion{}
   625  		}
   626  		version := twin.ActualVersion
   627  		var msgTwinActualVersion *dttype.TwinVersion
   628  		if dealType != RestDealType {
   629  			msgTwinActualVersion = msgTwin.ActualVersion
   630  		}
   631  		ok, err := dealVersion(version, msgTwinActualVersion, dealType)
   632  		if !ok {
   633  			if dealType != RestDealType {
   634  				syncResult[key].Actual = &dttype.TwinValue{Value: twin.Actual.Value, Metadata: twin.Actual.Metadata}
   635  				syncResult[key].ActualVersion = &dttype.TwinVersion{CloudVersion: twin.ActualVersion.CloudVersion, EdgeVersion: twin.ActualVersion.EdgeVersion}
   636  				syncOptional := *twin.Optional
   637  				syncResult[key].Optional = &syncOptional
   638  				metaJSON, _ := json.Marshal(twin.Metadata)
   639  				var meta dttype.TypeMetadata
   640  				json.Unmarshal(metaJSON, &meta)
   641  				syncResult[key].Metadata = &meta
   642  				isSyncAllow = false
   643  			} else {
   644  				returnResult.Err = err
   645  				return err
   646  			}
   647  		} else {
   648  			metaJSON, _ := json.Marshal(meta)
   649  			versionJSON, _ := json.Marshal(version)
   650  			cols["actual"] = value
   651  			cols["actual_meta"] = string(metaJSON)
   652  			cols["actual_version"] = string(versionJSON)
   653  			if twin.Actual == nil {
   654  				twin.Actual = &dttype.TwinValue{}
   655  			}
   656  			twin.Actual.Value = value
   657  			twin.Actual.Metadata = &meta
   658  			twin.ActualVersion = version
   659  			if dealType == RestDealType {
   660  				syncResult[key].Actual = &dttype.TwinValue{Value: msgTwin.Actual.Value, Metadata: &meta}
   661  				syncOptional := *twin.Optional
   662  				syncResult[key].Optional = &syncOptional
   663  				metaJSON, _ := json.Marshal(twin.Metadata)
   664  				var meta dttype.TypeMetadata
   665  				json.Unmarshal(metaJSON, &meta)
   666  				syncResult[key].Metadata = &meta
   667  				syncResult[key].ActualVersion = &dttype.TwinVersion{CloudVersion: version.CloudVersion, EdgeVersion: version.EdgeVersion}
   668  			}
   669  			isChange = true
   670  		}
   671  	} else {
   672  		if actualErr != nil && dealType == RestDealType {
   673  			returnResult.Err = actualErr
   674  			return actualErr
   675  		}
   676  	}
   677  
   678  	if isSyncAllow {
   679  		if msgTwin.Optional != nil {
   680  			if *msgTwin.Optional != *twin.Optional && *twin.Optional {
   681  				optional := *msgTwin.Optional
   682  				cols["optional"] = optional
   683  				twin.Optional = &optional
   684  				syncOptional := *twin.Optional
   685  				syncResult[key].Optional = &syncOptional
   686  				isChange = true
   687  			}
   688  		}
   689  		// if update the deleted twin, allow to update attr_type
   690  		if msgTwin.Metadata != nil {
   691  			msgMetaJSON, _ := json.Marshal(msgTwin.Metadata)
   692  			twinMetaJSON, _ := json.Marshal(twin.Metadata)
   693  			if strings.Compare(string(msgMetaJSON), string(twinMetaJSON)) != 0 {
   694  				meta := dttype.CopyMsgTwin(msgTwin, true)
   695  				meta.Metadata.Type = ""
   696  				metaJSON, _ := json.Marshal(meta.Metadata)
   697  				cols["metadata"] = string(metaJSON)
   698  				if strings.Compare(twin.Metadata.Type, "deleted") == 0 {
   699  					cols["attr_type"] = msgTwin.Metadata.Type
   700  					twin.Metadata.Type = msgTwin.Metadata.Type
   701  					var meta dttype.TypeMetadata
   702  					json.Unmarshal(msgMetaJSON, &meta)
   703  					syncResult[key].Metadata = &meta
   704  				}
   705  				isChange = true
   706  			}
   707  		} else {
   708  			if strings.Compare(twin.Metadata.Type, "deleted") == 0 {
   709  				twin.Metadata = &dttype.TypeMetadata{Type: "string"}
   710  				cols["attr_type"] = "string"
   711  				syncResult[key].Metadata = twin.Metadata
   712  				isChange = true
   713  			}
   714  		}
   715  
   716  	}
   717  	if isChange {
   718  		update = append(update, dtclient.DeviceTwinUpdate{DeviceID: deviceID, Name: key, Cols: cols})
   719  		returnResult.Update = update
   720  		current := dttype.CopyMsgTwin(twin, true)
   721  		document[key].CurrentState = &current
   722  		returnResult.Document = document
   723  
   724  		if dealType == RestDealType {
   725  			copyResult := dttype.CopyMsgTwin(syncResult[key], true)
   726  			returnResult.Result[key] = &copyResult
   727  			returnResult.SyncResult = syncResult
   728  		} else {
   729  			if !isSyncAllow {
   730  				returnResult.SyncResult = syncResult
   731  			} else {
   732  				delete(syncResult, key)
   733  			}
   734  		}
   735  
   736  	} else {
   737  		if dealType == RestDealType {
   738  			delete(document, key)
   739  			delete(syncResult, key)
   740  		} else {
   741  			delete(document, key)
   742  			if !isSyncAllow {
   743  				returnResult.SyncResult = syncResult
   744  			} else {
   745  				delete(syncResult, key)
   746  			}
   747  		}
   748  
   749  	}
   750  	return nil
   751  }
   752  
   753  func dealTwinAdd(returnResult *dttype.DealTwinResult, deviceID string, key string, twins map[string]*dttype.MsgTwin, msgTwin *dttype.MsgTwin, dealType int) error {
   754  	now := time.Now().UnixNano() / 1e6
   755  	document := returnResult.Document
   756  	document[key] = &dttype.TwinDoc{}
   757  	document[key].LastState = nil
   758  	if msgTwin == nil {
   759  		return errors.New("The request body is wrong")
   760  	}
   761  	deviceTwin := dttype.MsgTwinToDeviceTwin(key, msgTwin)
   762  	deviceTwin.DeviceID = deviceID
   763  	syncResult := returnResult.SyncResult
   764  	syncResult[key] = &dttype.MsgTwin{}
   765  	isChange := false
   766  	//add deleted twin when syncing from cloud: add version
   767  	if dealType != RestDealType && strings.Compare(msgTwin.Metadata.Type, "deleted") == 0 {
   768  		if msgTwin.ExpectedVersion != nil {
   769  			versionJSON, _ := json.Marshal(msgTwin.ExpectedVersion)
   770  			deviceTwin.ExpectedVersion = string(versionJSON)
   771  		}
   772  		if msgTwin.ActualVersion != nil {
   773  			versionJSON, _ := json.Marshal(msgTwin.ActualVersion)
   774  			deviceTwin.ActualVersion = string(versionJSON)
   775  		}
   776  	}
   777  
   778  	if msgTwin.Expected != nil {
   779  		version := &dttype.TwinVersion{}
   780  		var msgTwinExpectedVersion *dttype.TwinVersion
   781  		if dealType != RestDealType {
   782  			msgTwinExpectedVersion = msgTwin.ExpectedVersion
   783  		}
   784  		ok, err := dealVersion(version, msgTwinExpectedVersion, dealType)
   785  		if !ok {
   786  			// not match
   787  			if dealType == RestDealType {
   788  				returnResult.Err = err
   789  				return err
   790  			}
   791  			// reject add twin
   792  			return nil
   793  		}
   794  		// value type default string
   795  		valueType := "string"
   796  		if msgTwin.Metadata != nil {
   797  			valueType = msgTwin.Metadata.Type
   798  		}
   799  
   800  		err = dtcommon.ValidateValue(valueType, *msgTwin.Expected.Value)
   801  		if err == nil {
   802  			meta := dttype.ValueMetadata{Timestamp: now}
   803  			metaJSON, _ := json.Marshal(meta)
   804  			versionJSON, _ := json.Marshal(version)
   805  			deviceTwin.ExpectedMeta = string(metaJSON)
   806  			deviceTwin.ExpectedVersion = string(versionJSON)
   807  			deviceTwin.Expected = *msgTwin.Expected.Value
   808  			isChange = true
   809  		} else {
   810  			delete(document, key)
   811  			delete(syncResult, key)
   812  			// reject add twin, if rest add return the err, while sync add return nil
   813  			if dealType == RestDealType {
   814  				returnResult.Err = err
   815  				return err
   816  			}
   817  			return nil
   818  		}
   819  	}
   820  
   821  	if msgTwin.Actual != nil {
   822  		version := &dttype.TwinVersion{}
   823  		var msgTwinActualVersion *dttype.TwinVersion
   824  		if dealType != RestDealType {
   825  			msgTwinActualVersion = msgTwin.ActualVersion
   826  		}
   827  		ok, err := dealVersion(version, msgTwinActualVersion, dealType)
   828  		if !ok {
   829  			if dealType == RestDealType {
   830  				returnResult.Err = err
   831  				return err
   832  			}
   833  			return nil
   834  		}
   835  		valueType := "string"
   836  		if msgTwin.Metadata != nil {
   837  			valueType = msgTwin.Metadata.Type
   838  		}
   839  		err = dtcommon.ValidateValue(valueType, *msgTwin.Actual.Value)
   840  		if err == nil {
   841  			meta := dttype.ValueMetadata{Timestamp: now}
   842  			metaJSON, _ := json.Marshal(meta)
   843  			versionJSON, _ := json.Marshal(version)
   844  			deviceTwin.ActualMeta = string(metaJSON)
   845  			deviceTwin.ActualVersion = string(versionJSON)
   846  			deviceTwin.Actual = *msgTwin.Actual.Value
   847  			isChange = true
   848  		} else {
   849  			delete(document, key)
   850  			delete(syncResult, key)
   851  			if dealType == RestDealType {
   852  				returnResult.Err = err
   853  				return err
   854  			}
   855  			return nil
   856  		}
   857  	}
   858  
   859  	//add the optional of twin
   860  	if msgTwin.Optional != nil {
   861  		optional := *msgTwin.Optional
   862  		deviceTwin.Optional = optional
   863  		isChange = true
   864  	} else {
   865  		deviceTwin.Optional = true
   866  		isChange = true
   867  	}
   868  
   869  	//add the metadata of the twin
   870  	if msgTwin.Metadata != nil {
   871  		//todo
   872  		deviceTwin.AttrType = msgTwin.Metadata.Type
   873  		msgTwin.Metadata.Type = ""
   874  		metaJSON, _ := json.Marshal(msgTwin.Metadata)
   875  		deviceTwin.Metadata = string(metaJSON)
   876  		msgTwin.Metadata.Type = deviceTwin.AttrType
   877  		isChange = true
   878  	} else {
   879  		deviceTwin.AttrType = "string"
   880  		isChange = true
   881  	}
   882  
   883  	if isChange {
   884  		twins[key] = dttype.DeviceTwinToMsgTwin([]dtclient.DeviceTwin{deviceTwin})[key]
   885  		add := returnResult.Add
   886  		add = append(add, deviceTwin)
   887  		returnResult.Add = add
   888  
   889  		copytwin := dttype.CopyMsgTwin(twins[key], true)
   890  		if strings.Compare(twins[key].Metadata.Type, "deleted") == 0 {
   891  			document[key].CurrentState = nil
   892  		} else {
   893  			document[key].CurrentState = &copytwin
   894  		}
   895  		returnResult.Document = document
   896  
   897  		copySync := dttype.CopyMsgTwin(twins[key], false)
   898  		syncResult[key] = &copySync
   899  		if dealType == RestDealType {
   900  			copyResult := dttype.CopyMsgTwin(syncResult[key], true)
   901  			returnResult.Result[key] = &copyResult
   902  			returnResult.SyncResult = syncResult
   903  		} else {
   904  			delete(syncResult, key)
   905  		}
   906  
   907  	} else {
   908  		delete(document, key)
   909  		delete(syncResult, key)
   910  	}
   911  
   912  	return nil
   913  
   914  }
   915  
   916  //DealMsgTwin get diff while updating twin
   917  func DealMsgTwin(context *dtcontext.DTContext, deviceID string, msgTwins map[string]*dttype.MsgTwin, dealType int) dttype.DealTwinResult {
   918  	add := make([]dtclient.DeviceTwin, 0)
   919  	deletes := make([]dtclient.DeviceDelete, 0)
   920  	update := make([]dtclient.DeviceTwinUpdate, 0)
   921  	result := make(map[string]*dttype.MsgTwin)
   922  	syncResult := make(map[string]*dttype.MsgTwin)
   923  	document := make(map[string]*dttype.TwinDoc)
   924  	returnResult := dttype.DealTwinResult{Add: add,
   925  		Delete:     deletes,
   926  		Update:     update,
   927  		Result:     result,
   928  		SyncResult: syncResult,
   929  		Document:   document,
   930  		Err:        nil}
   931  
   932  	deviceModel, ok := context.GetDevice(deviceID)
   933  	if !ok {
   934  		klog.Errorf("invalid device id")
   935  		return dttype.DealTwinResult{Add: add,
   936  			Delete:     deletes,
   937  			Update:     update,
   938  			Result:     result,
   939  			SyncResult: syncResult,
   940  			Document:   document,
   941  			Err:        errors.New("invalid device id")}
   942  	}
   943  
   944  	twins := deviceModel.Twin
   945  	if twins == nil {
   946  		deviceModel.Twin = make(map[string]*dttype.MsgTwin)
   947  		twins = deviceModel.Twin
   948  	}
   949  
   950  	var err error
   951  	for key, msgTwin := range msgTwins {
   952  		if twin, exist := twins[key]; exist {
   953  			if dealType >= 1 && msgTwin != nil && (msgTwin.Metadata == nil) {
   954  				klog.Infof("Not found metadata of twin")
   955  			}
   956  			if msgTwin == nil && dealType == 0 || dealType >= 1 && strings.Compare(msgTwin.Metadata.Type, "deleted") == 0 {
   957  				err = dealTwinDelete(&returnResult, deviceID, key, twin, msgTwin, dealType)
   958  				if err != nil {
   959  					return returnResult
   960  				}
   961  				continue
   962  			}
   963  			err = dealTwinCompare(&returnResult, deviceID, key, twin, msgTwin, dealType)
   964  			if err != nil {
   965  				return returnResult
   966  			}
   967  		} else {
   968  			err = dealTwinAdd(&returnResult, deviceID, key, twins, msgTwin, dealType)
   969  			if err != nil {
   970  				return returnResult
   971  			}
   972  
   973  		}
   974  
   975  	}
   976  	context.DeviceList.Store(deviceID, deviceModel)
   977  	return returnResult
   978  }