Files
baseapi/platformapi/yilianyunapi/yilianyunapi.go
2025-11-21 09:09:09 +08:00

295 lines
8.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package yilianyunapi
import (
"crypto/md5"
"fmt"
"net/http"
"strings"
"sync"
"time"
"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 {
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, msign string) (tokenInfo *TokenInfo, err error) {
parameter := map[string]interface{}{
"machine_code": machineCode,
"scope": "all",
}
if qrKey != "" {
parameter["qr_key"] = qrKey
} else if msign != "" {
parameter["msign"] = msign
}
result, err := a.AccessAPI(scanCodemodelApiPath, parameter, "")
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("<audio>%s,9,0</audio>", 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
}
// 设置打印机声音
func (a *API) SetSound(machineCode, voice string) (err error) {
_, err = a.AccessAPI("printer/setsound", map[string]interface{}{
"machine_code": machineCode,
"response_type": "horn", //蜂鸣器buzzer或喇叭易连云默认喇叭
"voice": voice,
}, "")
return err
}