From ad1a6ab5c45a61de0bc1da25ffdbcb2c1eef423f Mon Sep 17 00:00:00 2001 From: gazebo Date: Thu, 14 Jun 2018 17:50:58 +0800 Subject: [PATCH] - elm callback basic. --- business/business.go | 21 +++++++ business/elm/controller/controller.go | 40 +++++++++++++ business/elm/controller/order.go | 86 +++++++++++++++++++++++++++ business/elm/models/order.go | 12 ++++ business/freshfood/freshfood.go | 60 +++++++++++++++---- business/jd/controller/controller.go | 16 +---- business/jd/controller/order.go | 25 +++----- controllers/elm_order.go | 40 +++++++++++++ controllers/jd_order.go | 4 +- globals/globals.go | 8 +++ main.go | 2 +- routers/router.go | 7 ++- 12 files changed, 273 insertions(+), 48 deletions(-) create mode 100644 business/business.go create mode 100644 business/elm/controller/controller.go create mode 100644 business/elm/controller/order.go create mode 100644 business/elm/models/order.go create mode 100644 controllers/elm_order.go diff --git a/business/business.go b/business/business.go new file mode 100644 index 000000000..7afad645c --- /dev/null +++ b/business/business.go @@ -0,0 +1,21 @@ +package controller + +import ( + elmmodels "git.rosy.net.cn/jx-callback/business/elm/models" + "git.rosy.net.cn/jx-callback/business/jd/models" + "github.com/astaxie/beego/orm" + _ "github.com/go-sql-driver/mysql" // import your used driver +) + +// 确定这个init是最先执行的 +func init() { + // set default database + orm.RegisterDataBase("default", "mysql", "root:WebServer@1@tcp(127.0.0.1:3306)/jx-callback?charset=utf8&loc=Local", 30) + + // register model + orm.RegisterModel(new(models.Jdorder)) + orm.RegisterModel(new(elmmodels.ELMOrder)) + + // create table + orm.RunSyncdb("default", false, true) +} diff --git a/business/elm/controller/controller.go b/business/elm/controller/controller.go new file mode 100644 index 000000000..d3bbdc6c5 --- /dev/null +++ b/business/elm/controller/controller.go @@ -0,0 +1,40 @@ +package controller + +import ( + "git.rosy.net.cn/baseapi/platform/elmapi" + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/globals" + "github.com/astaxie/beego/orm" + "go.uber.org/zap" +) + +const ( + elmToken = "" //"bab2a27f99562f394b411dbb9a6214da" + elmAppKey = "KLRDcOZGrk" + elmSecret = "1fc221f8265506531da36fb613d5f5ad673f2e9a" +) + +var ( + gElmAPI *elmapi.ELMAPI + sugarLogger *zap.SugaredLogger +) + +func init() { + sugarLogger = globals.SugarLogger + token := elmToken + if token == "" { + db := orm.NewOrm() + var tokenInfo []orm.Params + num, err := db.Raw("SELECT * FROM thirdpartytoken WHERE thirdparty='eleme'").Values(&tokenInfo) + if err != nil || num != 1 { + panic(err.Error()) + } + + var tokenInfo2 map[string]interface{} + if err := utils.UnmarshalUseNumber([]byte(tokenInfo[0]["token"].(string)), &tokenInfo2); err != nil { + panic(err.Error()) + } + token = tokenInfo2["accessToken"].(string) + } + gElmAPI = elmapi.NewELMAPI(token, elmAppKey, elmSecret, sugarLogger, true) +} diff --git a/business/elm/controller/order.go b/business/elm/controller/order.go new file mode 100644 index 000000000..96ee12015 --- /dev/null +++ b/business/elm/controller/order.go @@ -0,0 +1,86 @@ +package controller + +import ( + "git.rosy.net.cn/baseapi/platform/elmapi" + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/elm/models" + "git.rosy.net.cn/jx-callback/globals" + "github.com/astaxie/beego/orm" +) + +var ( + errResponseInternal = &elmapi.ELMCallbackResponse{Message: "internal error"} + errResponseDataError = &elmapi.ELMCallbackResponse{Message: "elm data error"} + errResponseDBError = &elmapi.ELMCallbackResponse{Message: "DB error"} + errResponseCallELMAPIError = &elmapi.ELMCallbackResponse{Message: "call ELM API error"} +) + +type OrderController struct { +} + +func (o *OrderController) OrderMessage(msg *elmapi.ELMCallbackMsg) *elmapi.ELMCallbackResponse { + var innerMsg map[string]interface{} + err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg) + if err != nil { + sugarLogger.Warnf("OrderMessage unmarshal %v error:%v", msg, err) + return errResponseDataError + } + if msg.Type == elmapi.OrderValid { + return o.NewOrder(msg, innerMsg["id"].(string)) + } else if msg.Type >= elmapi.MerchantValid && msg.Type <= elmapi.OrderFinished { + return o.OrderStatusChanged(msg, innerMsg["orderId"].(string)) + } + return elmapi.ELMResponseOK +} + +func (o *OrderController) NewOrder(msg *elmapi.ELMCallbackMsg, orderId string) *elmapi.ELMCallbackResponse { + db := orm.NewOrm() + rec := &models.ELMOrder{ + OrderId: orderId, + Type: msg.Type, + } + + created, _, err := db.ReadOrCreate(rec, "OrderId") + if err != nil { + sugarLogger.Warnf("error when calling ReadOrCreate, error:%v", err) + return errResponseDBError + } + if created || rec.Type != msg.Type { + result, err := gElmAPI.GetOrder(orderId) + if err != nil { + sugarLogger.Warnf("call GetOrder error:%v", err) + return errResponseCallELMAPIError + } + err = globals.FreshFoodAPI.NewELMOrder(result) + if err != nil { + sugarLogger.Warnf("internal error:%v", err) + return errResponseInternal + } + } else { + sugarLogger.Infof("duplicate elm msg received:%v", msg) + } + return elmapi.ELMResponseOK +} + +func (o *OrderController) OrderStatusChanged(msg *elmapi.ELMCallbackMsg, orderId string) *elmapi.ELMCallbackResponse { + db := orm.NewOrm() + rec := &models.ELMOrder{ + OrderId: orderId, + } + + err := db.Read(rec, "OrderId") + if err != nil { + sugarLogger.Warnf("error when calling ReadOrCreate, error:%v", err) + return errResponseDBError + } + if rec.Type != msg.Type { + err = globals.FreshFoodAPI.ELMOrderStatus(orderId, msg.Type, utils.GetCurTimestamp()) + if err != nil { + sugarLogger.Warnf("internal error:%v", err) + return errResponseInternal + } + } else { + sugarLogger.Infof("duplicate elm msg received:%v", msg) + } + return elmapi.ELMResponseOK +} diff --git a/business/elm/models/order.go b/business/elm/models/order.go new file mode 100644 index 000000000..8b72add1a --- /dev/null +++ b/business/elm/models/order.go @@ -0,0 +1,12 @@ +package models + +type ELMOrder struct { + Id int + OrderId string `orm:"size(50);unique;null"` + Data string `orm:"type(text);null"` + Type int `orm:"null"` +} + +func (e *ELMOrder) TableName() string { + return "elemeorder" +} diff --git a/business/freshfood/freshfood.go b/business/freshfood/freshfood.go index a1aed4e64..2853ef7ff 100644 --- a/business/freshfood/freshfood.go +++ b/business/freshfood/freshfood.go @@ -27,29 +27,44 @@ const ( URL_FRESHFOOD_PARA_DELIVERYMANNO = "deliveryManNo" URL_FRESHFOOD_PARA_DELIVERYMANNAME = "deliveryManName" URL_FRESHFOOD_PARA_DELIVERYMANPHONE = "deliveryManPhone" + + URL_FRESHFOOD_PARA_ELEMEORDER = "elemeOrder" +) + +const ( + JD_VENDERID = 0 + ELM_VENDERID = 2 +) + +const ( + retryCount = 3 ) type FreshFoodAPI struct { baseURL string sugarLogger *zap.SugaredLogger - client http.Client + client *http.Client } -func NewFreshFoodAPI(baseURL string, zapLogger *zap.Logger) *FreshFoodAPI { - return &FreshFoodAPI{baseURL, zapLogger.Sugar(), http.Client{Timeout: time.Second * 5}} +func NewFreshFoodAPI(baseURL string, sugarredLogger *zap.SugaredLogger) *FreshFoodAPI { + return &FreshFoodAPI{baseURL, sugarredLogger, &http.Client{Timeout: time.Second * 5}} } func (f *FreshFoodAPI) AccessFreshFodd(apiStr string, params url.Values) error { + var err error fullURL := f.baseURL + "/" + apiStr - // _, err := f.client.PostForm(fullURL, params) - err := error(nil) - f.sugarLogger.Debug(fullURL) - if err != nil { - f.sugarLogger.Warnf("Call %s error:%v", fullURL, err) + for i := 0; i < retryCount; i++ { + // _, err := f.client.PostForm(fullURL, params) + err = error(nil) + f.sugarLogger.Debug(fullURL) + if err != nil { + f.sugarLogger.Warnf("Call %s error:%v", fullURL, err) + } } - return nil + return err } +// jd api func (f *FreshFoodAPI) NewJDOrder(jdorder *models.Jdorder) error { params := make(url.Values) params.Set(URL_FRESHFOOD_PARA_JDORDER, string(utils.MustMarshal(jdorder))) @@ -57,9 +72,9 @@ func (f *FreshFoodAPI) NewJDOrder(jdorder *models.Jdorder) error { } // todo venderId -func (f *FreshFoodAPI) JDOrderStatus(jdorder *models.Jdorder, venderId string) error { +func (f *FreshFoodAPI) JDOrderStatus(jdorder *models.Jdorder) error { params := make(url.Values) - params.Set(URL_FRESHFOOD_PARA_VENDERID, venderId) + params.Set(URL_FRESHFOOD_PARA_VENDERID, utils.Int2Str(JD_VENDERID)) params.Set(URL_FRESHFOOD_PARA_ORDERID, utils.Int64ToStr(jdorder.JdOrderId)) params.Set(URL_FRESHFOOD_PARA_ORDERSTATUS, utils.Int2Str(jdorder.OrderStatus)) params.Set(URL_FRESHFOOD_PARA_ORDERSTATUSTIME, jdorder.OrderStatusTime) @@ -68,11 +83,11 @@ func (f *FreshFoodAPI) JDOrderStatus(jdorder *models.Jdorder, venderId string) e return f.AccessFreshFodd("order/status", params) } -func (f *FreshFoodAPI) JDOrderDeliveryStatus(jdOrderDeliveryStatusMsg *jdapi.JDDeliveryStatusMsg, venderId string) error { +func (f *FreshFoodAPI) JDOrderDeliveryStatus(jdOrderDeliveryStatusMsg *jdapi.JDDeliveryStatusMsg) error { params := make(url.Values) cityName := "all" - params.Set(URL_FRESHFOOD_PARA_VENDERID, venderId) + params.Set(URL_FRESHFOOD_PARA_VENDERID, utils.Int2Str(JD_VENDERID)) params.Set(URL_FRESHFOOD_PARA_ORDERID, jdOrderDeliveryStatusMsg.OrderId) params.Set(URL_FRESHFOOD_PARA_DELIVERYSTATUS, utils.Int2Str(jdOrderDeliveryStatusMsg.DeliveryStatus)) params.Set(URL_FRESHFOOD_PARA_DLIVERYSTATUSTIME, jdOrderDeliveryStatusMsg.DeliveryStatusTime) @@ -87,3 +102,22 @@ func (f *FreshFoodAPI) JDOrderDeliveryStatus(jdOrderDeliveryStatusMsg *jdapi.JDD return f.AccessFreshFodd("delivery/status", params) } + +// elm api +func (f *FreshFoodAPI) NewELMOrder(order map[string]interface{}) error { + str := string(utils.MustMarshal(order)) + params := make(url.Values) + params.Set(URL_FRESHFOOD_PARA_ELEMEORDER, str) + + return f.AccessFreshFodd("order/eleme", params) +} + +func (f *FreshFoodAPI) ELMOrderStatus(orderId string, status int, timestamp int64) error { + params := make(url.Values) + params.Set(URL_FRESHFOOD_PARA_VENDERID, utils.Int2Str(ELM_VENDERID)) + params.Set(URL_FRESHFOOD_PARA_ORDERID, orderId) + params.Set(URL_FRESHFOOD_PARA_ORDERSTATUS, utils.Int2Str(status)) + params.Set(URL_FRESHFOOD_PARA_ORDERSTATUSTIME, utils.Timestamp2Str(timestamp)) + + return f.AccessFreshFodd("order/status", params) +} diff --git a/business/jd/controller/controller.go b/business/jd/controller/controller.go index 6ca1ebd01..597f1c43a 100644 --- a/business/jd/controller/controller.go +++ b/business/jd/controller/controller.go @@ -2,9 +2,7 @@ package controller import ( "git.rosy.net.cn/baseapi/platform/jdapi" - "git.rosy.net.cn/jx-callback/business/jd/models" "git.rosy.net.cn/jx-callback/globals" - "github.com/astaxie/beego/orm" "go.uber.org/zap" ) @@ -16,18 +14,6 @@ var ( func init() { sugarLogger = globals.SugarLogger - logger := sugarLogger.Desugar() - - gJdapi = jdapi.NewJDAPI("91633f2a-c5f5-4982-a925-a220d19095c3", "1dba76d40cac446ca500c0391a0b6c9d", "a88d031a1e7b462cb1579f12e97fe7f4", logger) - - // set default database - orm.RegisterDataBase("default", "mysql", "root:WebServer@1@tcp(127.0.0.1:3306)/jx-callback?charset=utf8&loc=Local", 30) - - // register model - orm.RegisterModel(new(models.Jdorder)) - - // create table - orm.RunSyncdb("default", false, true) - + gJdapi = jdapi.NewJDAPI("91633f2a-c5f5-4982-a925-a220d19095c3", "1dba76d40cac446ca500c0391a0b6c9d", "a88d031a1e7b462cb1579f12e97fe7f4", sugarLogger) initOrder() } diff --git a/business/jd/controller/order.go b/business/jd/controller/order.go index e39ba82db..9e96c045b 100644 --- a/business/jd/controller/order.go +++ b/business/jd/controller/order.go @@ -5,11 +5,10 @@ import ( "git.rosy.net.cn/baseapi/platform/jdapi" "git.rosy.net.cn/baseapi/utils" - "git.rosy.net.cn/jx-callback/business/freshfood" "git.rosy.net.cn/jx-callback/business/jd/models" "git.rosy.net.cn/jx-callback/compat/corm" + "git.rosy.net.cn/jx-callback/globals" "github.com/astaxie/beego/orm" - _ "github.com/go-sql-driver/mysql" // import your used driver ) const ( @@ -19,18 +18,13 @@ const ( var ( errChecker corm.DBErrorChecker orderMsgChan chan *jdapi.JDOrderMsg - - // freshFoodServerURL = "http://portal.jingxicaishi.com" - freshFoodServerURL = "http://test.jxc4.com" - freshFoodAPI *freshfood.FreshFoodAPI ) -type OrderControler struct { +type OrderController struct { } func initOrder() { errChecker = new(corm.MysqlErrorChecker) - freshFoodAPI = freshfood.NewFreshFoodAPI(freshFoodServerURL, sugarLogger.Desugar()) orderMsgChan = make(chan *jdapi.JDOrderMsg, 128) go orderMsgHandlerRoutinue() @@ -86,7 +80,7 @@ func handleOrderMsg(orderMsg *jdapi.JDOrderMsg) { } // -------------- -func (c *OrderControler) OrderStatus(order *jdapi.JDOrderMsg) *jdapi.JDOrderMsgResponse { +func (c *OrderController) OrderStatus(order *jdapi.JDOrderMsg) *jdapi.JDOrderMsgResponse { if order.StatusId != jdapi.JdOrderStatusNew && order.StatusId != jdapi.JdOrderStatusAdjust { err := normalOrderStatus(order) if err != nil { @@ -137,8 +131,8 @@ func (c *OrderControler) OrderStatus(order *jdapi.JDOrderMsg) *jdapi.JDOrderMsgR return jdSuccessResponse } -func (c *OrderControler) OrderDeliveryStatus(jdOrderDeliveryStatusMsg *jdapi.JDDeliveryStatusMsg) *jdapi.JDOrderMsgResponse { - err := freshFoodAPI.JDOrderDeliveryStatus(jdOrderDeliveryStatusMsg, "0") +func (c *OrderController) OrderDeliveryStatus(jdOrderDeliveryStatusMsg *jdapi.JDDeliveryStatusMsg) *jdapi.JDOrderMsgResponse { + err := globals.FreshFoodAPI.JDOrderDeliveryStatus(jdOrderDeliveryStatusMsg) if err != nil { sugarLogger.Errorf("Error when calling JDOrderDeliveryStatus, error:%v", err) @@ -159,7 +153,7 @@ func newOrder(order *jdapi.JDOrderMsg) error { result, err := gJdapi.LegacyQuerySingleOrder(order.BillId) acceptOrder(order) if err != nil { - sugarLogger.Warnf("error when query jd order:%s, error:%v", order.BillId, err) + sugarLogger.Errorf("error when query jd order:%s, error:%v", order.BillId, err) } else { rec := &models.Jdorder{ Id: order.Id, @@ -186,9 +180,9 @@ func newOrder(order *jdapi.JDOrderMsg) error { rec.OrderStatus = int(orderStatus) rec.OrderStatusTime = resultList0["orderStatusTime"].(string) - resultByteArr, _ := json.Marshal(data) + resultByteArr := utils.MustMarshal(data) rec.Data = string(resultByteArr) - err = freshFoodAPI.NewJDOrder(rec) + err = globals.FreshFoodAPI.NewJDOrder(rec) if err == nil { db := orm.NewOrm() _, err = db.Update(rec, "Data", "Code", "Msg", "Success", "CityName", "OrderStatus", "OrderStatusTime") @@ -228,9 +222,8 @@ func normalOrderStatus(order *jdapi.JDOrderMsg) error { rec.OrderStatus = utils.Str2Int(order.StatusId) rec.OrderStatusTime = order.Timestamp - err = freshFoodAPI.JDOrderStatus(rec, "0") + err = globals.FreshFoodAPI.JDOrderStatus(rec) if err != nil { - // todo 这里应该要加一个重试机制 sugarLogger.Warnf("access freshfood failed, error:%v", err) return err } diff --git a/controllers/elm_order.go b/controllers/elm_order.go new file mode 100644 index 000000000..b58db54e3 --- /dev/null +++ b/controllers/elm_order.go @@ -0,0 +1,40 @@ +package controllers + +import ( + "encoding/json" + + "git.rosy.net.cn/baseapi/platform/elmapi" + "git.rosy.net.cn/jx-callback/business/elm/controller" + "git.rosy.net.cn/jx-callback/globals" + "github.com/astaxie/beego" +) + +// Operations about ELMOrder +type ELMOrderController struct { + beego.Controller +} + +func (c *ELMOrderController) URLMapping() { + c.Mapping("Msg", c.Msg) +} + +// @Title all msg +// @Description create object +// @Param jd_param_json formData string true "应用级别输入参数" +// @Success 200 {string} models.Object.Id +// @Failure 403 body is empty +// @router /msg [post] +func (c *ELMOrderController) Msg() { + var obj elmapi.ELMCallbackMsg + jdParamJSON := c.Ctx.Input.RequestBody + + err := json.Unmarshal([]byte(jdParamJSON), &obj) + if err != nil { + globals.SugarLogger.Warnf("error when Unmarshal data:%v, error:%v", jdParamJSON, err) + c.Data["json"] = elmapi.ELMCallbackResponse{Message: "failed"} + } else { + cc := &controller.OrderController{} + c.Data["json"] = cc.OrderMessage(&obj) + } + c.ServeJSON() +} diff --git a/controllers/jd_order.go b/controllers/jd_order.go index 31c161449..3f7737a37 100644 --- a/controllers/jd_order.go +++ b/controllers/jd_order.go @@ -43,7 +43,7 @@ func (c *JDOrderController) handleJDCallback(obj interface{}, needUnescape bool, func (c *JDOrderController) orderStatus() { var ob jdapi.JDOrderMsg c.handleJDCallback(&ob, false, func() interface{} { - cc := controller.OrderControler{} + cc := controller.OrderController{} return cc.OrderStatus(&ob) }) } @@ -147,7 +147,7 @@ func (c *JDOrderController) ApplyCancelOrder() { func (c *JDOrderController) PushDeliveryStatus() { var ob jdapi.JDDeliveryStatusMsg c.handleJDCallback(&ob, true, func() interface{} { - cc := controller.OrderControler{} + cc := controller.OrderController{} return cc.OrderDeliveryStatus(&ob) }) } diff --git a/globals/globals.go b/globals/globals.go index 0fb005ff4..6a1166e78 100644 --- a/globals/globals.go +++ b/globals/globals.go @@ -1,14 +1,22 @@ package globals import ( + "git.rosy.net.cn/jx-callback/business/freshfood" "go.uber.org/zap" ) +const ( + freshFoodServerURL = "http://test.jxc4.com" +) + var ( SugarLogger *zap.SugaredLogger + // freshFoodServerURL = "http://portal.jingxicaishi.com" + FreshFoodAPI *freshfood.FreshFoodAPI ) func init() { logger, _ := zap.NewDevelopment() SugarLogger = logger.Sugar() + FreshFoodAPI = freshfood.NewFreshFoodAPI(freshFoodServerURL, SugarLogger) } diff --git a/main.go b/main.go index 712b5996c..58869a0a2 100644 --- a/main.go +++ b/main.go @@ -1,8 +1,8 @@ package main import ( + _ "git.rosy.net.cn/jx-callback/business" _ "git.rosy.net.cn/jx-callback/routers" - "github.com/astaxie/beego" ) diff --git a/routers/router.go b/routers/router.go index 98ae14392..43f221c99 100644 --- a/routers/router.go +++ b/routers/router.go @@ -19,5 +19,10 @@ func init() { &controllers.JDOrderController{}, ), ) - beego.AddNamespace(ns) + ns2 := beego.NewNamespace("/elem", + beego.NSInclude( + &controllers.ELMOrderController{}, + ), + ) + beego.AddNamespace(ns, ns2) }