初始化项目

This commit is contained in:
皮蛋13361098506
2025-01-06 16:01:02 +08:00
commit 1b77f62820
575 changed files with 69193 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
package qcloud
// 公有字段
type commonField struct {
// 签名
Sig string `json:"sig"`
// Unix时间戳
Time int64 `json:"time"`
// 通道扩展码,可选字段,默认没有开通(需要填空)。
Extend string `json:"extend"`
// 用户的session内容腾讯server回包中会原样返回
Ext string `json:"ext"`
// 接收方
// 单发短信时填mobile
// 群发时填[]mobile
Tel interface{} `json:"tel"`
}
func newCommonField(sig string, time int64, extend string, ext string, tel interface{}) *commonField {
return &commonField{
Sig: sig,
Time: time,
Extend: extend,
Ext: ext,
Tel: tel,
}
}

View File

@@ -0,0 +1,16 @@
package qcloud
// 直接发送短信字段
type msgSmsField struct {
//0:普通短信;1:营销短信(强调:要按需填值,不然会影响到业务的正常使用)
Type interface{} `json:"type,omitempty"`
// 短信内容,需要匹配审核通过的模板内容
Msg string `json:"msg,omitempty"`
}
func newMsgSmsField(t int, msg string) *msgSmsField {
return &msgSmsField{
Type: t,
Msg: msg,
}
}

View File

@@ -0,0 +1,144 @@
package qcloud
import (
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"strings"
"time"
"goutil/mathUtil"
"goutil/smsUtil/sms"
)
const (
SINGLE_SMS_URL = "https://yun.tim.qq.com/v5/tlssmssvr/sendsms"
MULTI_SMS_URL = "https://yun.tim.qq.com/v5/tlssmssvr/sendmultisms2"
)
// 创建msg类型短信(直接发送短信内容)
// 参数:
//
// appid
// appkey
// nation []string 国家代码 eg: 86
// numbers []string 电话号码
// msg string 短信内容
// extend string 通道扩展码,可选字段,默认没有开通(需要填空串)
// ext string 用户的session内容腾讯server回包中会原样返回可选字段不需要就填空
//
// nation、numbers 需要一一对应 (nation[0]将与numbers[0]组合)
// msg 必须与已通过审核的模板匹配
func NewMsgSms(appid, appkey string,
nation, numbers []string,
msg, extend, ext string) (sms.Sms, error) {
return generateSms(appid, appkey,
nation, numbers,
extend, ext,
newMsgSmsField(0, msg),
nil)
}
// 创建tmpl类型短信(通过模板发送短信)
// 参数:
//
// appid
// appkey
// nation []string 国家代码 eg: 86
// numbers []string 电话号码
// tmplID int 模板ID
// params []string 模板参数
// sign string 短信签名(前缀)
// extend string 通道扩展码,可选字段,默认没有开通(需要填空串)
// ext string 用户的session内容腾讯server回包中会原样返回可选字段不需要就填空
//
// nation、numbers 需要一一对应 (nation[0]将与numbers[0]组合)
func NewTmplSms(appid, appkey string,
nation, numbers []string,
tmplID int, params []string,
sign, extend, ext string) (sms.Sms, error) {
return generateSms(appid, appkey,
nation, numbers,
extend, ext,
nil,
newTmplSmsField(sign, tmplID, params))
}
// create qcloud sms instance
func generateSms(appid, appkey string,
nation, numbers []string,
extend, ext string,
msg *msgSmsField,
tmpl *tmplSmsField) (s sms.Sms, err error) {
err = validateMobile(nation, numbers)
if err != nil {
return
}
var url string
// 区分
if len(nation) > 1 {
url = MULTI_SMS_URL
} else {
url = SINGLE_SMS_URL
}
// 生成随机数、时间戳,并计算签名
rnd := mathUtil.GetRand().GetRandRangeInt(100000, 999999)
timestap := time.Now().Unix()
sig := calcSig(appkey, rnd, timestap, numbers)
// 生成公共字段
comField := newCommonField(sig, timestap, extend, ext, generateTelField(nation, numbers))
// 生成smsData
data := newSmsData(comField, msg, tmpl)
// 生成qcloudsms
s = newSms(url, data, rnd, appid)
return
}
// calculate sign-string for phone numbers
func calcSig(appkey string, rnd int, tm int64, numbers []string) string {
mobile := strings.Join(numbers, ",")
sum := sha256.Sum256([]byte(fmt.Sprintf("appkey=%v&random=%v&time=%v&mobile=%v",
appkey, rnd, tm, mobile)))
return hex.EncodeToString(sum[:])
}
// 验证地区代码与手机号数量是否匹配
func validateMobile(nation, numbers []string) error {
if len(nation) != len(numbers) {
return errors.New("loadReq: nation、numbers 数量不同")
} else if len(nation) == 0 {
return errors.New("loadReq: nation、numbers 不能为空")
}
return nil
}
// 生成Tel字段
// 当多个号码时,生成[]telField
// 单个号码时生成telField
func generateTelField(nation, numbers []string) interface{} {
res := make([](*telField), len(nation))
for i := 0; i < len(nation); i++ {
res[i] = newTelField(nation[i], numbers[i])
}
if len(res) == 1 {
return res[0]
}
return res
}

View File

@@ -0,0 +1,22 @@
package qcloud
// 腾讯云平台的响应信息
// 响应信息
type QCloudResponse struct {
Result int // 0表示成功(计费依据)非0表示失败
Errmsg string // result非0时的具体错误信息
Ext string // 用户的session内容腾讯server回包中会原样返回
Sid string // 标识本次发送id标识一次短信下发记录
Fee int // 短信计费的条数
Detail []responsDetailItem // 群发短信时才有
}
type responsDetailItem struct {
Result int
Errmsg string
Mobile string
Nationcode string
Sid string
Fee int
}

