162 lines
4.7 KiB
Go
162 lines
4.7 KiB
Go
package express_tool
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"github.com/pkg/errors"
|
||
"io"
|
||
"log"
|
||
"net/http"
|
||
"net/url"
|
||
"time"
|
||
)
|
||
|
||
type AliCloudExpressClient struct {
|
||
AppCode string
|
||
Host string
|
||
cache ICacheAdapter
|
||
}
|
||
|
||
func NewAliCloudExpressClient(host, appCode string) *AliCloudExpressClient {
|
||
return &AliCloudExpressClient{
|
||
AppCode: appCode,
|
||
Host: host,
|
||
}
|
||
}
|
||
|
||
func (a *AliCloudExpressClient) GetLogisticsInfo(mobile, number string) (res *ExpressRes, err error) {
|
||
if mobile == "" || number == "" {
|
||
return nil, errors.New("请输入手机号和物流单号")
|
||
}
|
||
// 设置参数
|
||
params := url.Values{}
|
||
params.Add("mobile", mobile)
|
||
params.Add("number", number)
|
||
// 拼接URL
|
||
var fullURL string
|
||
fullURL, err = url.JoinPath(a.Host)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "查询物流信息失败, 拼接路径错误! 手机号:%s, 物流单号:%s", mobile, number)
|
||
}
|
||
// 拼接参数
|
||
fullURL = fmt.Sprintf("%s?%s", fullURL, params.Encode())
|
||
// 创建HTTP客户端
|
||
client := &http.Client{}
|
||
// 创建请求
|
||
var req *http.Request
|
||
req, err = http.NewRequest(http.MethodGet, fullURL, nil)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "查询物流信息失败, 创建请求失败! 手机号:%s, 物流单号:%s", mobile, number)
|
||
}
|
||
|
||
// 设置请求头
|
||
req.Header.Add("Authorization", "APPCODE "+a.AppCode)
|
||
|
||
// 发送请求
|
||
client.Timeout = 2 * time.Second
|
||
var resp *http.Response
|
||
resp, err = client.Do(req)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "查询物流信息失败, 发送请求失败! 手机号:%s, 物流单号:%s", mobile, number)
|
||
}
|
||
defer func(Body io.ReadCloser) {
|
||
err = Body.Close()
|
||
if err != nil {
|
||
log.Printf("查询物流信息失败, 关闭响应体失败! 手机号:%s, 物流单号:%s , %+v\n", mobile, number, err)
|
||
}
|
||
}(resp.Body)
|
||
|
||
// 读取响应体
|
||
var body []byte
|
||
body, err = io.ReadAll(resp.Body)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "查询物流信息失败, 读取响应体失败! 手机号:%s, 物流单号:%s", mobile, number)
|
||
}
|
||
//log.Printf("查询物流信息成功! %s\n", string(body))
|
||
|
||
// 解析JSON响应
|
||
var expressRes ExpressRes
|
||
err = json.Unmarshal(body, &expressRes)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "查询物流信息失败, 解析JSON响应失败, %s! 手机号:%s, 物流单号:%s", string(body), mobile, number)
|
||
}
|
||
|
||
if expressRes.Code != 0 {
|
||
return &expressRes, errors.Wrapf(err, "查询物流信息失败! expressRes:%+v 手机号:%s, 物流单号:%s", expressRes, mobile, number)
|
||
}
|
||
|
||
if expressRes.Data == nil {
|
||
return &expressRes, errors.Wrapf(err, "查询物流信息失败,没有查询到物流信息! expressRes:%+v 手机号:%s, 物流单号:%s", expressRes, mobile, number)
|
||
}
|
||
|
||
return &expressRes, nil
|
||
}
|
||
|
||
func (a *AliCloudExpressClient) Set(cache ICacheAdapter) {
|
||
a.cache = cache
|
||
}
|
||
|
||
func (a *AliCloudExpressClient) GetLogisticsInfoFormCache(ctx context.Context, mobile, prefix, number string, opt ...time.Duration) (res *ExpressRes, err error) {
|
||
if a.cache != nil {
|
||
res, err = a.cache.Get(ctx, a.numberKey(prefix, number))
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "获取缓存失败, number:%s", number)
|
||
}
|
||
if res != nil {
|
||
return res, nil
|
||
}
|
||
}
|
||
res, err = a.GetLogisticsInfo(mobile, number)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "获取物流信息失败, number:%s", number)
|
||
}
|
||
|
||
var infoJson []byte
|
||
infoJson, err = json.Marshal(res)
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "无法将物流信息转换为JSON, number:%s", number)
|
||
}
|
||
|
||
if len(opt) > 0 {
|
||
err = a.cache.Set(ctx, a.numberKey(prefix, number), string(infoJson), opt[0])
|
||
if err != nil {
|
||
return nil, errors.Wrapf(err, "缓存物流信息失败, number:%s", number)
|
||
}
|
||
}
|
||
return
|
||
}
|
||
|
||
func (a *AliCloudExpressClient) DeleteLogisticsInfoCache(ctx context.Context, prefix, number string) (err error) {
|
||
if a.cache == nil {
|
||
return errors.New("缓存不能为空")
|
||
}
|
||
err = a.cache.Del(ctx, a.numberKey(prefix, number))
|
||
return err
|
||
}
|
||
|
||
// ipKey 生成Redis key
|
||
func (a *AliCloudExpressClient) numberKey(prefix, number string) string {
|
||
return fmt.Sprintf("%s:number:%s", prefix, number)
|
||
}
|
||
|
||
type ExpressRes struct {
|
||
Code int `json:"code"`
|
||
Desc string `json:"desc"`
|
||
Data *Data `json:"data"`
|
||
}
|
||
|
||
type Data struct {
|
||
State int `json:"state" dc:"物流状态【1在途中,2派件中,3已签收,4派送失败,5揽收,6退回,7转单,8疑难,9退签,10待清关,11清关中,12已清关,13清关异常】"`
|
||
Name string `json:"name" dc:"物流名"`
|
||
Com string `json:"com"`
|
||
Number string `json:"number" dc:"单号"`
|
||
Logo string `json:"logo" dc:"图标地址"`
|
||
List []*List `json:"list"`
|
||
}
|
||
|
||
type List struct {
|
||
Time string `json:"time"`
|
||
Status string `json:"status"`
|
||
}
|