This commit is contained in:
unknown
2026-02-04 20:27:13 +08:00
commit 3b042d1dad
9410 changed files with 1488147 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
//go:build plus
package smssenders
import (
"encoding/json"
"errors"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/iwind/TeaGo/maps"
)
// AliyunSMSSender 阿里云短信
type AliyunSMSSender struct {
params *userconfigs.SMSSenderAliyunSMSParams
}
// NewAliyunSMSSender 获取新对象
func NewAliyunSMSSender() *AliyunSMSSender {
return &AliyunSMSSender{}
}
// Init 初始化
func (this *AliyunSMSSender) Init(params any) error {
if params == nil {
return errors.New("'params' should not be nil")
}
var ok bool
this.params, ok = params.(*userconfigs.SMSSenderAliyunSMSParams)
if !ok {
return errors.New("invalid params type")
}
return nil
}
// Send 发送短信
func (this *AliyunSMSSender) Send(mobile string, body string, code string) (resp string, isOk bool, err error) {
// {"Message":"OK","RequestId":"xxxx","BizId":"xxxx","Code":"OK"}
client, err := sdk.NewClientWithAccessKey("cn-hangzhou", this.params.AccessKeyId, this.params.AccessKeySecret)
if err != nil {
panic(err)
}
var request = requests.NewCommonRequest()
request.Method = "POST"
request.Scheme = "https" // https | http
request.Domain = "dysmsapi.aliyuncs.com"
request.Version = "2017-05-25"
request.ApiName = "SendSms"
request.QueryParams["RegionId"] = "cn-hangzhou"
request.QueryParams["PhoneNumbers"] = mobile // TODO 支持海外手机号?
request.QueryParams["SignName"] = this.params.Sign
request.QueryParams["TemplateCode"] = this.params.TemplateCode
var codeVarName = this.params.CodeVarName
if len(codeVarName) == 0 {
codeVarName = "code"
}
templateParamJSON, err := json.Marshal(map[string]string{
codeVarName: code,
})
if err != nil {
return "", false, err
}
request.QueryParams["TemplateParam"] = string(templateParamJSON)
response, err := client.ProcessCommonRequest(request)
if err != nil {
return "", false, err
}
var data = response.GetHttpContentBytes()
m := maps.Map{}
err = json.Unmarshal(data, &m)
if err != nil {
return string(data), false, err
}
if m.GetString("Code") == "OK" {
return "", true, nil
}
return string(data), false, errors.New("fail to send sms" + string(data))
}

View File

