github.com/kelleygo/clashcore@v1.0.2/common/observable/observable.go (about)

     1  package observable
     2  
     3  import (
     4  	"errors"
     5  	"sync"
     6  )
     7  
     8  type Observable[T any] struct {
     9  	iterable Iterable[T]
    10  	listener map[Subscription[T]]*Subscriber[T]
    11  	mux      sync.Mutex
    12  	done     bool
    13  }
    14  
    15  func (o *Observable[T]) process() {
    16  	for item := range o.iterable {
    17  		o.mux.Lock()
    18  		for _, sub := range o.listener {
    19  			sub.Emit(item)
    20  		}
    21  		o.mux.Unlock()
    22  	}
    23  	o.close()
    24  }
    25  
    26  func (o *Observable[T]) close() {
    27  	o.mux.Lock()
    28  	defer o.mux.Unlock()
    29  
    30  	o.done = true
    31  	for _, sub := range o.listener {
    32  		sub.Close()
    33  	}
    34  }
    35  
    36  func (o *Observable[T]) Subscribe() (Subscription[T], error) {
    37  	o.mux.Lock()
    38  	defer o.mux.Unlock()
    39  	if o.done {
    40  		return nil, errors.New("observable is closed")
    41  	}
    42  	subscriber := newSubscriber[T]()
    43  	o.listener[subscriber.Out()] = subscriber
    44  	return subscriber.Out(), nil
    45  }
    46  
    47  func (o *Observable[T]) UnSubscribe(sub Subscription[T]) {
    48  	o.mux.Lock()
    49  	defer o.mux.Unlock()
    50  	subscriber, exist := o.listener[sub]
    51  	if !exist {
    52  		return
    53  	}
    54  	delete(o.listener, sub)
    55  	subscriber.Close()
    56  }
    57  
    58  func NewObservable[T any](iter Iterable[T]) *Observable[T] {
    59  	observable := &Observable[T]{
    60  		iterable: iter,
    61  		listener: map[Subscription[T]]*Subscriber[T]{},
    62  	}
    63  	go observable.process()
    64  	return observable
    65  }