Compare commits
No commits in common. "main" and "v1.4.0" have entirely different histories.
@ -1,161 +0,0 @@
|
||||
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"`
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
package express_tool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"log"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestAliCloudExpressClient_GetLogisticsInfo(t *testing.T) {
|
||||
type fields struct {
|
||||
AppCode string
|
||||
Host string
|
||||
}
|
||||
type args struct {
|
||||
mobile string
|
||||
number string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantRes *ExpressRes
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "test1",
|
||||
fields: fields{
|
||||
AppCode: "",
|
||||
Host: "",
|
||||
},
|
||||
args: args{
|
||||
mobile: "",
|
||||
number: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := &AliCloudExpressClient{
|
||||
AppCode: tt.fields.AppCode,
|
||||
Host: tt.fields.Host,
|
||||
}
|
||||
gotRes, err := a.GetLogisticsInfo(tt.args.mobile, tt.args.number)
|
||||
log.Println(gotRes, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAliCloudExpressClient_GetLogisticsInfoFormCache(t *testing.T) {
|
||||
rdb := redis.NewClient(&redis.Options{
|
||||
Addr: "",
|
||||
Password: "",
|
||||
DB: 1,
|
||||
})
|
||||
|
||||
// 创建缓存实例
|
||||
cache := NewRedisCache(rdb)
|
||||
a := &AliCloudExpressClient{
|
||||
AppCode: "",
|
||||
Host: "",
|
||||
cache: cache,
|
||||
}
|
||||
gotRes, err := a.GetLogisticsInfoFormCache(context.Background(), "", "", "", time.Minute)
|
||||
log.Println(gotRes, err)
|
||||
}
|
||||
|
||||
func TestAliCloudExpressClient_DeleteLogisticsInfoCache(t *testing.T) {
|
||||
rdb := redis.NewClient(&redis.Options{
|
||||
Addr: "",
|
||||
Password: "",
|
||||
DB: 1,
|
||||
})
|
||||
|
||||
// 创建缓存实例
|
||||
cache := NewRedisCache(rdb)
|
||||
a := &AliCloudExpressClient{
|
||||
AppCode: "",
|
||||
Host: "",
|
||||
cache: cache,
|
||||
}
|
||||
err := a.DeleteLogisticsInfoCache(context.Background(), "", "")
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
type RedisCache struct {
|
||||
client *redis.Client
|
||||
}
|
||||
|
||||
func (r *RedisCache) Del(ctx context.Context, number string) error {
|
||||
return r.client.Del(ctx, number).Err()
|
||||
}
|
||||
|
||||
func NewRedisCache(client *redis.Client) *RedisCache {
|
||||
return &RedisCache{client: client}
|
||||
}
|
||||
|
||||
func (r *RedisCache) Set(ctx context.Context, number string, res string, ttl time.Duration) error {
|
||||
if number == "" {
|
||||
return errors.New("number不能为空")
|
||||
}
|
||||
|
||||
return r.client.Set(ctx, number, res, ttl).Err()
|
||||
}
|
||||
|
||||
// Get 从Redis获取IP信息
|
||||
func (r *RedisCache) Get(ctx context.Context, number string) (*ExpressRes, error) {
|
||||
if number == "" {
|
||||
return nil, errors.New("number不能为空")
|
||||
}
|
||||
|
||||
data, err := r.client.Get(ctx, number).Bytes()
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return nil, nil // 键不存在,返回nil而不是错误
|
||||
}
|
||||
return nil, fmt.Errorf("无法获取物流信息: %w", err)
|
||||
}
|
||||
|
||||
var info ExpressRes
|
||||
if err = json.Unmarshal(data, &info); err != nil {
|
||||
return nil, fmt.Errorf("无法解析物流信息: %w", err)
|
||||
}
|
||||
|
||||
return &info, nil
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package express_tool
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ICacheAdapter interface {
|
||||
Set(ctx context.Context, key string, res string, ttl time.Duration) error
|
||||
Get(ctx context.Context, key string) (*ExpressRes, error)
|
||||
Del(ctx context.Context, key string) error
|
||||
}
|
@ -19,10 +19,11 @@ type HuaChenIpClient struct {
|
||||
cache ICacheAdapter
|
||||
}
|
||||
|
||||
func NewHuaChenIpClient(appCode string) *HuaChenIpClient {
|
||||
func NewHuaChenIpClient(appCode string, cache ICacheAdapter) *HuaChenIpClient {
|
||||
return &HuaChenIpClient{
|
||||
AppCode: appCode,
|
||||
Host: "https://c2ba.api.huachen.cn",
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,19 +90,13 @@ func (h *HuaChenIpClient) GetIpInfo(ip string) (res *ApiResult, err error) {
|
||||
return &apiResult, nil
|
||||
}
|
||||
|
||||
func (h *HuaChenIpClient) Set(cache ICacheAdapter) {
|
||||
h.cache = cache
|
||||
}
|
||||
|
||||
func (h *HuaChenIpClient) GetIpInfoFormCache(ctx context.Context, ip string, opt ...time.Duration) (res *ApiResult, err error) {
|
||||
if h.cache != nil {
|
||||
res, err = h.cache.Get(ctx, h.ipKey(ip))
|
||||
func (h *HuaChenIpClient) GetIpInfoFormCache(ctx context.Context, ip string, ttl time.Duration) (res *ApiResult, err error) {
|
||||
getCache, err := h.cache.Get(ctx, h.ipKey(ip))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "获取缓存失败,ip:%s", ip)
|
||||
}
|
||||
if res != nil {
|
||||
return res, nil
|
||||
}
|
||||
if getCache != nil {
|
||||
return getCache, nil
|
||||
}
|
||||
res, err = h.GetIpInfo(ip)
|
||||
if err != nil {
|
||||
@ -114,12 +109,10 @@ func (h *HuaChenIpClient) GetIpInfoFormCache(ctx context.Context, ip string, opt
|
||||
return nil, errors.Wrapf(err, "无法将IP信息转换为JSON,ip:%s", ip)
|
||||
}
|
||||
|
||||
if len(opt) == 0 {
|
||||
err = h.cache.Set(ctx, h.ipKey(ip), string(infoJson), opt[0])
|
||||
err = h.cache.Set(ctx, h.ipKey(ip), string(infoJson), ttl)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "缓存ip:%s信息失败,", ip)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -9,5 +9,4 @@ type ICacheAdapter interface {
|
||||
Get(ctx context.Context, key string) (value interface{}, err error)
|
||||
Set(ctx context.Context, key string, value interface{}, expire time.Duration) (err error)
|
||||
Del(ctx context.Context, key string) (err error)
|
||||
SetNX(ctx context.Context, key string, value interface{}, expire time.Duration) (ok bool, err error)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v5/client"
|
||||
util "github.com/alibabacloud-go/tea-utils/v2/service"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -70,15 +71,7 @@ func (c *SmsClient) GetCode(ctx context.Context, key string) (code string, err e
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if value == nil {
|
||||
return "", errors.New("验证码不存在,请重新发送")
|
||||
}
|
||||
switch value.(type) {
|
||||
case string:
|
||||
return value.(string), nil
|
||||
default:
|
||||
return "", errors.New("验证码类型错误,请联系管理员")
|
||||
}
|
||||
}
|
||||
|
||||
// SaveCode 保存验证码
|
||||
@ -88,7 +81,10 @@ func (c *SmsClient) SaveCode(ctx context.Context, key string, code string, expir
|
||||
}
|
||||
//保存code
|
||||
err = c.Cache.Set(ctx, key, code, expire)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteCode 删除验证码
|
||||
@ -106,18 +102,34 @@ func (c *SmsClient) SaveCodeWithFrequency(ctx context.Context, key string, code
|
||||
return errors.New("缓存不能为空")
|
||||
}
|
||||
frequencyKey := fmt.Sprintf(CodeFrequencyKey, key)
|
||||
if frequency <= 0 {
|
||||
return errors.New("频率不能小于0")
|
||||
if frequency != 0 {
|
||||
// 判断验证码是否频繁
|
||||
frequencyValue, err := c.Cache.Get(ctx, frequencyKey)
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
// 缓存中没有数据
|
||||
fmt.Printf("缓存中没有数据")
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
ok, err := c.Cache.SetNX(ctx, frequencyKey, CodeFrequencyValue, frequency)
|
||||
}
|
||||
if frequencyValue != nil && frequencyValue.(string) == CodeFrequencyValue {
|
||||
return errors.New("code发送频繁,请稍后再试")
|
||||
}
|
||||
}
|
||||
//保存code
|
||||
err = c.SaveCode(ctx, key, code, expire)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
return errors.New("code发送频繁,请稍后再试")
|
||||
}
|
||||
err = c.SaveCode(ctx, key, code, expire)
|
||||
if frequency != 0 {
|
||||
// 保存验证码发送频率
|
||||
err = c.Cache.Set(ctx, frequencyKey, CodeFrequencyValue, frequency)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyCode 校验验证码
|
||||
|
@ -51,14 +51,6 @@ func (r *RedisCacheAdapter) Del(ctx context.Context, key string) error {
|
||||
return r.client.Del(ctx, key).Err()
|
||||
}
|
||||
|
||||
func (r *RedisCacheAdapter) SetNX(ctx context.Context, key string, value interface{}, expire time.Duration) (ok bool, err error) {
|
||||
data, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return r.client.SetNX(ctx, key, data, expire).Result()
|
||||
}
|
||||
|
||||
var (
|
||||
//SMS
|
||||
accessKeyId = os.Getenv("SMS_ALIBABA_CLOUD_ACCESS_KEY_ID")
|
||||
|
@ -33,7 +33,7 @@ func (w *WeiPinShangClient) GetManyPostage(getManyPostageReq *GetManyPostageReq)
|
||||
fmt.Println("getManyPostageReq", getManyPostageReq)
|
||||
paramMap := make(map[string]any)
|
||||
|
||||
paramMap["goodsInfo"] = getManyPostageReq.GoodsInfo
|
||||
paramMap["goodInfo"] = getManyPostageReq.GoodsInfo
|
||||
paramMap["address"] = getManyPostageReq.Address
|
||||
paramMap["province"] = getManyPostageReq.Province
|
||||
paramMap["county"] = getManyPostageReq.County
|
||||
|
@ -29,7 +29,7 @@ func TestWeiPinShangClient_GetManyPostage(t *testing.T) {
|
||||
Key: "f654ea5bde7635c3f46191191e5c4c8e",
|
||||
},
|
||||
args: GetManyPostageReq{
|
||||
GoodsInfo: "[{\"goodsId\":\"WPS427_adf0008\",\"goodSpecId\":\"WPS427_0715110641454716\",\"num\":1}]",
|
||||
GoodsInfo: "[{\"goodsId\":\"WPS592_00019\",\"goodSpecId\":\"WPS592_1105165115160944\",\"num\":1},{\"goodsId\":\"WPS505_00007\",\"goodSpecId\":\"WPS505_1007111249857536\",\"num\":1}]",
|
||||
Province: "广东省",
|
||||
Address: "奥园",
|
||||
City: "广州市",
|
||||
@ -80,14 +80,14 @@ func TestWeiPinShangClient_PreOrder(t *testing.T) {
|
||||
Key: "f654ea5bde7635c3f46191191e5c4c8e",
|
||||
},
|
||||
args: PreOrderReq{
|
||||
GoodsInfo: "[{\"goodsId\":\"WPS427_adf0008\",\"goodSpecId\":\"WPS427_0715110641454716\",\"num\":1}]",
|
||||
GoodsInfo: "[{\"goodsId\":\"WPS2_1231155626421463\",\"goodSpecId\":\"WPS2_12311556265677476\",\"num\":1}]",
|
||||
Province: "广东省",
|
||||
Address: "奥园",
|
||||
City: "广州市",
|
||||
Area: "番禺区",
|
||||
ConsigneePhone: "15375390426",
|
||||
ConsigneeContacts: "张三",
|
||||
LockCode: "L100000005",
|
||||
LockCode: "L100000004",
|
||||
Source: "AILEHUI",
|
||||
},
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user