diff --git a/platformapi/yilianyunapi/yilianyunapi.go b/platformapi/yilianyunapi/yilianyunapi.go new file mode 100644 index 00000000..2df43d0d --- /dev/null +++ b/platformapi/yilianyunapi/yilianyunapi.go @@ -0,0 +1,181 @@ +package yilianyunapi + +import ( + "crypto/md5" + "fmt" + "net/http" + "strings" + "sync" + "time" + + "git.rosy.net.cn/baseapi" + "git.rosy.net.cn/baseapi/platformapi" + "git.rosy.net.cn/baseapi/utils" +) + +const ( + prodURL = "https://open-api.10ss.net" + signKey = "sign" + timestampKey = "timestamp" + oathApiPath = "oauth/oauth" +) + +const ( + // ResponseCodeSuccess 操作成功 + ResponseCodeSuccess = "0" +) + +const ( + PrintStatusOffline = 0 + PrintStatusOnline = 1 + PrintStatusLackPaper = 2 +) + +var ( + exceedLimitCodes = map[string]int{} + canRetryCodes = map[string]int{} +) + +type API struct { + locker sync.RWMutex + accessToken string + + clientID string + clientSecret string + client *http.Client + config *platformapi.APIConfig +} + +type TokenInfo struct { + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token"` + ExpiresIn int64 `json:"expires_in"` + Scope string `json:"scope"` +} + +func New(clientID, clientSecret string, config ...*platformapi.APIConfig) *API { + curConfig := platformapi.DefAPIConfig + if len(config) > 0 { + curConfig = *config[0] + } + return &API{ + clientID: clientID, + clientSecret: clientSecret, + client: &http.Client{Timeout: curConfig.ClientTimeout}, + config: &curConfig, + } +} + +func (a *API) signParams(timestamp int64) string { + return fmt.Sprintf("%x", md5.Sum([]byte(a.clientID+utils.Int64ToStr(timestamp)+a.clientSecret))) +} + +func (a *API) AccessAPI(apiName string, apiParams map[string]interface{}) (retVal map[string]interface{}, err error) { + err = platformapi.AccessPlatformAPIWithRetry(a.client, + func() *http.Request { + timestamp := time.Now().Unix() + params := utils.MergeMaps(map[string]interface{}{ + timestampKey: timestamp, + signKey: a.signParams(timestamp), + "client_id": a.clientID, + "id": utils.GetUpperUUID(), + }, apiParams) + if oathApiPath != apiName { + params["access_token"] = a.GetToken() + } + request, _ := http.NewRequest(http.MethodPost, utils.GenerateGetURL(prodURL, apiName, nil), strings.NewReader(utils.Map2URLValues(params).Encode())) + request.Header.Set("charset", "UTF-8") + request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + // request.Close = true //todo 为了性能考虑还是不要关闭 + return request + }, + a.config, + func(jsonResult1 map[string]interface{}) (errLevel string, err error) { + code := utils.Interface2String(jsonResult1["error"]) + if code == ResponseCodeSuccess { + retVal, _ = jsonResult1["body"].(map[string]interface{}) + return platformapi.ErrLevelSuccess, nil + } + newErr := utils.NewErrorCode(jsonResult1["error_description"].(string), code) + if _, ok := exceedLimitCodes[code]; ok { + return platformapi.ErrLevelExceedLimit, newErr + } else if _, ok := canRetryCodes[code]; ok { + return platformapi.ErrLevelRecoverableErr, newErr + } else { + baseapi.SugarLogger.Debugf("yilianyun AccessAPI failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true)) + return platformapi.ErrLevelCodeIsNotOK, newErr + } + }) + return retVal, err +} + +func (a *API) SetToken(newToken string) bool { + curToken := a.GetToken() + if curToken != newToken { + a.locker.Lock() + defer a.locker.Unlock() + a.accessToken = newToken + return true + } + return false +} + +func (a *API) GetToken() string { + a.locker.RLock() + defer a.locker.RUnlock() + return a.accessToken +} + +func (a *API) RetrieveToken() (tokenInfo *TokenInfo, err error) { + result, err := a.AccessAPI(oathApiPath, map[string]interface{}{ + "grant_type": "client_credentials", + "scope": "all", + }) + if err != nil { + return nil, err + } + tokenInfo = &TokenInfo{} + if err = utils.Map2StructByJson(result, tokenInfo, false); err == nil { + a.SetToken(tokenInfo.AccessToken) + } + return tokenInfo, err +} + +func (a *API) AddPrinter(machineCode, msign, printerName string) (err error) { + _, err = a.AccessAPI("printer/addprinter", map[string]interface{}{ + "machine_code": machineCode, + "msign": msign, + "print_name": printerName, + }) + return err +} + +func (a *API) DeletePrinter(machineCode string) (err error) { + _, err = a.AccessAPI("printer/deleteprinter", map[string]interface{}{ + "machine_code": machineCode, + }) + return err +} + +func (a *API) PrintMsg(machineCode, orderID, content string) (err error) { + if orderID == "" { + orderID = utils.GetUUID() + } + _, err = a.AccessAPI("print/index", map[string]interface{}{ + "machine_code": machineCode, + "origin_id": orderID, + "content": content, + }) + return err +} + +func (a *API) GetPrintStatus(machineCode string) (state int, err error) { + result, err := a.AccessAPI("printer/getprintstatus", map[string]interface{}{ + "machine_code": machineCode, + }) + if err != nil { + return 0, err + } + return int(utils.Str2Int64(utils.Interface2String(result["state"]))), nil +} diff --git a/platformapi/yilianyunapi/yilianyunapi_test.go b/platformapi/yilianyunapi/yilianyunapi_test.go new file mode 100644 index 00000000..ba545d97 --- /dev/null +++ b/platformapi/yilianyunapi/yilianyunapi_test.go @@ -0,0 +1,58 @@ +package yilianyunapi + +import ( + "testing" + + "git.rosy.net.cn/baseapi" + "git.rosy.net.cn/baseapi/utils" + + "go.uber.org/zap" +) + +var ( + api *API + sugarLogger *zap.SugaredLogger +) + +func init() { + logger, _ := zap.NewDevelopment() + sugarLogger = logger.Sugar() + baseapi.Init(sugarLogger) + + api = New("1039586024", "4885d07c2997b661102e4b6099c0bf3b") + api.SetToken("a25e039ea5d14a7aa61653eb58118d9c") +} + +func handleError(t *testing.T, err error) { + if err != nil { + sugarLogger.Debug(err) + t.Fatal(err.Error()) + } +} + +func TestRetrieveToken(t *testing.T) { + token, err := api.RetrieveToken() + handleError(t, err) + baseapi.SugarLogger.Debug(utils.Format4Output(token, false)) +} + +func TestAddPrinter(t *testing.T) { + err := api.AddPrinter("4004600675", "fem2ukwvduik", "测试打印机1") + handleError(t, err) +} + +func TestDeletePrinter(t *testing.T) { + err := api.DeletePrinter("4004600675") + handleError(t, err) +} + +func TestPrintMsg(t *testing.T) { + err := api.PrintMsg("4004600675", utils.GetUUID(), "hello world") + handleError(t, err) +} + +func TestGetPrintStatus(t *testing.T) { + state, err := api.GetPrintStatus("4004600675") + handleError(t, err) + baseapi.SugarLogger.Debug(state) +}