You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

watcher.go 3.3 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. package sysevent
  2. import (
  3. "fmt"
  4. "sync"
  5. "github.com/streadway/amqp"
  6. "gitlink.org.cn/cloudream/common/pkgs/async"
  7. "gitlink.org.cn/cloudream/common/utils/lo2"
  8. "gitlink.org.cn/cloudream/common/utils/serder"
  9. )
  10. type Watcher interface {
  11. OnEvent(event SysEvent)
  12. }
  13. type WatcherEvent interface{}
  14. type WatcherExited struct {
  15. Err error
  16. }
  17. type WatcherHost struct {
  18. cfg Config
  19. watchers []Watcher
  20. lock sync.Mutex
  21. connection *amqp.Connection
  22. channel *amqp.Channel
  23. recvChan <-chan amqp.Delivery
  24. }
  25. func NewWatcherHost(cfg Config) (*WatcherHost, error) {
  26. if !cfg.Enabled {
  27. return &WatcherHost{
  28. cfg: cfg,
  29. }, nil
  30. }
  31. config := amqp.Config{
  32. Vhost: cfg.VHost,
  33. }
  34. url := fmt.Sprintf("amqp://%s:%s@%s", cfg.Account, cfg.Password, cfg.Address)
  35. connection, err := amqp.DialConfig(url, config)
  36. if err != nil {
  37. return nil, err
  38. }
  39. channel, err := connection.Channel()
  40. if err != nil {
  41. connection.Close()
  42. return nil, fmt.Errorf("openning channel on connection: %w", err)
  43. }
  44. err = channel.ExchangeDeclare(cfg.Exchange, "fanout", false, true, false, false, nil)
  45. if err != nil {
  46. connection.Close()
  47. return nil, fmt.Errorf("declare exchange: %w", err)
  48. }
  49. _, err = channel.QueueDeclare(
  50. cfg.Queue,
  51. false,
  52. true,
  53. false,
  54. false,
  55. nil,
  56. )
  57. if err != nil {
  58. channel.Close()
  59. connection.Close()
  60. return nil, fmt.Errorf("declare queue: %w", err)
  61. }
  62. err = channel.QueueBind(cfg.Queue, "", cfg.Exchange, false, nil)
  63. if err != nil {
  64. channel.Close()
  65. connection.Close()
  66. return nil, fmt.Errorf("bind queue: %w", err)
  67. }
  68. recvChan, err := channel.Consume(cfg.Queue, "", true, false, true, false, nil)
  69. if err != nil {
  70. channel.Close()
  71. connection.Close()
  72. return nil, fmt.Errorf("consume queue: %w", err)
  73. }
  74. wat := &WatcherHost{
  75. cfg: cfg,
  76. connection: connection,
  77. channel: channel,
  78. recvChan: recvChan,
  79. }
  80. return wat, nil
  81. }
  82. func (w *WatcherHost) Start() *async.UnboundChannel[WatcherEvent] {
  83. ch := async.NewUnboundChannel[WatcherEvent]()
  84. go func() {
  85. if !w.cfg.Enabled {
  86. return
  87. }
  88. defer ch.Close()
  89. defer w.channel.Close()
  90. defer w.connection.Close()
  91. for m := range w.recvChan {
  92. evt, err := serder.JSONToObjectEx[SysEvent](m.Body)
  93. if err != nil {
  94. ch.Send(OtherError{Err: fmt.Errorf("deserialize event: %w", err)})
  95. continue
  96. }
  97. w.lock.Lock()
  98. ws := make([]Watcher, 0, len(w.watchers))
  99. ws = append(ws, w.watchers...)
  100. w.lock.Unlock()
  101. for _, w := range ws {
  102. w.OnEvent(evt)
  103. }
  104. }
  105. ch.Send(WatcherExited{Err: nil})
  106. }()
  107. return ch
  108. }
  109. func (w *WatcherHost) Stop() {
  110. if !w.cfg.Enabled {
  111. return
  112. }
  113. w.channel.Close()
  114. w.connection.Close()
  115. }
  116. func (w *WatcherHost) Enabled() bool {
  117. return w.cfg.Enabled
  118. }
  119. func (w *WatcherHost) AddWatcher(watcher Watcher) {
  120. w.lock.Lock()
  121. defer w.lock.Unlock()
  122. w.watchers = append(w.watchers, watcher)
  123. }
  124. func (w *WatcherHost) AddWatcherFn(fn func(event SysEvent)) Watcher {
  125. watcher := &fnWatcher{fn: fn}
  126. w.AddWatcher(watcher)
  127. return watcher
  128. }
  129. func (w *WatcherHost) RemoveWatcher(watcher Watcher) {
  130. w.lock.Lock()
  131. defer w.lock.Unlock()
  132. w.watchers = lo2.Remove(w.watchers, watcher)
  133. }
  134. type fnWatcher struct {
  135. fn func(event SysEvent)
  136. }
  137. func (w *fnWatcher) OnEvent(event SysEvent) {
  138. w.fn(event)
  139. }

本项目旨在将云际存储公共基础设施化,使个人及企业可低门槛使用高效的云际存储服务(安装开箱即用云际存储客户端即可,无需关注其他组件的部署),同时支持用户灵活便捷定制云际存储的功能细节。