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 = ©twin 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] = ©Sync 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] = ©Sync 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] = ©Sync 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] = ©Sync 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 = ©twin 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 = ¤t 722 returnResult.Document = document 723 724 if dealType == RestDealType { 725 copyResult := dttype.CopyMsgTwin(syncResult[key], true) 726 returnResult.Result[key] = ©Result 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 = ©twin 894 } 895 returnResult.Document = document 896 897 copySync := dttype.CopyMsgTwin(twins[key], false) 898 syncResult[key] = ©Sync 899 if dealType == RestDealType { 900 copyResult := dttype.CopyMsgTwin(syncResult[key], true) 901 returnResult.Result[key] = ©Result 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 }