149 lines
4.0 KiB
Go
149 lines
4.0 KiB
Go
package sms
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"strings"
|
|
)
|
|
|
|
// ConfigKey 主站节点短信配置项,与分销站点的 business_templates 同构。
|
|
const ConfigKey = "sms.business_templates"
|
|
|
|
// DefaultStaleDays 上架未成交提醒的默认天数阈值。
|
|
const DefaultStaleDays = 3
|
|
|
|
// ConfigReader 读取系统配置文本,由 systemconfig.Repository 实现。
|
|
type ConfigReader interface {
|
|
FindValue(ctx context.Context, key string) (string, error)
|
|
}
|
|
|
|
// LoadConfig 从系统配置读取并解析节点短信配置。
|
|
func LoadConfig(ctx context.Context, reader ConfigReader) (Config, error) {
|
|
if reader == nil {
|
|
return DefaultConfig(), nil
|
|
}
|
|
value, err := reader.FindValue(ctx, ConfigKey)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
return ParseConfigValue(value)
|
|
}
|
|
|
|
// NodeConfig 是单个节点的开关与模板 CODE。
|
|
type NodeConfig struct {
|
|
Enabled bool `json:"enabled"`
|
|
TemplateCode string `json:"template_code"`
|
|
// StaleDays 仅上架未成交提醒使用:上架满多少天仍未成交才提醒,0 表示取默认值。
|
|
StaleDays int `json:"stale_days,omitempty"`
|
|
}
|
|
|
|
// Config 是主站节点短信配置(系统配置 sms.business_templates 的 JSON 结构)。
|
|
type Config struct {
|
|
Enabled bool `json:"enabled"`
|
|
Nodes map[string]NodeConfig `json:"nodes"`
|
|
}
|
|
|
|
// DefaultConfig 返回默认配置:总开关关闭(避免误发产生短信费用),
|
|
// 三个节点默认各自开启,模板 CODE 留空由运营在后台填写。
|
|
func DefaultConfig() Config {
|
|
nodes := make(map[string]NodeConfig, len(nodeMetas))
|
|
for _, meta := range nodeMetas {
|
|
node := NodeConfig{Enabled: true}
|
|
if meta.SupportsStaleDays {
|
|
node.StaleDays = DefaultStaleDays
|
|
}
|
|
nodes[meta.Code] = node
|
|
}
|
|
return Config{Enabled: false, Nodes: nodes}
|
|
}
|
|
|
|
// DefaultConfigValue 返回默认配置的 JSON 文本。
|
|
func DefaultConfigValue() string {
|
|
raw, err := MarshalConfig(DefaultConfig())
|
|
if err != nil {
|
|
return `{"enabled":false,"nodes":{}}`
|
|
}
|
|
return raw
|
|
}
|
|
|
|
// ParseConfigValue 解析系统配置里的 JSON 文本,缺失字段回落到默认值。
|
|
func ParseConfigValue(value string) (Config, error) {
|
|
cfg := DefaultConfig()
|
|
value = strings.TrimSpace(value)
|
|
if value == "" {
|
|
return cfg, nil
|
|
}
|
|
var raw struct {
|
|
Enabled *bool `json:"enabled"`
|
|
Nodes map[string]NodeConfig `json:"nodes"`
|
|
}
|
|
if err := json.Unmarshal([]byte(value), &raw); err != nil {
|
|
return Config{}, err
|
|
}
|
|
if raw.Enabled != nil {
|
|
cfg.Enabled = *raw.Enabled
|
|
}
|
|
if raw.Nodes != nil {
|
|
// 以已登记节点为基准合并,避免后台配置里出现未知节点。
|
|
for code, node := range raw.Nodes {
|
|
if !IsKnownNode(code) {
|
|
continue
|
|
}
|
|
node.TemplateCode = strings.TrimSpace(node.TemplateCode)
|
|
if node.StaleDays < 0 {
|
|
node.StaleDays = 0
|
|
}
|
|
cfg.Nodes[code] = node
|
|
}
|
|
}
|
|
return cfg, nil
|
|
}
|
|
|
|
// MarshalConfig 规范化并序列化配置。
|
|
func MarshalConfig(cfg Config) (string, error) {
|
|
normalized := DefaultConfig()
|
|
normalized.Enabled = cfg.Enabled
|
|
for code, node := range cfg.Nodes {
|
|
if !IsKnownNode(code) {
|
|
continue
|
|
}
|
|
node.TemplateCode = strings.TrimSpace(node.TemplateCode)
|
|
if node.StaleDays < 0 {
|
|
node.StaleDays = 0
|
|
}
|
|
normalized.Nodes[code] = node
|
|
}
|
|
raw, err := json.Marshal(normalized)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(raw), nil
|
|
}
|
|
|
|
// Node 返回指定节点的配置。
|
|
func (c Config) Node(code string) (NodeConfig, bool) {
|
|
node, ok := c.Nodes[code]
|
|
return node, ok
|
|
}
|
|
|
|
// NodeActive 判断节点是否可发送:总开关、节点开关与模板 CODE 都必须就绪。
|
|
func (c Config) NodeActive(code string) bool {
|
|
if !c.Enabled {
|
|
return false
|
|
}
|
|
node, ok := c.Node(code)
|
|
if !ok || !node.Enabled {
|
|
return false
|
|
}
|
|
return strings.TrimSpace(node.TemplateCode) != ""
|
|
}
|
|
|
|
// StaleDaysFor 返回上架未成交提醒的天数阈值,未配置时取默认值。
|
|
func (c Config) StaleDaysFor(code string) int {
|
|
node, ok := c.Node(code)
|
|
if !ok || node.StaleDays <= 0 {
|
|
return DefaultStaleDays
|
|
}
|
|
return node.StaleDays
|
|
}
|