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 }