初始化
This commit is contained in:
@@ -0,0 +1,410 @@
|
||||
package aliyun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"code.yun.ink/pkg/smsx/entity"
|
||||
"code.yun.ink/pkg/smsx/interfaces"
|
||||
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v4/client"
|
||||
util "github.com/alibabacloud-go/tea-utils/v2/service"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
"github.com/yuninks/loggerx"
|
||||
)
|
||||
|
||||
type Aliyun struct {
|
||||
interfaces.DefaultSmsx
|
||||
client *dysmsapi20170525.Client
|
||||
params entity.SmsConfigData
|
||||
logger loggerx.LoggerInterface
|
||||
}
|
||||
|
||||
func (l *Aliyun) InitSmsx(ctx context.Context, params entity.SmsConfigData, logger loggerx.LoggerInterface) (interfaces.Smsx, error) {
|
||||
l.logger = logger
|
||||
if params.SysType != entity.Platform3rdTypeAliyun {
|
||||
return nil, errors.New("not aliyun")
|
||||
}
|
||||
|
||||
config := &openapi.Config{
|
||||
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
|
||||
AccessKeyId: tea.String(params.Aliyun.AccessKeyId),
|
||||
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
|
||||
AccessKeySecret: tea.String(params.Aliyun.AccessKeySecret),
|
||||
}
|
||||
// Endpoint 请参考 https://api.aliyun.com/product/Dysmsapi
|
||||
if params.Aliyun.Endpoint == "" {
|
||||
params.Aliyun.Endpoint = "dysmsapi.aliyuncs.com"
|
||||
}
|
||||
|
||||
config.Endpoint = tea.String(params.Aliyun.Endpoint)
|
||||
// _result = &dysmsapi20170525.Client{}
|
||||
_result, err := dysmsapi20170525.NewClient(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Aliyun{
|
||||
client: _result,
|
||||
params: params,
|
||||
logger: logger,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Send 发送短信
|
||||
func (l *Aliyun) Send(ctx context.Context, templateCode string, phone string, params []interfaces.SmsSendParam) error {
|
||||
if l.client == nil {
|
||||
return errors.New("not init")
|
||||
}
|
||||
|
||||
l.logger.Infof(ctx, "Aliyun send templateId:%+v phone:%+v params:%+v", templateCode, phone, params)
|
||||
|
||||
paramMap := map[string]string{}
|
||||
for _, param := range params {
|
||||
paramMap[param.Field] = param.Value
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(paramMap)
|
||||
|
||||
sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
|
||||
SignName: tea.String(l.params.Aliyun.SignName),
|
||||
TemplateCode: tea.String(templateCode),
|
||||
PhoneNumbers: tea.String(phone),
|
||||
TemplateParam: tea.String(string(b)),
|
||||
}
|
||||
|
||||
runtime := &util.RuntimeOptions{}
|
||||
tryErr := func() (_e error) {
|
||||
defer func() {
|
||||
if r := tea.Recover(recover()); r != nil {
|
||||
_e = r
|
||||
}
|
||||
}()
|
||||
// 复制代码运行请自行打印 API 的返回值
|
||||
resp, _err := l.client.SendSmsWithOptions(sendSmsRequest, runtime)
|
||||
l.logger.Infof(ctx, "Aliyun resp resp:%+v err:%+v", resp, _err)
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
||||
if resp == nil || resp.Body == nil {
|
||||
return errors.New("未知响应")
|
||||
}
|
||||
|
||||
if *resp.Body.Code != "OK" {
|
||||
return errors.New(tea.StringValue(resp.Body.Message))
|
||||
}
|
||||
|
||||
// {
|
||||
// "headers": {
|
||||
// "access-control-allow-origin": "*",
|
||||
// "access-control-expose-headers": "*",
|
||||
// "connection": "keep-alive",
|
||||
// "content-length": "133",
|
||||
// "content-type": "application/json;charset=utf-8",
|
||||
// "date": "Tue, 27 Aug 2024 10:37:25 GMT",
|
||||
// "etag": "1YHcV2uF0Hw6v4+PJKSpMwA1",
|
||||
// "keep-alive": "timeout=25",
|
||||
// "x-acs-request-id": "B7CCDAD3-AA89-55ED-94F5-4C08D746399B",
|
||||
// "x-acs-trace-id": "cef86cfb21d73f60869bbb9034794714"
|
||||
// },
|
||||
// "statusCode": 200,
|
||||
// "body": {
|
||||
// "Code": "isv.SMS_SIGNATURE_ILLEGAL",
|
||||
// "Message": "该账号下找不到对应签名",
|
||||
// "RequestId": "B7CCDAD3-AA89-55ED-94F5-4C08D746399B"
|
||||
// }
|
||||
// }
|
||||
|
||||
// {
|
||||
// "headers": {
|
||||
// "access-control-allow-origin": "*",
|
||||
// "access-control-expose-headers": "*",
|
||||
// "connection": "keep-alive",
|
||||
// "content-length": "110",
|
||||
// "content-type": "application/json;charset=utf-8",
|
||||
// "date": "Tue, 27 Aug 2024 10:39:59 GMT",
|
||||
// "etag": "19rMwUYhdQd2sDRXr2iLPLg0",
|
||||
// "keep-alive": "timeout=25",
|
||||
// "x-acs-request-id": "D8F5E530-57BD-5A6C-AE57-18AD67BDDF70",
|
||||
// "x-acs-trace-id": "95bdbb6a3f64ca8f7da8d398410c1bfa"
|
||||
// },
|
||||
// "statusCode": 200,
|
||||
// "body": {
|
||||
// "BizId": "181408424755199417^0",
|
||||
// "Code": "OK",
|
||||
// "Message": "OK",
|
||||
// "RequestId": "D8F5E530-57BD-5A6C-AE57-18AD67BDDF70"
|
||||
// }
|
||||
// }
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
if tryErr != nil {
|
||||
|
||||
return tryErr
|
||||
|
||||
// var error = &tea.SDKError{}
|
||||
// if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||
// error = _t
|
||||
// } else {
|
||||
// error.Message = tea.String(tryErr.Error())
|
||||
// }
|
||||
// // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
|
||||
// // 错误 message
|
||||
// fmt.Println(tea.StringValue(error.Message))
|
||||
// // 诊断地址
|
||||
// var data interface{}
|
||||
// d := json.NewDecoder(strings.NewReader(tea.StringValue(error.Data)))
|
||||
// d.Decode(&data)
|
||||
// if m, ok := data.(map[string]interface{}); ok {
|
||||
// recommend, _ := m["Recommend"]
|
||||
// fmt.Println(recommend)
|
||||
// }
|
||||
// _, _err := util.AssertAsString(error.Message)
|
||||
// if _err != nil {
|
||||
// return _err
|
||||
// }
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTemp 获取模板
|
||||
func (l *Aliyun) GetTemp(ctx context.Context) ([]interfaces.TemplateInfo, error) {
|
||||
page := 0
|
||||
resp := []interfaces.TemplateInfo{}
|
||||
|
||||
l.logger.Infof(ctx, "aliyun getTemp: start")
|
||||
|
||||
for {
|
||||
page++
|
||||
r, err := l.getTemp(ctx, int32(page))
|
||||
if err != nil {
|
||||
l.logger.Errorf(ctx, "aliyun getTemp: err:%+v", err)
|
||||
return nil, err
|
||||
}
|
||||
if len(r) == 0 {
|
||||
break
|
||||
}
|
||||
resp = append(resp, r...)
|
||||
}
|
||||
return resp, nil
|
||||
|
||||
}
|
||||
|
||||
func (l *Aliyun) getTemp(ctx context.Context, page int32) ([]interfaces.TemplateInfo, error) {
|
||||
if l.client == nil {
|
||||
return nil, errors.New("not init")
|
||||
}
|
||||
|
||||
querySmsTemplateListRequest := &dysmsapi20170525.QuerySmsTemplateListRequest{
|
||||
PageIndex: tea.Int32(page),
|
||||
PageSize: tea.Int32(20),
|
||||
}
|
||||
runtime := &util.RuntimeOptions{}
|
||||
|
||||
resps := []interfaces.TemplateInfo{}
|
||||
|
||||
tryErr := func() (_e error) {
|
||||
defer func() {
|
||||
if r := tea.Recover(recover()); r != nil {
|
||||
l.logger.Errorf(ctx, "aliyun getTemp: err:%+v", r)
|
||||
_e = r
|
||||
}
|
||||
}()
|
||||
// 复制代码运行请自行打印 API 的返回值
|
||||
resp, _err := l.client.QuerySmsTemplateListWithOptions(querySmsTemplateListRequest, runtime)
|
||||
if _err != nil {
|
||||
l.logger.Errorf(ctx, "aliyun getTemp: err:%+v", _err)
|
||||
return _err
|
||||
}
|
||||
|
||||
l.logger.Infof(ctx, "aliyun getTemp: resp:%+v err:%+v", resp, _err)
|
||||
|
||||
if resp == nil || resp.Body == nil {
|
||||
return fmt.Errorf("resp is nil")
|
||||
}
|
||||
|
||||
for _, val := range resp.Body.SmsTemplateList {
|
||||
s := l.extractParams(tea.StringValue(val.TemplateContent))
|
||||
|
||||
params := []entity.SmsTemplateParam{}
|
||||
for _, p := range s {
|
||||
params = append(params, entity.SmsTemplateParam{
|
||||
FieldName: p,
|
||||
})
|
||||
}
|
||||
|
||||
resps = append(resps, interfaces.TemplateInfo{
|
||||
TempId: tea.StringValue(val.TemplateCode),
|
||||
TempName: tea.StringValue(val.TemplateName),
|
||||
TempType: l.tempTypePlatToLocal(tea.Int32Value(val.OuterTemplateType)),
|
||||
TempRange: l.tempRangePlatToLocal(tea.Int32Value(val.OuterTemplateType)),
|
||||
Content: tea.StringValue(val.TemplateContent),
|
||||
Status: l.auditStatusPlatToLocal(tea.StringValue(val.AuditStatus)),
|
||||
Params: params,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
if tryErr != nil {
|
||||
var error = &tea.SDKError{}
|
||||
if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||
error = _t
|
||||
} else {
|
||||
error.Message = tea.String(tryErr.Error())
|
||||
}
|
||||
return nil, error
|
||||
|
||||
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
|
||||
// 错误 message
|
||||
// fmt.Println(tea.StringValue(error.Message))
|
||||
// 诊断地址
|
||||
// var data interface{}
|
||||
// d := json.NewDecoder(strings.NewReader(tea.StringValue(error.Data)))
|
||||
// d.Decode(&data)
|
||||
// if m, ok := data.(map[string]interface{}); ok {
|
||||
// recommend, _ := m["Recommend"]
|
||||
// fmt.Println(recommend)
|
||||
// }
|
||||
// _, _err := util.AssertAsString(error.Message)
|
||||
// if _err != nil {
|
||||
// return nil, _err
|
||||
// }
|
||||
}
|
||||
|
||||
return resps, nil
|
||||
}
|
||||
|
||||
// TempDel 删除模板
|
||||
func (l *Aliyun) TempDel(ctx context.Context, templateId string) error {
|
||||
if l.client == nil {
|
||||
return errors.New("not init")
|
||||
}
|
||||
|
||||
deleteSmsTemplateRequest := &dysmsapi20170525.DeleteSmsTemplateRequest{
|
||||
TemplateCode: tea.String(templateId),
|
||||
}
|
||||
runtime := &util.RuntimeOptions{}
|
||||
tryErr := func() (_e error) {
|
||||
defer func() {
|
||||
if r := tea.Recover(recover()); r != nil {
|
||||
_e = r
|
||||
}
|
||||
}()
|
||||
// 复制代码运行请自行打印 API 的返回值
|
||||
_, _err := l.client.DeleteSmsTemplateWithOptions(deleteSmsTemplateRequest, runtime)
|
||||
if _err != nil {
|
||||
return _err
|
||||
}
|
||||
|
||||
return nil
|
||||
}()
|
||||
|
||||
if tryErr != nil {
|
||||
|
||||
return tryErr
|
||||
|
||||
// var error = &tea.SDKError{}
|
||||
// if _t, ok := tryErr.(*tea.SDKError); ok {
|
||||
// error = _t
|
||||
// } else {
|
||||
// error.Message = tea.String(tryErr.Error())
|
||||
// }
|
||||
// // 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
|
||||
// // 错误 message
|
||||
// fmt.Println(tea.StringValue(error.Message))
|
||||
// // 诊断地址
|
||||
// var data interface{}
|
||||
// d := json.NewDecoder(strings.NewReader(tea.StringValue(error.Data)))
|
||||
// d.Decode(&data)
|
||||
// if m, ok := data.(map[string]interface{}); ok {
|
||||
// recommend, _ := m["Recommend"]
|
||||
// fmt.Println(recommend)
|
||||
// }
|
||||
// _, _err := util.AssertAsString(error.Message)
|
||||
// if _err != nil {
|
||||
// return _err
|
||||
// }
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 审核状态转换 短信平台=>本地
|
||||
func (l *Aliyun) auditStatusPlatToLocal(status string) entity.SmsTemplateStatus {
|
||||
|
||||
// AUDIT_STATE_INIT:审核中。
|
||||
// AUDIT_STATE_PASS:通过审核。
|
||||
// AUDIT_STATE_NOT_PASS:未通过审核,请在返回参数 Reason 中查看审核未通过原因。
|
||||
// AUDIT_STATE_CANCEL:取消审核。
|
||||
// AUDIT_SATE_CANCEL:取消审核。
|
||||
|
||||
switch status {
|
||||
case "AUDIT_STATE_INIT":
|
||||
return entity.SmsTemplateStatusAudit
|
||||
case "AUDIT_STATE_PASS":
|
||||
return entity.SmsTemplateStatusPass
|
||||
case "AUDIT_STATE_NOT_PASS":
|
||||
return entity.SmsTemplateStatusUnPass
|
||||
case "AUDIT_STATE_CANCEL":
|
||||
return entity.SmsTemplateStatusCancel
|
||||
case "AUDIT_SATE_CANCEL":
|
||||
return entity.SmsTemplateStatusCancel
|
||||
default:
|
||||
return entity.SmsTemplateStatusUnknown
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Aliyun) tempTypePlatToLocal(platType int32) entity.SmsTemplateType {
|
||||
// 0:验证码短信。
|
||||
// 1:通知短信。
|
||||
// 2:推广短信。
|
||||
// 3:国际/港澳台短信。
|
||||
// 7:数字短信。
|
||||
|
||||
switch platType {
|
||||
case 0:
|
||||
return entity.SmsTemplateTypeVerifyCode
|
||||
case 1:
|
||||
return entity.SmsTemplateTypeNotice
|
||||
case 2:
|
||||
return entity.SmsTemplateTypePromotion
|
||||
case 3:
|
||||
return entity.SmsTemplateTypeInternational
|
||||
case 7:
|
||||
return entity.SmsTemplateTypeDigital
|
||||
default:
|
||||
return entity.SmsTemplateTypeUnknown
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Aliyun) tempRangePlatToLocal(platType int32) entity.SmsTemplateRange {
|
||||
// 非国际/港澳台短信。
|
||||
if platType == 3 {
|
||||
return entity.SmsTemplateRangeInternational
|
||||
}
|
||||
return entity.SmsTemplateRangeChina
|
||||
}
|
||||
|
||||
// 提取参数
|
||||
func (l *Aliyun) extractParams(str string) []string {
|
||||
// str := "订单尾号${dingdanhao}超过${shijian}分钟,系统已自动放行。交易完成,请登录查看账户变动。"
|
||||
|
||||
re := regexp.MustCompile(`\$\{(.+?)\}`)
|
||||
matches := re.FindAllStringSubmatch(str, -1)
|
||||
|
||||
var keys []string
|
||||
for _, match := range matches {
|
||||
keys = append(keys, match[1])
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package aliyun_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"code.yun.ink/pkg/smsx/aliyun"
|
||||
"code.yun.ink/pkg/smsx/entity"
|
||||
"code.yun.ink/pkg/smsx/interfaces"
|
||||
"github.com/yuninks/loggerx"
|
||||
)
|
||||
|
||||
func TestSend(t *testing.T) {
|
||||
ali := &aliyun.Aliyun{}
|
||||
ctx := context.Background()
|
||||
|
||||
logger := loggerx.NewLogger(ctx)
|
||||
|
||||
params := entity.SmsConfigData{
|
||||
SysType: entity.Platform3rdTypeAliyun,
|
||||
Aliyun: &entity.SmsConfigDataAliyun{
|
||||
AccessKeyId: "LTAI5tSgopmbntKXnq8ESrvh",
|
||||
AccessKeySecret: "BEgEFCOh4eokzhg8EfxeETbSk4B2UJ",
|
||||
SignName: "深圳展鸣科技",
|
||||
},
|
||||
}
|
||||
|
||||
nAli, err := ali.InitSmsx(ctx, params, logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = nAli.Send(ctx, "SMS_465941403", "18819446148", []interfaces.SmsSendParam{
|
||||
{Field: "code", Value: "123456"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Log("success")
|
||||
}
|
||||
|
||||
func TestGetTemp(t *testing.T) {
|
||||
ali := &aliyun.Aliyun{}
|
||||
ctx := context.Background()
|
||||
|
||||
logger := loggerx.NewLogger(ctx)
|
||||
|
||||
params := entity.SmsConfigData{
|
||||
SysType: entity.Platform3rdTypeAliyun,
|
||||
Aliyun: &entity.SmsConfigDataAliyun{
|
||||
AccessKeyId: "LTAI5tSgopmbntKXnq8ESrvh",
|
||||
AccessKeySecret: "BEgEFCOh4eokzhg8EfxeETbSk4B2UJ",
|
||||
SignName: "深圳展鸣科技",
|
||||
},
|
||||
}
|
||||
|
||||
nAli, err := ali.InitSmsx(ctx, params, logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resp, err := nAli.GetTemp(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Log("resp=", resp)
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user