gitee.com/h79/goutils@v1.22.10/loader/loader.go (about) 1 package loader 2 3 import ( 4 "encoding/json" 5 "encoding/xml" 6 "gitee.com/h79/goutils/common/bus" 7 "gitee.com/h79/goutils/common/coder" 8 cJSON "gitee.com/h79/goutils/common/json" 9 "gitee.com/h79/goutils/common/system" 10 cXML "gitee.com/h79/goutils/common/xml" 11 cYAML "gitee.com/h79/goutils/common/yaml" 12 "gopkg.in/yaml.v3" 13 "sync" 14 "sync/atomic" 15 "time" 16 ) 17 18 type LoadFunc func() (interface{}, error) 19 20 type Loader struct { 21 stop chan bool 22 update chan bool 23 reading bool 24 watch int32 25 upChan chan bool 26 second time.Duration 27 format string //xml,json,yaml 28 topic string 29 cmd string 30 data interface{} 31 rm sync.RWMutex 32 loadFunc LoadFunc 33 unmarshal coder.Unmarshal //默认json 34 publisher bus.Publisher 35 watchRunning system.RunningCheck 36 } 37 38 const ( 39 defCmd = "load" 40 defTopic = "load.data" 41 ) 42 43 func CreateLoader() Loader { 44 return Loader{ 45 cmd: defCmd, 46 topic: defTopic, 47 format: "json", 48 watch: 0, 49 update: make(chan bool), 50 stop: make(chan bool), 51 second: time.Second * 5, 52 reading: false, 53 data: nil, 54 loadFunc: nil, 55 publisher: nil, 56 unmarshal: cJSON.DefaultCoder, 57 } 58 } 59 60 func New() *Loader { 61 l := CreateLoader() 62 return &l 63 } 64 65 // Deprecated: this function simply calls [Data]. 66 func (load *Loader) Get() interface{} { 67 return load.Data() 68 } 69 70 func (load *Loader) Data() interface{} { 71 load.rm.RLock() 72 defer load.rm.RUnlock() 73 return load.data 74 } 75 76 func (load *Loader) JSON() (string, error) { 77 load.rm.RLock() 78 defer load.rm.RUnlock() 79 buf, err := json.Marshal(load.data) 80 if err != nil { 81 return "", err 82 } 83 return string(buf), nil 84 } 85 86 func (load *Loader) XML() (string, error) { 87 load.rm.RLock() 88 defer load.rm.RUnlock() 89 buf, err := xml.Marshal(load.data) 90 if err != nil { 91 return "", err 92 } 93 return string(buf), nil 94 } 95 96 func (load *Loader) YAML() (string, error) { 97 load.rm.RLock() 98 defer load.rm.RUnlock() 99 buf, err := yaml.Marshal(load.data) 100 if err != nil { 101 return "", err 102 } 103 return string(buf), nil 104 } 105 106 func (load *Loader) WithFormat(format string) *Loader { 107 load.format = format 108 if format == JsonFormat { 109 load.unmarshal = cJSON.DefaultCoder 110 } else if format == XmlFormat { 111 load.unmarshal = cXML.DefaultCoder 112 } else if format == YamlFormat { 113 load.unmarshal = cYAML.DefaultCoder 114 } else { 115 load.unmarshal = coder.UnmarshalFunc(func(content []byte, v interface{}) error { 116 return ErrNotDefined 117 }) 118 } 119 return load 120 } 121 122 func (load *Loader) WithCmd(cmd string) *Loader { 123 load.cmd = cmd 124 return load 125 } 126 127 func (load *Loader) WithTopic(topic string) *Loader { 128 load.topic = topic 129 return load 130 } 131 132 func (load *Loader) WithSecond(second time.Duration) *Loader { 133 load.second = second 134 return load 135 } 136 137 func (load *Loader) WithLoadFunc(l LoadFunc) *Loader { 138 load.loadFunc = l 139 return load 140 } 141 142 func (load *Loader) WithUnmarshal(l coder.Unmarshal) *Loader { 143 load.unmarshal = l 144 return load 145 } 146 147 func (load *Loader) WithPublisher(p bus.Publisher) *Loader { 148 load.publisher = p 149 return load 150 } 151 152 func (load *Loader) Update(async bool) { 153 if async { 154 if atomic.LoadInt32(&load.watch) > 0 { 155 load.watchRunning.GoRunning(load.watchLoad) 156 load.update <- true 157 } else { 158 system.ChildRunning(load.read) 159 } 160 } else { 161 load.read() 162 } 163 } 164 165 func (load *Loader) Reset() { 166 load.reading = false 167 } 168 169 func (load *Loader) Watch() { 170 if atomic.LoadInt32(&load.watch) == 0 { 171 atomic.StoreInt32(&load.watch, 1) 172 load.watchRunning.GoRunning(load.watchLoad) 173 } 174 } 175 176 func (load *Loader) WatchChan() <-chan bool { 177 if atomic.LoadInt32(&load.watch) == 0 { 178 atomic.StoreInt32(&load.watch, 2) 179 load.upChan = make(chan bool) 180 } else if atomic.LoadInt32(&load.watch) == 1 { 181 atomic.StoreInt32(&load.watch, 2) 182 load.upChan = make(chan bool) 183 } 184 load.watchRunning.GoRunning(load.watchLoad) 185 186 return load.upChan 187 } 188 189 func (load *Loader) Stop() { 190 if atomic.LoadInt32(&load.watch) == 2 { 191 close(load.upChan) 192 } 193 atomic.StoreInt32(&load.watch, 0) 194 close(load.stop) 195 } 196 197 func (load *Loader) Read() (error, bool) { 198 if load.loadFunc == nil { 199 return nil, false 200 } 201 if load.reading { 202 return nil, false 203 } 204 load.reading = true 205 data, err := load.loadFunc() 206 load.reading = false 207 if err != nil { 208 return err, false 209 } 210 load.rm.Lock() 211 load.data = data 212 load.rm.Unlock() 213 return nil, true 214 } 215 216 func (load *Loader) watchLoad() { 217 defer atomic.StoreInt32(&load.watch, 0) 218 ticker := time.NewTicker(load.second) 219 for { 220 select { 221 case _ = <-load.stop: 222 return 223 case _ = <-load.update: 224 if load.readV2() && atomic.LoadInt32(&load.watch) == 2 { 225 load.upChan <- true 226 } 227 case _ = <-ticker.C: 228 if load.readV2() && atomic.LoadInt32(&load.watch) == 2 { 229 load.upChan <- true 230 } 231 case <-system.Closed(): 232 return 233 } 234 } 235 } 236 237 func (load *Loader) readV2() bool { 238 // 打开文件 239 // 为什么使用匿名函数? 当匿名函数退出时可用defer去关闭文件 240 // 如果不用匿名函数,在循环中不好关闭文件,一不小心就内存泄露 241 err, fUpdate := load.Read() 242 if err != nil { 243 return false 244 } 245 if !fUpdate { 246 return false 247 } 248 load.publish() 249 return true 250 } 251 252 func (load *Loader) read() { 253 load.readV2() 254 } 255 256 func (load *Loader) publish() { 257 if load.publisher == nil { 258 return 259 } 260 topic := load.topic 261 if len(topic) == 0 { 262 topic = defTopic 263 } 264 cmd := load.cmd 265 if len(cmd) == 0 { 266 cmd = defCmd 267 } 268 load.publisher.Publish(topic, bus.Event{Cmd: cmd, Data: load.data}) 269 }