You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
4.0 KiB
175 lines
4.0 KiB
package sms
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"yunyan/lego/utils/mapstructure"
|
|
)
|
|
|
|
// 短信服务商。Provider 留空按腾讯云处理(兼容加入阿里云之前已落库/落 yaml 的配置)。
|
|
const (
|
|
ProviderTencent = "tencent"
|
|
ProviderAliyun = "aliyun"
|
|
)
|
|
|
|
// 阿里云默认值:地域与模板参数名。
|
|
const (
|
|
defaultAliRegionId = "cn-hangzhou"
|
|
defaultAliTemplateParam = "code"
|
|
)
|
|
|
|
type Option func(*Options)
|
|
type Options struct {
|
|
Provider string // tencent(默认) | aliyun
|
|
|
|
// 腾讯云
|
|
AppId string
|
|
SecretId string
|
|
SecretKey string
|
|
|
|
// 阿里云
|
|
AccessKeyId string
|
|
AccessKeySecret string
|
|
RegionId string // 默认 cn-hangzhou;国际站按需 ap-southeast-1
|
|
TemplateParamName string // 模板变量名,默认 code(对应模板里的 ${code})
|
|
|
|
// 两家共用
|
|
SignName string
|
|
Template1 string // 国内模板(腾讯 TemplateId / 阿里 TemplateCode)
|
|
Template2 string // 国际/港澳台模板
|
|
}
|
|
|
|
func SetProvider(v string) Option {
|
|
return func(o *Options) {
|
|
o.Provider = v
|
|
}
|
|
}
|
|
|
|
func SetAppId(v string) Option {
|
|
return func(o *Options) {
|
|
o.AppId = v
|
|
}
|
|
}
|
|
|
|
func SetSecretId(v string) Option {
|
|
return func(o *Options) {
|
|
o.SecretId = v
|
|
}
|
|
}
|
|
|
|
func KeySecretKey(v string) Option {
|
|
return func(o *Options) {
|
|
o.SecretKey = v
|
|
}
|
|
}
|
|
|
|
func SetAccessKeyId(v string) Option {
|
|
return func(o *Options) {
|
|
o.AccessKeyId = v
|
|
}
|
|
}
|
|
|
|
func SetAccessKeySecret(v string) Option {
|
|
return func(o *Options) {
|
|
o.AccessKeySecret = v
|
|
}
|
|
}
|
|
|
|
func SetRegionId(v string) Option {
|
|
return func(o *Options) {
|
|
o.RegionId = v
|
|
}
|
|
}
|
|
|
|
func SetTemplateParamName(v string) Option {
|
|
return func(o *Options) {
|
|
o.TemplateParamName = v
|
|
}
|
|
}
|
|
|
|
func SetSignName(v string) Option {
|
|
return func(o *Options) {
|
|
o.SignName = v
|
|
}
|
|
}
|
|
func SetTemplate1(v string) Option {
|
|
return func(o *Options) {
|
|
o.Template1 = v
|
|
}
|
|
}
|
|
func SetTemplate2(v string) Option {
|
|
return func(o *Options) {
|
|
o.Template2 = v
|
|
}
|
|
}
|
|
func newOptionsByOption(opts ...Option) (Options, error) {
|
|
options := Options{}
|
|
for _, o := range opts {
|
|
o(&options)
|
|
}
|
|
options.normalize()
|
|
return options, options.validate()
|
|
}
|
|
|
|
// provider 归一化后的服务商(空 → 腾讯云)。
|
|
func (o Options) provider() string {
|
|
if p := strings.ToLower(strings.TrimSpace(o.Provider)); p != "" {
|
|
return p
|
|
}
|
|
return ProviderTencent
|
|
}
|
|
|
|
// normalize 填充可留空字段的默认值,并把服务商归一化成小写。
|
|
func (o *Options) normalize() {
|
|
o.Provider = o.provider()
|
|
if o.Provider == ProviderAliyun {
|
|
if o.RegionId == "" {
|
|
o.RegionId = defaultAliRegionId
|
|
}
|
|
if o.TemplateParamName == "" {
|
|
o.TemplateParamName = defaultAliTemplateParam
|
|
}
|
|
}
|
|
}
|
|
|
|
// validate 校验发短信必需字段,按服务商分别校验。
|
|
func (o Options) validate() error {
|
|
switch o.provider() {
|
|
case ProviderTencent:
|
|
if o.SecretId == "" {
|
|
return errors.New("sms 配置缺失: SecretId 为空(腾讯云)")
|
|
}
|
|
if o.SecretKey == "" {
|
|
return errors.New("sms 配置缺失: SecretKey 为空(腾讯云)")
|
|
}
|
|
case ProviderAliyun:
|
|
if o.AccessKeyId == "" {
|
|
return errors.New("sms 配置缺失: AccessKeyId 为空(阿里云)")
|
|
}
|
|
if o.AccessKeySecret == "" {
|
|
return errors.New("sms 配置缺失: AccessKeySecret 为空(阿里云)")
|
|
}
|
|
if o.SignName == "" {
|
|
return errors.New("sms 配置缺失: SignName 为空(阿里云签名必填)")
|
|
}
|
|
default:
|
|
return fmt.Errorf("sms 配置错误: 未知服务商 Provider=%q(可选 %s / %s)", o.Provider, ProviderTencent, ProviderAliyun)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// newOptionsChecked 解析 map 配置并校验,不合法时返回 error 而非 panic。
|
|
// 启动(OnInit)与运行时热重载(Reload)共用:配置缺失只应让本子系统降级/本次重载失败,不该打挂进程。
|
|
func newOptionsChecked(config map[string]interface{}, opts ...Option) (Options, error) {
|
|
options := Options{}
|
|
if config != nil {
|
|
mapstructure.Decode(config, &options)
|
|
}
|
|
for _, o := range opts {
|
|
o(&options)
|
|
}
|
|
options.normalize()
|
|
return options, options.validate()
|
|
}
|
|
|