@@ -0,0 +1,29 @@
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package smssenders_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/senders/smssenders"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"testing"
)
func TestAliyunSMSSender_Send(t *testing.T) {
var sender = smssenders.NewAliyunSMSSender()
err := sender.Init(&userconfigs.SMSSenderAliyunSMSParams{
Sign: "SIGN",
TemplateCode: "TEMPLATE CODE",
CodeVarName: "code1",
AccessKeyId: "ACCESS KEY ID",
AccessKeySecret: "ACCESS KEY SECRET",
})
if err != nil {
t.Fatal(err)
}
_, _, err = sender.Send("13888888888", "", "1234")
if err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,12 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package smssenders
type SenderInterface interface {
// Init 初始化
Init(params any) error
// Send 发送短信
Send(mobile string, body string, code string) (resp string, isOk bool, err error)
}

View File

@@ -0,0 +1,69 @@
//go:build plus
package smssenders
import (
"errors"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
sms "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms/v20210111" // 引入sms
)
// 相关文档https://cloud.tencent.com/document/product/382/43199
// TencentSMSSender 腾讯云短信
type TencentSMSSender struct {
params *userconfigs.SMSSenderTencentSMSParams
}
// NewTencentSMSSender 获取新对象
func NewTencentSMSSender() *TencentSMSSender {
return &TencentSMSSender{}
}
// Init 初始化
func (this *TencentSMSSender) Init(params any) error {
if params == nil {
return errors.New("'params' should not be nil")
}
var ok bool
this.params, ok = params.(*userconfigs.SMSSenderTencentSMSParams)
if !ok {
return errors.New("invalid params type")
}
return nil
}
// Send 发送短信
func (this *TencentSMSSender) Send(mobile string, body string, code string) (resp string, isOk bool, err error) {
var credential = common.NewCredential(this.params.AccessKeyId, this.params.AccessKeySecret)
var cpf = profile.NewClientProfile()
cpf.HttpProfile.ReqMethod = "POST"
// cpf.HttpProfile.ReqTimeout = 5
cpf.HttpProfile.Endpoint = "sms.tencentcloudapi.com"
cpf.SignMethod = "HmacSHA1"
client, err := sms.NewClient(credential, "ap-guangzhou", cpf)
if err != nil {
return "", false, err
}
var request = sms.NewSendSmsRequest()
request.SmsSdkAppId = common.StringPtr(this.params.SDKAppId)
request.SignName = common.StringPtr(this.params.Sign)
request.TemplateId = common.StringPtr(this.params.TemplateId)
request.TemplateParamSet = common.StringPtrs([]string{code})
request.PhoneNumberSet = common.StringPtrs([]string{"+86" + mobile}) // TODO 支持海外手机号?
request.SessionContext = common.StringPtr("")
request.ExtendCode = common.StringPtr("")
request.SenderId = common.StringPtr("")
// 通过client对象调用想要访问的接口需要传入请求对象
_, err = client.SendSms(request)
if err != nil {
return "", false, err
}
return "", true, nil
}

View File

@@ -0,0 +1,28 @@
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package smssenders_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/senders/smssenders"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"testing"
)
func TestTencentSMSSender_Send(t *testing.T) {
var sender = smssenders.NewAliyunSMSSender()
err := sender.Init(&userconfigs.SMSSenderTencentSMSParams{
SDKAppId: "123456",
Sign: "SIGN",
TemplateId: "123456",
AccessKeyId: "ACCESS KEY ID",
AccessKeySecret: "ACCESS KEY SECRET",
})
if err != nil {
t.Fatal(err)
}
_, _, err = sender.Send("13888888888", "", "1234")
if err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,89 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package smssenders
import (
"errors"
"fmt"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/iwind/TeaGo/types"
"io"
"net/http"
"net/url"
"strings"
"time"
)
type WebHookSender struct {
params *userconfigs.SMSSenderWebHookParams
}
func NewWebHookSender() *WebHookSender {
return &WebHookSender{}
}
func (this *WebHookSender) Init(params any) error {
if params == nil {
return errors.New("'params' should not be nil")
}
var ok bool
this.params, ok = params.(*userconfigs.SMSSenderWebHookParams)
if !ok {
return errors.New("invalid params type")
}
return nil
}
// Send 发送短信
func (this *WebHookSender) Send(mobile string, body string, code string) (result string, isOk bool, err error) {
var encodedQuery = (&url.Values{
"mobile": []string{mobile},
"body": []string{body},
"code": []string{code},
}).Encode()
var webHookURL = this.params.URL
var reader io.Reader
if this.params.Method == "POST" {
reader = strings.NewReader(encodedQuery)
} else {
if strings.Contains(webHookURL, "?") {
webHookURL += "&" + encodedQuery
} else {
webHookURL += "?" + encodedQuery
}
}
req, err := http.NewRequest(this.params.Method, webHookURL, reader)
if err != nil {
return "", false, fmt.Errorf("create request failed: %w", err)
}
req.Header.Set("User-Agent", teaconst.ProductName+"/"+teaconst.Version)
if this.params.Method == "POST" {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
resp, err := utils.SharedHttpClient(10 * time.Second).Do(req)
if err != nil {
return "", false, err
}
if resp == nil || resp.Body == nil {
return "", false, errors.New("invalid response")
}
defer func() {
_ = resp.Body.Close()
}()
respData, err := io.ReadAll(resp.Body)
if err != nil {
return "", false, err
}
if resp.StatusCode != http.StatusOK {
return "StatusCode: " + types.String(resp.StatusCode) + ": " + string(respData), false, nil
}
return string(respData), true, nil
}

View File

@@ -0,0 +1,62 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package smssenders_test
import (
"github.com/TeaOSLab/EdgeAPI/internal/senders/smssenders"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"net/http"
"testing"
)
func TestWebHookSender_Send_Get(t *testing.T) {
var sender = smssenders.NewWebHookSender()
err := sender.Init(&userconfigs.SMSSenderWebHookParams{
URL: "http://192.168.2.41:2345/sms/get",
Method: http.MethodGet,
})
if err != nil {
t.Fatal(err)
}
resp, isOk, err := sender.Send("13888888888", "THIS IS BODY", "1234")
if err != nil {
t.Fatal(err)
}
t.Log(isOk)
t.Log("response:", resp)
}
func TestWebHookSender_Send_Get_Fail(t *testing.T) {
var sender = smssenders.NewWebHookSender()
err := sender.Init(&userconfigs.SMSSenderWebHookParams{
URL: "http://192.168.2.41:2345/404",
Method: http.MethodGet,
})
if err != nil {
t.Fatal(err)
}
resp, isOk, err := sender.Send("13888888888", "THIS IS BODY", "1234")
if err != nil {
t.Fatal(err)
}
t.Log(isOk)
t.Log("response:", resp)
}
func TestWebHookSender_Send_POST(t *testing.T) {
var sender = smssenders.NewWebHookSender()
err := sender.Init(&userconfigs.SMSSenderWebHookParams{
URL: "http://192.168.2.41:2345/sms/post",
Method: http.MethodPost,
})
if err != nil {
t.Fatal(err)
}
resp, isOk, err := sender.Send("13888888888", "THIS IS BODY", "1234")
if err != nil {
t.Fatal(err)
}
t.Log(isOk)
t.Log("response:", resp)
}

View File

@@ -0,0 +1,69 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package smssenders
import (
"encoding/json"
"errors"
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
)
type SenderDefinition struct {
Name string `json:"name"`
Code string `json:"code"`
}
func FindAllTypes() []*SenderDefinition {
return []*SenderDefinition{
{
Name: "自定义HTTP接口",
Code: userconfigs.SMSSenderWebHook,
},
{
Name: "阿里云短信",
Code: userconfigs.SMSSenderAliyunSMS,
},
{
Name: "腾讯云短信",
Code: userconfigs.SMSSenderTencentSMS,
},
}
}
func CreateSender(senderType userconfigs.SMSSenderType, paramsJSON []byte) (sender SenderInterface, err error) {
var params any
switch senderType {
case userconfigs.SMSSenderWebHook:
sender = NewWebHookSender()
params = &userconfigs.SMSSenderWebHookParams{}
case userconfigs.SMSSenderAliyunSMS:
sender = NewAliyunSMSSender()
params = &userconfigs.SMSSenderAliyunSMSParams{}
case userconfigs.SMSSenderTencentSMS:
sender = NewTencentSMSSender()
params = &userconfigs.SMSSenderTencentSMSParams{}
default:
return nil, errors.New("could not find sender with type '" + senderType + "'")
}
if sender == nil {
return nil, errors.New("could not find sender with type '" + senderType + "'")
}
err = json.Unmarshal(paramsJSON, params)
if err != nil {
err = fmt.Errorf("decode params failed: %w", err)
return
}
err = sender.Init(params)
if err != nil {
err = fmt.Errorf("initialize sender failed: %w", err)
return
}
return
}