package main import ( "context" "encoding/json" "errors" "sparrow/pkg/productconfig" "sparrow/pkg/rpcs" "github.com/opentracing/opentracing-go/ext" "github.com/opentracing/opentracing-go" "net/http" "sparrow/pkg/models" "sparrow/pkg/server" "github.com/go-martini/martini" "github.com/martini-contrib/render" ) const ( ErrOK = 0 ErrSystemFault = 10001 ErrProductNotFound = 10002 ErrDeviceNotFound = 10003 ErrDeviceNotOnline = 10004 ErrWrongRequestFormat = 10005 ErrWrongProductConfig = 10006 ErrWrongQueryFormat = 10007 ErrAccessDenied = 10008 ErrIllegalityAction = 10009 //非法操作 ErrWrongSecret = 10010 // ) var ( // ErrBadRequestString 参数不全错误 errBadRequestString = errors.New("请求参数不全") errIllegalityString = errors.New("非法操作") ) const ( defaultTimeOut = 3 // seconds ) func renderError(code int, err error) Common { result := Common{} result.Code = code result.Message = err.Error() server.Log.Error(err.Error()) return result } func done(result interface{}) Common { return Common{ Code: ErrOK, Message: "success", Result: result, } } // GetDeviceInfoByKey get device info with device key func GetDeviceInfoByKey(params martini.Params, req *http.Request, r render.Render) { key := req.URL.Query().Get("device_key") server.Log.Printf("ACTION GetDeviceInfoByKey, key:: %v", key) device := &models.Device{} span, ctx := opentracing.StartSpanFromContext(context.Background(), "GetDeviceInfoByKey") defer span.Finish() ext.SpanKindRPCClient.Set(span) span.SetTag("device_key", key) err := server.RPCCallByName(ctx, rpcs.RegistryServerName, "Registry.ValidateDevice", key, device) if err != nil { r.JSON(http.StatusOK, renderError(ErrDeviceNotFound, err)) return } result := DeviceInfoResponse{ Data: DeviceInfoData{ Identifier: device.DeviceIdentifier, Name: device.DeviceName, Description: device.DeviceDescription, Version: device.DeviceVersion, }, } r.JSON(http.StatusOK, result) return } // GetDeviceInfoByIdentifier get device info with device identifier func GetDeviceInfoByIdentifier(urlparams martini.Params, r render.Render) { identifier := urlparams["identifier"] server.Log.Printf("ACTION GetDeviceInfoByIdentifier, identifier:: %v", identifier) device := &models.Device{} span, ctx := opentracing.StartSpanFromContext(context.Background(), "GetDeviceInfoByIdentifier") defer span.Finish() ext.SpanKindRPCClient.Set(span) span.SetTag("identifier", identifier) err := server.RPCCallByName(ctx, rpcs.RegistryServerName, "Registry.FindDeviceByIdentifier", identifier, device) if err != nil { r.JSON(http.StatusOK, renderError(ErrDeviceNotFound, err)) return } result := DeviceInfoResponse{ Data: DeviceInfoData{ Identifier: device.DeviceIdentifier, Name: device.DeviceName, Description: device.DeviceDescription, Version: device.DeviceVersion, }, } r.JSON(http.StatusOK, result) return } func GetDeviceCurrentStatus(device *models.Device, config *productconfig.ProductConfig, urlparams martini.Params, r render.Render) { server.Log.Printf("ACTION GetDeviceCurrentStatus, identifier:: %v", device.DeviceIdentifier) statusargs := rpcs.ArgsGetStatus{ Id: device.RecordId, } statusreply := rpcs.ReplyGetStatus{} //opentracing span, ctx := opentracing.StartSpanFromContext(context.Background(), "GetDeviceCurrentStatus") defer span.Finish() ext.SpanKindRPCClient.Set(span) err := server.RPCCallByName(ctx, rpcs.ControllerName, "Controller.GetStatus", statusargs, &statusreply) if err != nil { server.Log.Errorf("get devie status error: %v", err) r.JSON(http.StatusOK, renderError(ErrSystemFault, err)) return } status, err := config.StatusToMap(statusreply.Status) if err != nil { r.JSON(http.StatusOK, renderError(ErrWrongRequestFormat, err)) return } result := DeviceStatusResponse{ Data: status, } r.JSON(http.StatusOK, result) return } // GetDeviceLatestStatus get device latest status func GetDeviceLatestStatus() { } // SetDeviceStatus set device status func SetDeviceStatus(device *models.Device, config *productconfig.ProductConfig, urlparams martini.Params, req *http.Request, r render.Render) { server.Log.Printf("ACTION GetDeviceCurrentStatus, identifier:: %v,request: %v", device.DeviceIdentifier, req.Body) var args interface{} decoder := json.NewDecoder(req.Body) err := decoder.Decode(&args) if err != nil { r.JSON(http.StatusOK, renderError(ErrWrongRequestFormat, err)) return } m, ok := args.(map[string]interface{}) if !ok { r.JSON(http.StatusOK, renderError(ErrWrongRequestFormat, err)) return } status, err := config.MapToStatus(m) if err != nil { r.JSON(http.StatusOK, renderError(ErrWrongRequestFormat, err)) return } statusargs := rpcs.ArgsSetStatus{ DeviceId: device.RecordId, Status: status, } statusreply := rpcs.ReplySetStatus{} //opentracing span, ctx := opentracing.StartSpanFromContext(context.Background(), "SetDeviceStatus") defer span.Finish() ext.SpanKindRPCClient.Set(span) err = server.RPCCallByName(ctx, rpcs.ControllerName, "Controller.SetStatus", statusargs, &statusreply) if err != nil { server.Log.Errorf("set devie status error: %v", err) r.JSON(http.StatusOK, renderError(ErrSystemFault, err)) return } r.JSON(http.StatusOK, Common{}) return } // SendCommandToDevice send command to device func SendCommandToDevice(device *models.Device, config *productconfig.ProductConfig, urlparams martini.Params, req *http.Request, r render.Render) { timeout := req.URL.Query().Get("timeout") server.Log.Printf("ACTION SendCommandToDevice, identifier:: %v, request: %v, timeout: %v", device.DeviceIdentifier, req.Body, timeout) var args interface{} decoder := json.NewDecoder(req.Body) err := decoder.Decode(&args) if err != nil { r.JSON(http.StatusOK, renderError(ErrWrongRequestFormat, err)) return } m, ok := args.(map[string]interface{}) if !ok { r.JSON(http.StatusOK, renderError(ErrWrongRequestFormat, err)) return } command, err := config.MapToCommand(m) if err != nil { r.JSON(http.StatusOK, renderError(ErrWrongRequestFormat, err)) return } cmdargs := rpcs.ArgsSendCommand{ DeviceId: device.RecordId, SubDevice: uint16(command.Head.SubDeviceid), No: uint16(command.Head.No), WaitTime: uint32(defaultTimeOut), Params: command.Params, } cmdreply := rpcs.ReplySendCommand{} //opentracing span, ctx := opentracing.StartSpanFromContext(context.Background(), "SendCommandToDevice") defer span.Finish() ext.SpanKindRPCClient.Set(span) err = server.RPCCallByName(ctx, rpcs.ControllerName, "Controller.SendCommand", cmdargs, &cmdreply) if err != nil { server.Log.Errorf("send devie command error: %v", err) r.JSON(http.StatusOK, renderError(ErrSystemFault, err)) return } r.JSON(http.StatusOK, Common{}) return } // AddRule 增加设备规则 func AddRule(device *models.Device, req *http.Request, r render.Render) { var ruleReq CreateRuleRequest decoder := json.NewDecoder(req.Body) err := decoder.Decode(&ruleReq) if err != nil { r.JSON(http.StatusOK, renderError(ErrWrongRequestFormat, err)) return } rule := &models.Rule{ DeviceID: device.RecordId, RuleType: ruleReq.Type, Trigger: ruleReq.Trigger, Target: ruleReq.Target, Action: ruleReq.Action, } reply := &rpcs.ReplyEmptyResult{} //opentracing span, ctx := opentracing.StartSpanFromContext(context.Background(), "AddRule") defer span.Finish() ext.SpanKindRPCClient.Set(span) err = server.RPCCallByName(ctx, rpcs.RegistryServerName, "Registry.CreateRule", rule, reply) if err != nil { server.Log.Errorf("create device rule error: %v", err) r.JSON(http.StatusOK, renderError(ErrSystemFault, err)) return } r.JSON(http.StatusOK, Common{}) return } func AppAuth(req *http.Request, r render.Render) { var ruleReq rpcs.ArgsAppAuth decoder := json.NewDecoder(req.Body) err := decoder.Decode(&ruleReq) if err != nil { r.JSON(http.StatusOK, renderError(ErrWrongRequestFormat, err)) return } span, ctx := opentracing.StartSpanFromContext(context.Background(), "AppAuth") defer span.Finish() ext.SpanKindRPCClient.Set(span) app := &models.Application{} err = server.RPCCallByName(ctx, rpcs.RegistryServerName, "Registry.FindApplicationByAppKey", ruleReq, app) if err != nil { r.JSON(http.StatusOK, renderError(ErrWrongSecret, errors.New("Invalid secret key"))) return } if app.SecretKey != ruleReq.Secretkey { // device secret is wrong. r.JSON(http.StatusOK, renderError(ErrWrongSecret, errors.New("wrong application secret."))) return } result := AppAuthDataResponse{ AccessToken: TokenMaker(app), } r.JSON(http.StatusOK, Common{ Result: result, }) return }