代码拉取完成,页面将自动刷新
package providers
import (
"context"
"fmt"
"regexp"
"strings"
"time"
)
// SMSProvider SMS提供商接口
type SMSProvider interface {
// GetName 获取提供商名称
GetName() string
// SendSMS 发送单条短信
SendSMS(ctx context.Context, req *SendSMSRequest) (*SendSMSResponse, error)
// SendBatchSMS 批量发送短信
SendBatchSMS(ctx context.Context, req *BatchSMSRequest) (*BatchSMSResponse, error)
// QuerySMS 查询短信状态
QuerySMS(ctx context.Context, req *QuerySMSRequest) (*QuerySMSResponse, error)
// GetQuota 获取剩余配额
GetQuota(ctx context.Context) (*QuotaResponse, error)
// ValidateConfig 验证配置
ValidateConfig() error
// HealthCheck 健康检查
HealthCheck(ctx context.Context) error
}
// SendSMSRequest 发送短信请求
type SendSMSRequest struct {
Phone string `json:"phone"` // 手机号
Content string `json:"content"` // 短信内容
Sign string `json:"sign,omitempty"` // 短信签名
Type string `json:"type,omitempty"` // 短信类型
Priority int `json:"priority,omitempty"` // 优先级
Scheduled *time.Time `json:"scheduled,omitempty"` // 定时发送时间
Metadata map[string]string `json:"metadata,omitempty"` // 元数据
MessageID string `json:"message_id"` // 消息ID
}
// SendSMSResponse 发送短信响应
type SendSMSResponse struct {
MessageID string `json:"message_id"` // 消息ID
Status string `json:"status"` // 状态
ProviderID string `json:"provider_id"` // 提供商消息ID
Cost float64 `json:"cost,omitempty"` // 费用
SentAt time.Time `json:"sent_at"` // 发送时间
DeliveredAt *time.Time `json:"delivered_at,omitempty"` // 送达时间
ErrorCode string `json:"error_code,omitempty"` // 错误代码
ErrorMessage string `json:"error_message,omitempty"` // 错误消息
Metadata map[string]string `json:"metadata,omitempty"` // 元数据
}
// BatchSMSRequest 批量发送短信请求
type BatchSMSRequest struct {
Requests []*SendSMSRequest `json:"requests"` // 短信请求列表
BatchID string `json:"batch_id"` // 批次ID
}
// BatchSMSResponse 批量发送短信响应
type BatchSMSResponse struct {
BatchID string `json:"batch_id"` // 批次ID
Total int `json:"total"` // 总数
Success int `json:"success"` // 成功数
Failed int `json:"failed"` // 失败数
Results []*BatchSMSResult `json:"results"` // 结果列表
StartedAt time.Time `json:"started_at"` // 开始时间
FinishedAt time.Time `json:"finished_at"` // 完成时间
Cost float64 `json:"cost"` // 总费用
}
// BatchSMSResult 批量发送结果
type BatchSMSResult struct {
Index int `json:"index"` // 索引
Phone string `json:"phone"` // 手机号
MessageID string `json:"message_id,omitempty"` // 消息ID
ProviderID string `json:"provider_id,omitempty"` // 提供商消息ID
Status string `json:"status"` // 状态
Cost float64 `json:"cost,omitempty"` // 费用
SentAt *time.Time `json:"sent_at,omitempty"` // 发送时间
ErrorCode string `json:"error_code,omitempty"` // 错误代码
ErrorMessage string `json:"error_message,omitempty"` // 错误消息
}
// QuerySMSRequest 查询短信状态请求
type QuerySMSRequest struct {
MessageID string `json:"message_id,omitempty"` // 消息ID
ProviderID string `json:"provider_id,omitempty"` // 提供商消息ID
Phone string `json:"phone,omitempty"` // 手机号
}
// QuerySMSResponse 查询短信状态响应
type QuerySMSResponse struct {
MessageID string `json:"message_id"` // 消息ID
ProviderID string `json:"provider_id"` // 提供商消息ID
Phone string `json:"phone"` // 手机号
Content string `json:"content"` // 短信内容
Status string `json:"status"` // 状态
SentAt *time.Time `json:"sent_at,omitempty"` // 发送时间
DeliveredAt *time.Time `json:"delivered_at,omitempty"` // 送达时间
FailedAt *time.Time `json:"failed_at,omitempty"` // 失败时间
ErrorCode string `json:"error_code,omitempty"` // 错误代码
ErrorMessage string `json:"error_message,omitempty"` // 错误消息
Cost float64 `json:"cost,omitempty"` // 费用
Metadata map[string]string `json:"metadata,omitempty"` // 元数据
}
// QuotaResponse 配额响应
type QuotaResponse struct {
Total int64 `json:"total"` // 总配额
Used int64 `json:"used"` // 已使用
Remaining int64 `json:"remaining"` // 剩余
ResetAt time.Time `json:"reset_at"` // 重置时间
}
// ProviderError 提供商错误
type ProviderError struct {
Code string `json:"code"` // 错误代码
Message string `json:"message"` // 错误消息
Provider string `json:"provider"` // 提供商
Retryable bool `json:"retryable"` // 是否可重试
}
// Error 实现error接口
func (e *ProviderError) Error() string {
return fmt.Sprintf("[%s] %s: %s", e.Provider, e.Code, e.Message)
}
// IsRetryable 是否可重试
func (e *ProviderError) IsRetryable() bool {
return e.Retryable
}
// ProviderFactory 提供商工厂接口
type ProviderFactory interface {
// CreateProvider 创建提供商实例
CreateProvider(providerType string, config interface{}) (SMSProvider, error)
// GetSupportedProviders 获取支持的提供商列表
GetSupportedProviders() []string
// ValidateProviderConfig 验证提供商配置
ValidateProviderConfig(providerType string, config interface{}) error
}
// BaseProvider 基础提供商实现
type BaseProvider struct {
name string
timeout time.Duration
}
// GetName 获取提供商名称
func (p *BaseProvider) GetName() string {
return p.name
}
// SetTimeout 设置超时时间
func (p *BaseProvider) SetTimeout(timeout time.Duration) {
p.timeout = timeout
}
// GetTimeout 获取超时时间
func (p *BaseProvider) GetTimeout() time.Duration {
if p.timeout == 0 {
return 30 * time.Second // 默认30秒
}
return p.timeout
}
// ValidateRequest 验证请求参数
func (p *BaseProvider) ValidateRequest(req *SendSMSRequest) error {
if req == nil {
return &ProviderError{
Code: "INVALID_REQUEST",
Message: "请求不能为空",
Provider: p.name,
Retryable: false,
}
}
if req.Phone == "" {
return &ProviderError{
Code: "INVALID_PHONE",
Message: "手机号不能为空",
Provider: p.name,
Retryable: false,
}
}
if req.Content == "" {
return &ProviderError{
Code: "INVALID_CONTENT",
Message: "短信内容不能为空",
Provider: p.name,
Retryable: false,
}
}
return nil
}
// ValidateBatchRequest 验证批量请求参数
func (p *BaseProvider) ValidateBatchRequest(req *BatchSMSRequest) error {
if req == nil {
return &ProviderError{
Code: "INVALID_REQUEST",
Message: "批量请求不能为空",
Provider: p.name,
Retryable: false,
}
}
if len(req.Requests) == 0 {
return &ProviderError{
Code: "EMPTY_BATCH",
Message: "批量请求列表不能为空",
Provider: p.name,
Retryable: false,
}
}
for i, smsReq := range req.Requests {
if err := p.ValidateRequest(smsReq); err != nil {
return &ProviderError{
Code: "INVALID_BATCH_ITEM",
Message: fmt.Sprintf("第%d项请求无效: %s", i+1, err.Error()),
Provider: p.name,
Retryable: false,
}
}
}
return nil
}
// CreateProviderError 创建提供商错误
func (p *BaseProvider) CreateProviderError(code, message string, retryable bool) *ProviderError {
return &ProviderError{
Code: code,
Message: message,
Provider: p.name,
Retryable: retryable,
}
}
// FormatPhone 格式化手机号
func FormatPhone(phone string) string {
// 去除空格和特殊字符
phone = strings.ReplaceAll(phone, " ", "")
phone = strings.ReplaceAll(phone, "-", "")
phone = strings.ReplaceAll(phone, "(", "")
phone = strings.ReplaceAll(phone, ")", "")
// 如果是中国大陆手机号,确保以+86开头
if matched, _ := regexp.MatchString(`^1[3-9]\d{9}$`, phone); matched {
if !strings.HasPrefix(phone, "+86") {
phone = "+86" + phone
}
}
return phone
}
// EstimateCost 估算费用
func EstimateCost(content string, smsType string) float64 {
length := len([]rune(content))
baseCost := 0.05 // 基础费用5分
// 根据长度计算费用
if length > 70 {
baseCost *= float64((length-1)/70 + 1) // 超过70字符按条数计费
}
// 根据类型调整费用
switch smsType {
case "marketing":
baseCost *= 1.2 // 营销短信费用更高
case "international":
baseCost *= 3.0 // 国际短信费用更高
}
return baseCost
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。