package ebaiapi import ( "crypto/md5" "fmt" "net/http" "net/url" "sort" "strings" "sync" "git.rosy.net.cn/baseapi" "git.rosy.net.cn/baseapi/platformapi" "git.rosy.net.cn/baseapi/utils" ) const ( prodURL = "https://api-be.ele.me/" signKey = "sign" secretKey = "secret" ) const ( ResponseCodeSuccess = 0 GetStoreSuccessButUnderfind = 4001 // 拉取网页饿百门店信息,但是显示门店不存在 ResponseCodeCallElmFailed = 2101 // 这个可以尝试重试 ) type ResponseResult struct { ErrNo int `json:"errno"` Error string `json:"error"` Data interface{} `json:"data"` } type API struct { platformapi.APICookie source string secret string encrypt string client *http.Client config *platformapi.APIConfig speedLimiter *platformapi.Limiter supplierID int64 locker sync.RWMutex storeCookies map[string]string } func New(source, secret string, config ...*platformapi.APIConfig) *API { // baseapi.SugarLogger.Debugf("token=%v, appKey=%v, secret=%v", token, appKey, secret) curConfig := platformapi.DefAPIConfig if len(config) > 0 { curConfig = *config[0] } api := &API{ source: source, secret: secret, client: &http.Client{Timeout: curConfig.ClientTimeout}, config: &curConfig, speedLimiter: platformapi.New(apiLimitConfigs, nil), //defaultAPILimitConfig), storeCookies: make(map[string]string), supplierID: -1, } return api } func (a *API) signParams(params url.Values) string { keyValues := make([]string, 0) for k, v := range params { if k != signKey { keyValues = append(keyValues, k+"="+v[0]) } } keyValues = append(keyValues, secretKey+"="+a.secret) sort.Strings(keyValues) finalStr := strings.Join(keyValues, "&") // baseapi.SugarLogger.Debugf("sign str:%v", finalStr) return fmt.Sprintf("%X", md5.Sum([]byte(finalStr))) } func (a *API) getShopID(body map[string]interface{}) (shopID string) { if body[KeyShopID] != nil { return body[KeyShopID].(string) } else if body[KeyBaiduShopID] != nil { return fmt.Sprint(body[KeyBaiduShopID]) } return "" } func (a *API) AccessAPI2(cmd string, body map[string]interface{}, trackInfo string) (retVal *ResponseResult, err error) { baseapi.SugarLogger.Debugf("ebai AccessAPI cmd:%s", cmd) // a.speedLimiter.AccessAPI(allAPI) a.speedLimiter.AccessAPI(cmd, a.getShopID(body)) if body == nil { body = make(map[string]interface{}, 0) } params := url.Values{ "cmd": []string{cmd}, "version": []string{"3"}, "timestamp": []string{utils.Int64ToStr(utils.GetCurTimestamp())}, "ticket": []string{utils.GetUpperUUID()}, "source": []string{a.source}, "body": []string{string(utils.MustMarshal(body))}, "encrypt": []string{a.encrypt}, } params[signKey] = []string{a.signParams(params)} encodedParams := params.Encode() err = platformapi.AccessPlatformAPIWithRetry(a.client, func() *http.Request { request, _ := http.NewRequest(http.MethodPost, prodURL, strings.NewReader(encodedParams)) request.Header.Set("Content-Type", "application/x-www-form-urlencoded") request.Header.Set("User-Agent", "ebai-golang-api") if trackInfo != "" { request.Header.Set(platformapi.KeyTrackInfo, trackInfo) } return request }, a.config, func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) { if jsonResult1 == nil { return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil") } Body := jsonResult1["body"].(map[string]interface{}) retVal = &ResponseResult{ ErrNo: int(utils.MustInterface2Int64(Body["errno"])), Error: utils.Interface2String(Body["error"]), Data: Body["data"], } if retVal.ErrNo == ResponseCodeSuccess { return platformapi.ErrLevelSuccess, nil } baseapi.SugarLogger.Debugf("ebai AccessAPI failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true)) newErr := utils.NewErrorIntCode(retVal.Error, retVal.ErrNo) // todo 临时处理超过阈值错... if (newErr.IntCode() == 20501 && strings.Index(retVal.Error, "阈值") >= 0) || (newErr.IntCode() == 20502 && strings.Index(retVal.Error, "系统繁忙") >= 0) { return platformapi.ErrLevelExceedLimit, newErr } return platformapi.ErrLevelCodeIsNotOK, newErr }) err = platformapi.RebuildError(err, body, []string{ KeyBaiduShopID, KeyShopID, KeySkuID, KeyCustomSkuID, }) return retVal, err } func (a *API) AccessAPI(cmd string, body map[string]interface{}) (retVal *ResponseResult, err error) { return a.AccessAPI2(cmd, body, "") } func (a *API) GetSupplierID() (supplierID int64) { a.locker.RLock() supplierID = a.supplierID a.locker.RUnlock() if supplierID < 0 { a.locker.Lock() defer a.locker.Unlock() a.supplierID = 0 if shopList, err := a.ShopList(SysStatusAll); err == nil { for _, shop := range shopList { if shopDetail, err := a.ShopGet2("", shop.BaiduShopID); err != nil { break } else if shopDetail.SupplierID > 0 { a.supplierID = shopDetail.SupplierID break } } } } return a.supplierID }