package sms import ( "errors" "sync" ) type ( ISys interface { SendCaptcha(mobile string, captcha string) error } ) // defsys 由 OnInit(启动) 与 Reload(运行时热更) 写、SendCaptcha 读,故必须加锁: // 无锁并发读写接口值是 data race。 var ( mu sync.RWMutex defsys ISys ) var errNotInit = errors.New("sms 系统未初始化") func get() ISys { mu.RLock() defer mu.RUnlock() return defsys } func set(sys ISys) { mu.Lock() defsys = sys mu.Unlock() } func OnInit(config map[string]interface{}, option ...Option) (err error) { sys, err := newSys(newOptions(config, option...)) if err != nil { return } set(sys) return } // Reload 运行时热替换短信客户端(console 后台改配置后由业务侧调用)。 // 配置不合法时返回 error 而非 panic,且**保留原客户端不动**。 func Reload(config map[string]interface{}, option ...Option) error { options, err := newOptionsChecked(config, option...) if err != nil { return err } sys, err := newSys(options) if err != nil { return err } set(sys) return nil } func NewSys(option ...Option) (sys ISys, err error) { sys, err = newSys(newOptionsByOption(option...)) return } func SendCaptcha(_email string, _captcha string) error { sys := get() if sys == nil { return errNotInit } return sys.SendCaptcha(_email, _captcha) }