初始化项目
This commit is contained in:
28
trunk/goutil/smsUtil/qcloud/commonField.go
Normal file
28
trunk/goutil/smsUtil/qcloud/commonField.go
Normal 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,
|
||||
}
|
||||
}
|
||||
16
trunk/goutil/smsUtil/qcloud/msgSmsField.go
Normal file
16
trunk/goutil/smsUtil/qcloud/msgSmsField.go
Normal 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,
|
||||
}
|
||||
}
|
||||
144
trunk/goutil/smsUtil/qcloud/qcloud.go
Normal file
144
trunk/goutil/smsUtil/qcloud/qcloud.go
Normal 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
|
||||
}
|
||||
22
trunk/goutil/smsUtil/qcloud/response.go
Normal file
22
trunk/goutil/smsUtil/qcloud/response.go
Normal 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
|
||||
}
|
||||
86
trunk/goutil/smsUtil/qcloud/sms.go
Normal file
86
trunk/goutil/smsUtil/qcloud/sms.go
Normal 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
|
||||
}
|
||||
16
trunk/goutil/smsUtil/qcloud/smsData.go
Normal file
16
trunk/goutil/smsUtil/qcloud/smsData.go
Normal 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}
|
||||
}
|
||||
14
trunk/goutil/smsUtil/qcloud/telField.go
Normal file
14
trunk/goutil/smsUtil/qcloud/telField.go
Normal 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,
|
||||
}
|
||||
}
|
||||
19
trunk/goutil/smsUtil/qcloud/tmplSmsField.go
Normal file
19
trunk/goutil/smsUtil/qcloud/tmplSmsField.go
Normal 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,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user