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" scanCodemodelApiPath = "oauth/scancodemodel" ) 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"` MachineCode string `json:"machine_code"` } type PrinterOrderResult struct { Content string `json:"content"` ID string `json:"id"` OriginID string `json:"origin_id"` PrintTime string `json:"print_time"` ReceivingTime string `json:"receiving_time"` Status int `json:"status"` } 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{}, token string) (retVal map[string]interface{}, err error) { if !IsStrToken(token) { token = "" } 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 && scanCodemodelApiPath != apiName { if token == "" { token = a.GetToken() } params["access_token"] = token } 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(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) { if jsonResult1 == nil { return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil") } 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 { if err = utils.Map2StructByJson(result, &tokenInfo, false); err == nil { a.SetToken(tokenInfo.AccessToken) } } return tokenInfo, err } func (a *API) Code2Token(code string) (tokenInfo *TokenInfo, err error) { result, err := a.AccessAPI(oathApiPath, map[string]interface{}{ "grant_type": "authorization_code", "scope": "all", "code": code, }, "") if err == nil { err = utils.Map2StructByJson(result, &tokenInfo, false) } return tokenInfo, err } func (a *API) RefreshToken(refreshToken string) (tokenInfo *TokenInfo, err error) { result, err := a.AccessAPI(oathApiPath, map[string]interface{}{ "grant_type": "refresh_token", "scope": "all", "refresh_token": refreshToken, }, "") if err == nil { err = utils.Map2StructByJson(result, &tokenInfo, false) } 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, token string) (err error) { if orderID == "" { orderID = utils.GetUUID() } _, err = a.AccessAPI("print/index", map[string]interface{}{ "machine_code": machineCode, "origin_id": orderID, "content": content, }, token) return err } func (a *API) PrintMsg(machineCode, orderID, content string) (err error) { return a.printMsg(machineCode, orderID, content, "") } func (a *API) PrintMsgWithToken(machineCode, orderID, content, token string) (err error) { return a.printMsg(machineCode, orderID, content, token) } func (a *API) getPrintStatus(machineCode, token string) (state int, err error) { result, err := a.AccessAPI("printer/getprintstatus", map[string]interface{}{ "machine_code": machineCode, }, token) if err != nil { return 0, err } return int(utils.Str2Int64(utils.Interface2String(result["state"]))), nil } func (a *API) GetPrintStatus(machineCode string) (state int, err error) { return a.getPrintStatus(machineCode, "") } func (a *API) GetPrintStatusWithToken(machineCode, token string) (state int, err error) { return a.getPrintStatus(machineCode, token) } func (a *API) GetPrinterToken(machineCode, qrKey string) (tokenInfo *TokenInfo, err error) { result, err := a.AccessAPI(scanCodemodelApiPath, map[string]interface{}{ "machine_code": machineCode, "qr_key": qrKey, "scope": "all", }, "") if err == nil { err = utils.Map2StructByJson(result, &tokenInfo, false) } return tokenInfo, err } func IsStrToken(possibleToken string) bool { return len(possibleToken) >= len("d65578a6fa414d738e0c44f85ac4b950") } func (a *API) CancelAll(machineCode, token string) (err error) { _, err = a.AccessAPI("printer/cancelall", map[string]interface{}{ "machine_code": machineCode, }, token) return err } func (a *API) PlayText(machineCode, orderID, text, token string) (err error) { return a.printMsg(machineCode, orderID, fmt.Sprintf("", strings.Replace(text, ",", ".", -1)), token) } // pageIndex从1开始,pageSize最大为100 func (a *API) GetOrderPagingList(machineCode, token string, pageIndex, pageSize int) (orderResultList []*PrinterOrderResult, err error) { result, err := a.AccessAPI("printer/getorderpaginglist", map[string]interface{}{ "machine_code": machineCode, "page_index": pageIndex, "page_size": pageSize, }, token) if err != nil { err = utils.Map2StructByJson(result, &orderResultList, false) } return orderResultList, err }