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  }