github.com/fumiama/NanoBot@v0.0.0-20231122134259-c22d8183efca/future.go (about)

     1  package nano
     2  
     3  // FutureEvent 是 ZeroBot 交互式的核心,用于异步获取指定事件
     4  type FutureEvent struct {
     5  	Type     string
     6  	Priority int
     7  	Rule     []Rule
     8  	Block    bool
     9  }
    10  
    11  // NewFutureEvent 创建一个FutureEvent, 并返回其指针
    12  func NewFutureEvent(Type string, Priority int, Block bool, rule ...Rule) *FutureEvent {
    13  	return &FutureEvent{
    14  		Type:     Type,
    15  		Priority: Priority,
    16  		Rule:     rule,
    17  		Block:    Block,
    18  	}
    19  }
    20  
    21  // FutureEvent 返回一个 FutureEvent 实例指针,用于获取满足 Rule 的 未来事件
    22  func (m *Matcher) FutureEvent(Type string, rule ...Rule) *FutureEvent {
    23  	return &FutureEvent{
    24  		Type:     Type,
    25  		Priority: m.priority,
    26  		Block:    m.Block,
    27  		Rule:     rule,
    28  	}
    29  }
    30  
    31  // Next 返回一个 chan 用于接收下一个指定事件
    32  //
    33  // 该 chan 必须接收,如需手动取消监听,请使用 Repeat 方法
    34  func (n *FutureEvent) Next() <-chan *Ctx {
    35  	ch := make(chan *Ctx, 1)
    36  	StoreTempMatcher(&Matcher{
    37  		Type:     n.Type,
    38  		Block:    n.Block,
    39  		priority: n.Priority,
    40  		Rules:    n.Rule,
    41  		Engine:   defaultEngine,
    42  		Process: func(ctx *Ctx) {
    43  			ch <- ctx
    44  			close(ch)
    45  		},
    46  	})
    47  	return ch
    48  }
    49  
    50  // Repeat 返回一个 chan 用于接收无穷个指定事件,和一个取消监听的函数
    51  //
    52  // 如果没有取消监听,将不断监听指定事件
    53  func (n *FutureEvent) Repeat() (recv <-chan *Ctx, cancel func()) {
    54  	ch, done := make(chan *Ctx, 1), make(chan struct{})
    55  	go func() {
    56  		defer close(ch)
    57  		in := make(chan *Ctx, 1)
    58  		matcher := StoreMatcher(&Matcher{
    59  			Type:     n.Type,
    60  			Block:    n.Block,
    61  			priority: n.Priority,
    62  			Rules:    n.Rule,
    63  			Engine:   defaultEngine,
    64  			Process: func(ctx *Ctx) {
    65  				in <- ctx
    66  			},
    67  		})
    68  		for {
    69  			select {
    70  			case e := <-in:
    71  				ch <- e
    72  			case <-done:
    73  				matcher.Delete()
    74  				close(in)
    75  				return
    76  			}
    77  		}
    78  	}()
    79  	return ch, func() {
    80  		close(done)
    81  	}
    82  }
    83  
    84  // Take 基于 Repeat 封装,返回一个 chan 接收指定数量的事件
    85  //
    86  // 该 chan 对象必须接收,否则将有 goroutine 泄漏,如需手动取消请使用 Repeat
    87  func (n *FutureEvent) Take(num int) <-chan *Ctx {
    88  	recv, cancel := n.Repeat()
    89  	ch := make(chan *Ctx, num)
    90  	go func() {
    91  		defer close(ch)
    92  		for i := 0; i < num; i++ {
    93  			ch <- <-recv
    94  		}
    95  		cancel()
    96  	}()
    97  	return ch
    98  }