github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edge/pkg/devicetwin/process.go (about) 1 package devicetwin 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "errors" 7 "strings" 8 "sync" 9 "time" 10 11 "k8s.io/klog" 12 13 beehiveContext "github.com/kubeedge/beehive/pkg/core/context" 14 "github.com/kubeedge/beehive/pkg/core/model" 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/dtmodule" 19 "github.com/kubeedge/kubeedge/edge/pkg/devicetwin/dttype" 20 ) 21 22 var ( 23 //EventActionMap map for event to action 24 EventActionMap map[string]map[string]string 25 //ActionModuleMap map for action to module 26 ActionModuleMap map[string]string 27 ) 28 29 //RegisterDTModule register dtmodule 30 func (dt *DeviceTwin) RegisterDTModule(name string) { 31 module := dtmodule.DTModule{ 32 Name: name, 33 } 34 35 dt.DTContexts.CommChan[name] = make(chan interface{}, 128) 36 dt.HeartBeatToModule[name] = make(chan interface{}, 128) 37 module.InitWorker(dt.DTContexts.CommChan[name], dt.DTContexts.ConfirmChan, 38 dt.HeartBeatToModule[name], dt.DTContexts) 39 dt.DTModules[name] = module 40 41 } 42 43 //distributeMsg distribute message to diff module 44 func (dt *DeviceTwin) distributeMsg(m interface{}) error { 45 msg, ok := m.(model.Message) 46 if !ok { 47 klog.Errorf("Distribute message, msg is nil") 48 return errors.New("Distribute message, msg is nil") 49 } 50 message := dttype.DTMessage{Msg: &msg} 51 if message.Msg.GetParentID() != "" { 52 klog.Infof("Send msg to the %s module in twin", dtcommon.CommModule) 53 confirmMsg := dttype.DTMessage{Msg: model.NewMessage(message.Msg.GetParentID()), Action: dtcommon.Confirm} 54 if err := dt.DTContexts.CommTo(dtcommon.CommModule, &confirmMsg); err != nil { 55 return err 56 } 57 } 58 if !classifyMsg(&message) { 59 return errors.New("Not found action") 60 } 61 if ActionModuleMap == nil { 62 initActionModuleMap() 63 } 64 65 if moduleName, exist := ActionModuleMap[message.Action]; exist { 66 //how to deal write channel error 67 klog.Infof("Send msg to the %s module in twin", moduleName) 68 if err := dt.DTContexts.CommTo(moduleName, &message); err != nil { 69 return err 70 } 71 } else { 72 klog.Info("Not found deal module for msg") 73 return errors.New("Not found deal module for msg") 74 } 75 76 return nil 77 } 78 79 func initEventActionMap() { 80 EventActionMap = make(map[string]map[string]string) 81 EventActionMap[dtcommon.MemETPrefix] = make(map[string]string) 82 EventActionMap[dtcommon.DeviceETPrefix] = make(map[string]string) 83 EventActionMap[dtcommon.MemETPrefix][dtcommon.MemETDetailResultSuffix] = dtcommon.MemDetailResult 84 EventActionMap[dtcommon.MemETPrefix][dtcommon.MemETUpdateSuffix] = dtcommon.MemUpdated 85 EventActionMap[dtcommon.MemETPrefix][dtcommon.MemETGetSuffix] = dtcommon.MemGet 86 EventActionMap[dtcommon.DeviceETPrefix][dtcommon.DeviceETStateGetSuffix] = dtcommon.DeviceStateGet 87 EventActionMap[dtcommon.DeviceETPrefix][dtcommon.DeviceETUpdatedSuffix] = dtcommon.DeviceUpdated 88 EventActionMap[dtcommon.DeviceETPrefix][dtcommon.DeviceETStateUpdateSuffix] = dtcommon.DeviceStateUpdate 89 EventActionMap[dtcommon.DeviceETPrefix][dtcommon.TwinETUpdateSuffix] = dtcommon.TwinUpdate 90 EventActionMap[dtcommon.DeviceETPrefix][dtcommon.TwinETCloudSyncSuffix] = dtcommon.TwinCloudSync 91 EventActionMap[dtcommon.DeviceETPrefix][dtcommon.TwinETGetSuffix] = dtcommon.TwinGet 92 } 93 94 func initActionModuleMap() { 95 ActionModuleMap = make(map[string]string) 96 //membership twin device event , not lifecycle event 97 ActionModuleMap[dtcommon.MemDetailResult] = dtcommon.MemModule 98 ActionModuleMap[dtcommon.MemGet] = dtcommon.MemModule 99 ActionModuleMap[dtcommon.MemUpdated] = dtcommon.MemModule 100 ActionModuleMap[dtcommon.TwinGet] = dtcommon.TwinModule 101 ActionModuleMap[dtcommon.TwinUpdate] = dtcommon.TwinModule 102 ActionModuleMap[dtcommon.TwinCloudSync] = dtcommon.TwinModule 103 ActionModuleMap[dtcommon.DeviceUpdated] = dtcommon.DeviceModule 104 ActionModuleMap[dtcommon.DeviceStateGet] = dtcommon.DeviceModule 105 ActionModuleMap[dtcommon.DeviceStateUpdate] = dtcommon.DeviceModule 106 ActionModuleMap[dtcommon.Connected] = dtcommon.CommModule 107 ActionModuleMap[dtcommon.Disconnected] = dtcommon.CommModule 108 ActionModuleMap[dtcommon.LifeCycle] = dtcommon.CommModule 109 ActionModuleMap[dtcommon.Confirm] = dtcommon.CommModule 110 } 111 112 // SyncSqlite sync sqlite 113 func SyncSqlite(context *dtcontext.DTContext) error { 114 klog.Info("Begin to sync sqlite ") 115 rows, queryErr := dtclient.QueryDeviceAll() 116 if queryErr != nil { 117 klog.Errorf("Query sqlite failed while syncing sqlite, err: %#v", queryErr) 118 return queryErr 119 } 120 if rows == nil { 121 klog.Info("Query sqlite nil while syncing sqlite") 122 return nil 123 } 124 for _, device := range *rows { 125 err := SyncDeviceFromSqlite(context, device.ID) 126 if err != nil { 127 continue 128 } 129 } 130 return nil 131 132 } 133 134 //SyncDeviceFromSqlite sync device from sqlite 135 func SyncDeviceFromSqlite(context *dtcontext.DTContext, deviceID string) error { 136 klog.Infof("Sync device detail info from DB of device %s", deviceID) 137 _, exist := context.GetDevice(deviceID) 138 if !exist { 139 var deviceMutex sync.Mutex 140 context.DeviceMutex.Store(deviceID, &deviceMutex) 141 } 142 143 defer context.Unlock(deviceID) 144 context.Lock(deviceID) 145 146 devices, err := dtclient.QueryDevice("id", deviceID) 147 if err != nil { 148 klog.Errorf("query device failed: %v", err) 149 return err 150 } 151 if len(*devices) <= 0 { 152 return errors.New("Not found device from db") 153 } 154 device := (*devices)[0] 155 156 deviceAttr, err := dtclient.QueryDeviceAttr("deviceid", deviceID) 157 if err != nil { 158 klog.Errorf("query device attr failed: %v", err) 159 return err 160 } 161 attributes := make([]dtclient.DeviceAttr, 0) 162 for _, attr := range *deviceAttr { 163 attributes = append(attributes, attr) 164 } 165 166 deviceTwin, err := dtclient.QueryDeviceTwin("deviceid", deviceID) 167 if err != nil { 168 klog.Errorf("query device twin failed: %v", err) 169 return err 170 } 171 twins := make([]dtclient.DeviceTwin, 0) 172 for _, twin := range *deviceTwin { 173 twins = append(twins, twin) 174 } 175 176 context.DeviceList.Store(deviceID, &dttype.Device{ 177 ID: deviceID, 178 Name: device.Name, 179 Description: device.Description, 180 State: device.State, 181 LastOnline: device.LastOnline, 182 Attributes: dttype.DeviceAttrToMsgAttr(attributes), 183 Twin: dttype.DeviceTwinToMsgTwin(twins)}) 184 185 return nil 186 } 187 188 func classifyMsg(message *dttype.DTMessage) bool { 189 if EventActionMap == nil { 190 initEventActionMap() 191 } 192 var identity string 193 var action string 194 msgSource := message.Msg.GetSource() 195 if strings.Compare(msgSource, "bus") == 0 { 196 idLoc := 3 197 topic := message.Msg.GetResource() 198 topicByte, err := base64.URLEncoding.DecodeString(topic) 199 if err != nil { 200 return false 201 } 202 topic = string(topicByte) 203 204 klog.Infof("classify the msg with the topic %s", topic) 205 splitString := strings.Split(topic, "/") 206 if len(splitString) == 4 { 207 if strings.HasPrefix(topic, dtcommon.LifeCycleConnectETPrefix) { 208 action = dtcommon.LifeCycle 209 } else if strings.HasPrefix(topic, dtcommon.LifeCycleDisconnectETPrefix) { 210 action = dtcommon.LifeCycle 211 } else { 212 return false 213 } 214 } else { 215 identity = splitString[idLoc] 216 loc := strings.Index(topic, identity) 217 nextLoc := loc + len(identity) 218 prefix := topic[0:loc] 219 suffix := topic[nextLoc:] 220 klog.Infof("%s %s", prefix, suffix) 221 if v, exist := EventActionMap[prefix][suffix]; exist { 222 action = v 223 } else { 224 return false 225 } 226 } 227 message.Msg.Content = []byte((message.Msg.Content).(string)) 228 message.Identity = identity 229 message.Action = action 230 klog.Infof("Classify the msg to action %s", action) 231 return true 232 } else if (strings.Compare(msgSource, "edgemgr") == 0) || (strings.Compare(msgSource, "devicecontroller") == 0) { 233 switch message.Msg.Content.(type) { 234 case []byte: 235 klog.Info("Message content type is []byte, no need to marshal again") 236 default: 237 content, err := json.Marshal(message.Msg.Content) 238 if err != nil { 239 return false 240 } 241 message.Msg.Content = content 242 } 243 if strings.Contains(message.Msg.Router.Resource, "membership/detail") { 244 message.Action = dtcommon.MemDetailResult 245 return true 246 } else if strings.Contains(message.Msg.Router.Resource, "membership") { 247 message.Action = dtcommon.MemUpdated 248 return true 249 } else if strings.Contains(message.Msg.Router.Resource, "twin/cloud_updated") { 250 message.Action = dtcommon.TwinCloudSync 251 resources := strings.Split(message.Msg.Router.Resource, "/") 252 message.Identity = resources[1] 253 return true 254 } else if strings.Contains(message.Msg.Router.Operation, "updated") { 255 resources := strings.Split(message.Msg.Router.Resource, "/") 256 if len(resources) == 2 && strings.Compare(resources[0], "device") == 0 { 257 message.Action = dtcommon.DeviceUpdated 258 message.Identity = resources[1] 259 } 260 return true 261 } 262 return false 263 264 } else if strings.Compare(msgSource, "edgehub") == 0 { 265 if strings.Compare(message.Msg.Router.Resource, "node/connection") == 0 { 266 message.Action = dtcommon.LifeCycle 267 return true 268 } 269 return false 270 } 271 return false 272 } 273 274 func (dt *DeviceTwin) runDeviceTwin() { 275 276 moduleNames := []string{dtcommon.MemModule, dtcommon.TwinModule, dtcommon.DeviceModule, dtcommon.CommModule} 277 for _, v := range moduleNames { 278 dt.RegisterDTModule(v) 279 go dt.DTModules[v].Start() 280 } 281 go func() { 282 for { 283 select { 284 case <-beehiveContext.Done(): 285 klog.Warning("Stop DeviceTwin ModulesContext Receive loop") 286 return 287 default: 288 289 } 290 if msg, ok := beehiveContext.Receive("twin"); ok == nil { 291 klog.Info("DeviceTwin receive msg") 292 err := dt.distributeMsg(msg) 293 if err != nil { 294 klog.Warningf("distributeMsg failed: %v", err) 295 } 296 } 297 } 298 }() 299 300 for { 301 select { 302 case <-time.After((time.Duration)(60) * time.Second): 303 //range to check whether has bug 304 for dtmName := range dt.DTModules { 305 health, ok := dt.DTContexts.ModulesHealth.Load(dtmName) 306 if ok { 307 now := time.Now().Unix() 308 if now-health.(int64) > 60*2 { 309 klog.Infof("%s health %v is old, and begin restart", dtmName, health) 310 go dt.DTModules[dtmName].Start() 311 } 312 } 313 } 314 for _, v := range dt.HeartBeatToModule { 315 v <- "ping" 316 } 317 case <-beehiveContext.Done(): 318 for _, v := range dt.HeartBeatToModule { 319 v <- "stop" 320 } 321 klog.Warning("Stop DeviceTwin ModulesHealth load loop") 322 return 323 } 324 } 325 }