View File

@@ -0,0 +1,86 @@
package qcloud
import (
"encoding/json"
"fmt"
"goutil/debugUtil"
"goutil/smsUtil/sender/httpSender"
)
// qcloud sms
type qcloudsms struct {
url string
data *smsData
rnd int
appid string
rspn *QCloudResponse
}
func newSms(url string, data *smsData, rnd int, appid string) *qcloudsms {
return &qcloudsms{
url: url,
data: data,
rnd: rnd,
appid: appid,
}
}
// 实现sms.Sms、httpSender.Requester、httpSender.Responser接口
// httpSender.Requester接口
// 返回请求方式
func (*qcloudsms) GetMethod() string {
return "POST"
}
// httpSender.Requester接口
// 返回请求url
func (this *qcloudsms) GetUrl() string {
// url 额外参数
url := fmt.Sprintf("%s?sdkappid=%s&random=%d", this.url, this.appid, this.rnd)
return url
}
// httpSender.Requester接口
// 返回发送数据
func (this *qcloudsms) GetData() []byte {
bytes, err := json.Marshal(this.data)
if err != nil {
debugUtil.Println("failed to json marshal sms data")
return []byte("")
}
return bytes
}
// 解析返回数据,判断是否发送成功
func (this *qcloudsms) ParseReponse(rspn []byte) (bool, error) {
this.rspn = new(QCloudResponse)
err := json.Unmarshal(rspn, this.rspn)
if err != nil {
return false, err
}
if this.rspn.Result == 0 {
return true, nil
} else {
return false, fmt.Errorf(this.rspn.Errmsg)
}
}
// sms.Sms接口
func (this *qcloudsms) Send() (bool, error) {
sender := httpSender.New()
rspn, err := sender.Send(this)
if err != nil {
return false, err
}
return this.ParseReponse(rspn)
}
func (this *qcloudsms) GetResponse() interface{} {
return this.rspn
}

View File

@@ -0,0 +1,16 @@
package qcloud
// 发送短信请求结构
type smsData struct {
// 公共字段
*commonField
// 短信字段
// 根据类型,对其中一个结构的字段进行赋值
*msgSmsField
*tmplSmsField
}
func newSmsData(common *commonField, msg *msgSmsField, tmpl *tmplSmsField) *smsData {
return &smsData{common, msg, tmpl}
}

View File

@@ -0,0 +1,14 @@
package qcloud
// 电话结构
type telField struct {
Nationcode string `json:"nationcode"`
Mobile string `json:"mobile"`
}
func newTelField(nation, number string) *telField {
return &telField{
Nationcode: nation,
Mobile: number,
}
}

View File

@@ -0,0 +1,19 @@
package qcloud
// 发送模板短信字段
type tmplSmsField struct {
// 签名 (前缀)
Sign string `json:"sign,omitempty"`
// 模板id
Tpl_id int `json:"tpl_id,omitempty"`
// 模板参数
Params []string `json:"params,omitempty"`
}
func newTmplSmsField(sign string, id int, params []string) *tmplSmsField {
return &tmplSmsField{
Sign: sign,
Tpl_id: id,
Params: params,
}
}

View File

@@ -0,0 +1,26 @@
package qirui
import (
"fmt"
"goutil/webUtil"
)
const (
SEND_MESSAGE_URL = "http://api.qirui.com:7891/mt"
)
func SendMessage(apiKey, apiSecret, mobile, message string) (bool, error) {
smsUrl := fmt.Sprintf("%s?dc=15&un=%s&pw=%s&da=%s&sm=%s&tf=3&rf=2&rd=1", SEND_MESSAGE_URL, apiKey, apiSecret, mobile, message)
status, resp, err := webUtil.GetWebData3(smsUrl, "", webUtil.GetJsonHeader(), nil)
if err != nil {
return false, err
}
if status != 200 {
return false, fmt.Errorf("StatusCode is %d", status)
}
fmt.Printf("qirui.SendMessage:%s, %s, %s\n", mobile, message, string(resp))
return true, nil
}

View File

@@ -0,0 +1,47 @@
package httpSender
import (
"errors"
"fmt"
// "goutil/debugUtil"
"goutil/webUtil"
)
// 实现Sender相关接口
type httpClient struct{}
// 发送Requester
func (this *httpClient) Send(req Requester) (rspn []byte, err error) {
if req.GetMethod() == "POST" {
rspn, err = this.post(req)
return
} else {
err = errors.New(fmt.Sprintf("request: unsupport method (%s)", req.GetMethod()))
return
}
}
// 发送 post 请求
func (*httpClient) post(req Requester) ([]byte, error) {
url := req.GetUrl()
bytes := req.GetData()
// debugUtil.Printf("httpClient-POST %s\r\n%v\n", url, string(bytes))
rspn, err := webUtil.PostByteData(url, bytes, nil)
if err != nil {
return nil, err
}
// body := []byte("{\"result\":0,\"errmsg\":\"OK\",\"ext\":\"hello-world\",\"sid\":\"6:59106203271444582828\",\"fee\":1}")
// debugUtil.Printf("httpClient-Res: %s", string(rspn))
return rspn, nil
}
func New() *httpClient {
return new(httpClient)
}

View File

@@ -0,0 +1,8 @@
package httpSender
// 请求
type Requester interface {
GetMethod() string
GetUrl() string
GetData() []byte
}

View File

@@ -0,0 +1,7 @@
package httpSender
// 发送器
// 用于发送Requester
type Sender interface {
Send(req Requester) ([]byte, error)
}

View File

@@ -0,0 +1,9 @@
package sms
type Sms interface {
// 发送
Send() (bool, error)
// 用于获取准确的返回数据
GetResponse() interface{}
}