github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/pkg/mq/mq.go (about)

     1  package mq
     2  
     3  import (
     4  	"encoding/gob"
     5  	"github.com/cloudreve/Cloudreve/v3/pkg/aria2/common"
     6  	"github.com/cloudreve/Cloudreve/v3/pkg/aria2/rpc"
     7  	"strconv"
     8  	"sync"
     9  	"time"
    10  )
    11  
    12  // Message 消息事件正文
    13  type Message struct {
    14  	// 消息触发者
    15  	TriggeredBy string
    16  
    17  	// 事件标识
    18  	Event string
    19  
    20  	// 消息正文
    21  	Content interface{}
    22  }
    23  
    24  type CallbackFunc func(Message)
    25  
    26  // MQ 消息队列
    27  type MQ interface {
    28  	rpc.Notifier
    29  
    30  	// 发布一个消息
    31  	Publish(string, Message)
    32  
    33  	// 订阅一个消息主题
    34  	Subscribe(string, int) <-chan Message
    35  
    36  	// 订阅一个消息主题,注册触发回调函数
    37  	SubscribeCallback(string, CallbackFunc)
    38  
    39  	// 取消订阅一个消息主题
    40  	Unsubscribe(string, <-chan Message)
    41  }
    42  
    43  var GlobalMQ = NewMQ()
    44  
    45  func NewMQ() MQ {
    46  	return &inMemoryMQ{
    47  		topics:    make(map[string][]chan Message),
    48  		callbacks: make(map[string][]CallbackFunc),
    49  	}
    50  }
    51  
    52  func init() {
    53  	gob.Register(Message{})
    54  	gob.Register([]rpc.Event{})
    55  }
    56  
    57  type inMemoryMQ struct {
    58  	topics    map[string][]chan Message
    59  	callbacks map[string][]CallbackFunc
    60  	sync.RWMutex
    61  }
    62  
    63  func (i *inMemoryMQ) Publish(topic string, message Message) {
    64  	i.RLock()
    65  	subscribersChan, okChan := i.topics[topic]
    66  	subscribersCallback, okCallback := i.callbacks[topic]
    67  	i.RUnlock()
    68  
    69  	if okChan {
    70  		go func(subscribersChan []chan Message) {
    71  			for i := 0; i < len(subscribersChan); i++ {
    72  				select {
    73  				case subscribersChan[i] <- message:
    74  				case <-time.After(time.Millisecond * 500):
    75  				}
    76  			}
    77  		}(subscribersChan)
    78  
    79  	}
    80  
    81  	if okCallback {
    82  		for i := 0; i < len(subscribersCallback); i++ {
    83  			go subscribersCallback[i](message)
    84  		}
    85  	}
    86  }
    87  
    88  func (i *inMemoryMQ) Subscribe(topic string, buffer int) <-chan Message {
    89  	ch := make(chan Message, buffer)
    90  	i.Lock()
    91  	i.topics[topic] = append(i.topics[topic], ch)
    92  	i.Unlock()
    93  	return ch
    94  }
    95  
    96  func (i *inMemoryMQ) SubscribeCallback(topic string, callbackFunc CallbackFunc) {
    97  	i.Lock()
    98  	i.callbacks[topic] = append(i.callbacks[topic], callbackFunc)
    99  	i.Unlock()
   100  }
   101  
   102  func (i *inMemoryMQ) Unsubscribe(topic string, sub <-chan Message) {
   103  	i.Lock()
   104  	defer i.Unlock()
   105  
   106  	subscribers, ok := i.topics[topic]
   107  	if !ok {
   108  		return
   109  	}
   110  
   111  	var newSubs []chan Message
   112  	for _, subscriber := range subscribers {
   113  		if subscriber == sub {
   114  			continue
   115  		}
   116  		newSubs = append(newSubs, subscriber)
   117  	}
   118  
   119  	i.topics[topic] = newSubs
   120  }
   121  
   122  func (i *inMemoryMQ) Aria2Notify(events []rpc.Event, status int) {
   123  	for _, event := range events {
   124  		i.Publish(event.Gid, Message{
   125  			TriggeredBy: event.Gid,
   126  			Event:       strconv.FormatInt(int64(status), 10),
   127  			Content:     events,
   128  		})
   129  	}
   130  }
   131  
   132  // OnDownloadStart 下载开始
   133  func (i *inMemoryMQ) OnDownloadStart(events []rpc.Event) {
   134  	i.Aria2Notify(events, common.Downloading)
   135  }
   136  
   137  // OnDownloadPause 下载暂停
   138  func (i *inMemoryMQ) OnDownloadPause(events []rpc.Event) {
   139  	i.Aria2Notify(events, common.Paused)
   140  }
   141  
   142  // OnDownloadStop 下载停止
   143  func (i *inMemoryMQ) OnDownloadStop(events []rpc.Event) {
   144  	i.Aria2Notify(events, common.Canceled)
   145  }
   146  
   147  // OnDownloadComplete 下载完成
   148  func (i *inMemoryMQ) OnDownloadComplete(events []rpc.Event) {
   149  	i.Aria2Notify(events, common.Complete)
   150  }
   151  
   152  // OnDownloadError 下载出错
   153  func (i *inMemoryMQ) OnDownloadError(events []rpc.Event) {
   154  	i.Aria2Notify(events, common.Error)
   155  }
   156  
   157  // OnBtDownloadComplete BT下载完成
   158  func (i *inMemoryMQ) OnBtDownloadComplete(events []rpc.Event) {
   159  	i.Aria2Notify(events, common.Complete)
   160  }