作者 唐旭辉

新增,修改

... ... @@ -6,7 +6,7 @@ require (
github.com/astaxie/beego v1.10.0
github.com/go-sql-driver/mysql v1.4.1
github.com/prometheus/client_golang v1.1.0
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect
gitlab.fjmaimaimai.com/mmm-go/gocomm v0.0.1
google.golang.org/appengine v1.6.2 // indirect
)
... ...
... ... @@ -65,6 +65,7 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
... ... @@ -89,8 +90,10 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
... ...
package datastore
//redis 缓存
... ...
package datastore
// 内存
... ...
package filestore
//IFileStore TODO文件存储相关
type IFileStore interface {
Auth() error //在获取文件前进行对请求进行检查
ReadFile() (string, error) //实际获取文件操作
StoreFile() (string, error) //实际存储文件操作
DeleteFile() error
}
// type LocalFileStore struct {
// }
// type XXXFileStore struct {
// }
... ...
... ... @@ -3,22 +3,34 @@ package sms
import (
"encoding/json"
"errors"
"fmt"
"regexp"
"github.com/astaxie/beego"
"github.com/astaxie/beego/httplib"
)
//ISmsServe 短信服务接口协议
type ISmsServe interface {
Send() error //调用远端接口发送短信
TextContent(v ...interface{}) (string, error) //构建短信文本内容
ValidReturn() (string, error) //检查调用远端接口后的返回内容,可用于记日志等操作
Name() string
}
//SmsServe 生产线上使用的短信服务
type SmsServe struct {
ToPhone string
UseTpl string
smsContent string //非导出
serveReturn *YunPainReturn //非导出
ToPhone string //对方的电话号码
UseTpl string //使用的短信模板
smsContent string //非导出,最终发送的短信内容
serveReturn *YunPianReturn //非导出,调用远端接口后的响应内容
}
type YunPainReturn struct {
var (
_ ISmsServe = &SmsServe{}
)
type YunPianReturn struct {
Code int `json:"code"` //0代表发送成功,其他code代表出错,详细见"返回值说明"页面
Msg string `json:"msg"` //例如""发送成功"",或者相应错误信息
Count int `json:"count"` //发送成功短信的计费条数(计费条数:70个字一条,超出70个字时按每67字一条计费)
... ... @@ -36,17 +48,34 @@ func NewSmsServe(toPhone string, useTpl string) *SmsServe {
}
//Send 短信服务发送动作
//实现接口 ISmsServe
func (s *SmsServe) Send() error {
if len(s.ToPhone) == 0 {
return nil
}
//TODO
//校验号码合法性/^1[3456789][0-9]{9}$/
ok, err := regexp.MatchString(`^1[3456789][0-9]{9}$`, s.ToPhone)
if !ok {
return fmt.Errorf("ToPhone err:%w", err)
}
//发送短信
var (
resp *YunPianReturn
)
post := httplib.Post(beego.AppConfig.String("yunpian_sms_sdk_url"))
post.Param("apikey", beego.AppConfig.String("yunpian_app_key"))
post.Param("mobile", s.ToPhone)
post.Param("text", s.smsContent)
if err := post.ToJSON(&resp); err != nil {
return fmt.Errorf("parse yunpian response err:%w ", err)
}
//获取并设置返回值
s.serveReturn = resp
return nil
}
// TextContent 短信正文内容设置
//实现接口 ISmsServe
func (s *SmsServe) TextContent(v ...interface{}) (string, error) {
tpl, err := getSmsTpl(s.UseTpl)
if err != nil {
... ... @@ -61,6 +90,7 @@ func (s *SmsServe) TextContent(v ...interface{}) (string, error) {
}
//ValidReturn 校验调用远端接口后返回的响应内容
//实现接口 ISmsServe
func (s *SmsServe) ValidReturn() (string, error) {
if s.serveReturn == nil {
return "", errors.New("serveReturn is nil")
... ... @@ -71,3 +101,69 @@ func (s *SmsServe) ValidReturn() (string, error) {
}
return string(str), nil
}
func (s *SmsServe) Name() string {
return "SmsServe"
}
//DevSmsServe 开发调试使用的短信服务
type DevSmsServe struct {
ToPhone string //对方的电话号码
UseTpl string //使用的短信模板
smsContent string //非导出,最终发送的短信内容
serveReturn string //非导出,调用远端接口后的响应内容
}
var (
_ ISmsServe = &DevSmsServe{}
)
func NewDevSmsServe(toPhone string, useTpl string) *DevSmsServe {
return &DevSmsServe{
ToPhone: toPhone,
UseTpl: useTpl,
serveReturn: "",
}
}
//Send 实现接口 ISmsServe
func (s *DevSmsServe) Send() error {
return nil
}
//TextContent 实现接口 ISmsServe
func (s *DevSmsServe) TextContent(v ...interface{}) (string, error) {
tpl, err := getSmsTpl(s.UseTpl)
if err != nil {
return "", err
}
t, err := tpl.ParseTpl(v)
if err != nil {
return "", err
}
s.smsContent = t
return t, nil
}
//ValidReturn 实现接口 ISmsServe
func (s *DevSmsServe) ValidReturn() (string, error) {
return "ok", nil
}
func (s *DevSmsServe) Name() string {
return "DevSmsServe"
}
//SendSms 发送短信调用出口 TODO
func SendSms(phone string, code string, param ...interface{}) error {
var serve ISmsServe
serve = NewSmsServe(phone, code)
// serve = NewDevSmsServe(phone, code)
_, err := serve.TextContent(param)
if err != nil {
return err
}
return serve.Send()
}
... ...
package sms
import (
"bytes"
"errors"
"fmt"
"html/template"
)
type ISmsTpl interface {
... ... @@ -13,6 +15,9 @@ type ISmsTpl interface {
//注册短信模板
var smsTpl = map[string]ISmsTpl{
"10001": SmsTpl{"【云片网】您的验证码是%s", 1},
"10002": SmsTplUseHtml{
`【买买买信息科技】{{.Code}}({{.AppName}}手机验证码,请完成验证),如非本人操作,请忽略本短信`,
"10002"},
}
const (
... ... @@ -21,8 +26,8 @@ const (
)
type SmsTpl struct {
Formate string
ParamNum int
Formate string //模板字符串
ParamNum int //模板限定参数数量
}
var (
... ... @@ -42,6 +47,35 @@ func (t SmsTpl) String() string {
return t.Formate
}
//SmsTplUseHtml 以html模板方式构建短信模板
type SmsTplUseHtml struct {
Formate string //模板字符串
Name string
}
var (
_ ISmsTpl = SmsTplUseHtml{}
)
func (t SmsTplUseHtml) ParseTpl(v ...interface{}) (string, error) {
var param interface{}
if len(v) > 0 {
param = v[0]
}
tpl, err := template.New(t.Name).Parse(t.Formate)
if err != nil {
return "", err
}
btTpl := bytes.NewBuffer(nil)
if err = tpl.Execute(btTpl, param); err != nil {
return "", err
}
return btTpl.String(), nil
}
func (t SmsTplUseHtml) String() string {
return t.Formate
}
//getSmsTpl 获取样板
//TODO 待优化
func getSmsTpl(code string) (ISmsTpl, error) {
... ...