github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/consense/dpoa/event.go (about)

     1  package dpoa
     2  
     3  
     4  import (
     5  	"errors"
     6  	"reflect"
     7  	"sync"
     8  )
     9  
    10  type Subscription interface {
    11  	Err() <-chan error
    12  	Unsubscribe()
    13  }
    14  
    15  var errBadChannel = errors.New("event: Subscribe argument does not have sendable channel type")
    16  
    17  type Feed struct {
    18  	once      sync.Once
    19  	sendLock  chan struct{}
    20  	removeSub chan interface{}
    21  	sendCases caseList
    22  
    23  	mu     sync.Mutex
    24  	inbox  caseList
    25  	etype  reflect.Type
    26  	closed bool
    27  }
    28  
    29  const firstSubSendCase = 1
    30  
    31  type feedTypeError struct {
    32  	got, want reflect.Type
    33  	op        string
    34  }
    35  
    36  func (e feedTypeError) Error() string {
    37  	return "event: wrong type in " + e.op + " got " + e.got.String() + ", want " + e.want.String()
    38  }
    39  
    40  func (f *Feed) init() {
    41  	f.removeSub = make(chan interface{})
    42  	f.sendLock = make(chan struct{}, 1)
    43  	f.sendLock <- struct{}{}
    44  	f.sendCases = caseList{{Chan: reflect.ValueOf(f.removeSub), Dir: reflect.SelectRecv}}
    45  }
    46  
    47  func (f *Feed) Subscribe(channel interface{}) Subscription {
    48  	f.once.Do(f.init)
    49  
    50  	chanval := reflect.ValueOf(channel)
    51  	chantyp := chanval.Type()
    52  	if chantyp.Kind() != reflect.Chan || chantyp.ChanDir()&reflect.SendDir == 0 {
    53  		panic(errBadChannel)
    54  	}
    55  	sub := &feedSub{feed: f, channel: chanval, err: make(chan error, 1)}
    56  
    57  	f.mu.Lock()
    58  	defer f.mu.Unlock()
    59  	if !f.typecheck(chantyp.Elem()) {
    60  		panic(feedTypeError{op: "Subscribe", got: chantyp, want: reflect.ChanOf(reflect.SendDir, f.etype)})
    61  	}
    62  
    63  	cas := reflect.SelectCase{Dir: reflect.SelectSend, Chan: chanval}
    64  	f.inbox = append(f.inbox, cas)
    65  	return sub
    66  }
    67  
    68  func (f *Feed) typecheck(typ reflect.Type) bool {
    69  	if f.etype == nil {
    70  		f.etype = typ
    71  		return true
    72  	}
    73  	return f.etype == typ
    74  }
    75  
    76  func (f *Feed) remove(sub *feedSub) {
    77  	ch := sub.channel.Interface()
    78  	f.mu.Lock()
    79  	index := f.inbox.find(ch)
    80  	if index != -1 {
    81  		f.inbox = f.inbox.delete(index)
    82  		f.mu.Unlock()
    83  		return
    84  	}
    85  	f.mu.Unlock()
    86  
    87  	select {
    88  	case f.removeSub <- ch:
    89  	case <-f.sendLock:
    90  		f.sendCases = f.sendCases.delete(f.sendCases.find(ch))
    91  		f.sendLock <- struct{}{}
    92  	}
    93  }
    94  
    95  func (f *Feed) Send(value interface{}) (nsent int) {
    96  	rvalue := reflect.ValueOf(value)
    97  
    98  	f.once.Do(f.init)
    99  	<-f.sendLock
   100  
   101  	f.mu.Lock()
   102  	f.sendCases = append(f.sendCases, f.inbox...)
   103  	f.inbox = nil
   104  
   105  	if !f.typecheck(rvalue.Type()) {
   106  		f.sendLock <- struct{}{}
   107  		panic(feedTypeError{op: "Send", got: rvalue.Type(), want: f.etype})
   108  	}
   109  	f.mu.Unlock()
   110  
   111  	for i := firstSubSendCase; i < len(f.sendCases); i++ {
   112  		f.sendCases[i].Send = rvalue
   113  	}
   114  
   115  	cases := f.sendCases
   116  	for {
   117  		for i := firstSubSendCase; i < len(cases); i++ {
   118  			if cases[i].Chan.TrySend(rvalue) {
   119  				nsent++
   120  				cases = cases.deactivate(i)
   121  				i--
   122  			}
   123  		}
   124  		if len(cases) == firstSubSendCase {
   125  			break
   126  		}
   127  		chosen, recv, _ := reflect.Select(cases)
   128  		if chosen == 0 {
   129  			index := f.sendCases.find(recv.Interface())
   130  			f.sendCases = f.sendCases.delete(index)
   131  			if index >= 0 && index < len(cases) {
   132  				cases = f.sendCases[:len(cases)-1]
   133  			}
   134  		} else {
   135  			cases = cases.deactivate(chosen)
   136  			nsent++
   137  		}
   138  	}
   139  
   140  	for i := firstSubSendCase; i < len(f.sendCases); i++ {
   141  		f.sendCases[i].Send = reflect.Value{}
   142  	}
   143  	f.sendLock <- struct{}{}
   144  	return nsent
   145  }
   146  
   147  type feedSub struct {
   148  	feed    *Feed
   149  	channel reflect.Value
   150  	errOnce sync.Once
   151  	err     chan error
   152  }
   153  
   154  func (sub *feedSub) Unsubscribe() {
   155  	sub.errOnce.Do(func() {
   156  		sub.feed.remove(sub)
   157  		close(sub.err)
   158  	})
   159  }
   160  
   161  func (sub *feedSub) Err() <-chan error {
   162  	return sub.err
   163  }
   164  
   165  type caseList []reflect.SelectCase
   166  
   167  func (cs caseList) find(channel interface{}) int {
   168  	for i, cas := range cs {
   169  		if cas.Chan.Interface() == channel {
   170  			return i
   171  		}
   172  	}
   173  	return -1
   174  }
   175  
   176  func (cs caseList) delete(index int) caseList {
   177  	return append(cs[:index], cs[index+1:]...)
   178  }
   179  
   180  func (cs caseList) deactivate(index int) caseList {
   181  	last := len(cs) - 1
   182  	cs[index], cs[last] = cs[last], cs[index]
   183  	return cs[:last]
   184  }