github.com/igoogolx/clash@v1.19.8/common/observable/observable.go (about)

     1  package observable
     2  
     3  import (
     4  	"errors"
     5  	"sync"
     6  )
     7  
     8  type Observable struct {
     9  	iterable Iterable
    10  	listener map[Subscription]*Subscriber
    11  	mux      sync.Mutex
    12  	done     bool
    13  }
    14  
    15  func (o *Observable) 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) 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) Subscribe() (Subscription, 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()
    43  	o.listener[subscriber.Out()] = subscriber
    44  	return subscriber.Out(), nil
    45  }
    46  
    47  func (o *Observable) UnSubscribe(sub Subscription) {
    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(any Iterable) *Observable {
    59  	observable := &Observable{
    60  		iterable: any,
    61  		listener: map[Subscription]*Subscriber{},
    62  	}
    63  	go observable.process()
    64  	return observable
    65  }