func (self *Selector) Select() (interface{}, error) { nCases := len(self.cases) sel: i := 1 for i < nCases && self.buffers[i-1] == nil { i++ } if i == nCases { // no buffered value n, v, ok := reflect.Select(self.cases[1:i]) // no default case if !ok { return nil, ChanClosedErr{Chan: self.cases[n+1].Chan} } self.buffers[n] = &box{v.Interface()} goto sel } else { // has buffered value n, v, ok := reflect.Select(self.cases[:i]) // default case at index 0 if !ok && n > 0 { return nil, ChanClosedErr{Chan: self.cases[n].Chan} } if n > 0 { // higher priority chan received self.buffers[n-1] = &box{v.Interface()} goto sel } // default for i, buf := range self.buffers { if buf != nil { self.buffers[i] = nil return buf.v, nil } } } panic("impossible") return nil, nil }
func (d *Dispatcher) pullSubtask(accepts []string) (*dispatcher.Subtask, error) { tc := time.After(PullTimeout) cases := make([]reflect.SelectCase, len(accepts)+1) var timeoutIdx = len(accepts) for i, v := range accepts { q := d.ensureQueue(v) cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(q)} } cases[timeoutIdx] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(tc)} for { chosen, value, _ := reflect.Select(cases) if chosen == timeoutIdx { return nil, ErrTimeout } subtask := value.Interface().(*dispatcher.Subtask) d.mu.RLock() _, ok := d.result[subtask.ID] d.mu.RUnlock() if ok { return subtask, nil } } }
func (r *Runner) Start() { err := r.handler.Perform() if err != nil { log.Print(err) } event_cases := make([]reflect.SelectCase, len(r.watchers)) for i, watcher := range r.watchers { localEventChan := make(chan *etcd.Response) event_cases[i] = reflect.SelectCase{ Dir: reflect.SelectRecv, Chan: reflect.ValueOf(localEventChan), } go watcher.Start(localEventChan) } for { _, _, ok := reflect.Select(event_cases) log.Printf("Received a new event") if !ok { log.Printf("Spotted a chan close, returning") return } err := r.handler.Perform() if err != nil { log.Print(err) } } }
func (r *Runner) Start() { consumerChan := make(chan bool, r.bufferSize) r.handler.Run(consumerChan) // Init the consumer consumerChan <- true eventCases := make([]reflect.SelectCase, len(r.watchers)) for i, watcher := range r.watchers { eventCases[i] = reflect.SelectCase{ Dir: reflect.SelectRecv, Chan: reflect.ValueOf( watcher.Start(), ), } } for { chosen, _, ok := reflect.Select(eventCases) log.Printf("Received a new event") if !ok { log.Printf( "Spotted a chan close at %d, returning\n", chosen, ) close(consumerChan) return } consumerChan <- true } }
func (s *Selector) Select() { for i := 0; i < len(s.cases); i++ { if s.predict[i] != nil { if !s.predict[i]() { s.selecting[i] = emptyCase } else { s.selecting[i] = s.cases[i] } } if s.toSend[i] != nil { ret := s.toSend[i].Call(nil) s.selecting[i].Send = ret[0] } } n, recv, ok := reflect.Select(s.selecting) if s.selecting[n].Dir == reflect.SelectRecv { if ok { if s.cbs[n] != nil { switch cb := s.cbs[n].(type) { case func(): cb() default: reflect.ValueOf(cb).Call([]reflect.Value{ recv, }) } } } } else { if s.cbs[n] != nil { (s.cbs[n].(func()))() } } }
// channelIntoSlice buffers channel data into a slice. func channelIntoSlice(w http.ResponseWriter, r *http.Request, from interface{}) interface{} { ctx := r.Context() var to []interface{} for { switch chosen, recv, ok := reflect.Select([]reflect.SelectCase{ {Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ctx.Done())}, {Dir: reflect.SelectRecv, Chan: reflect.ValueOf(from)}, }); chosen { case 0: // equivalent to: case <-ctx.Done() http.Error(w, "Server Timeout", 504) return nil default: // equivalent to: case v, ok := <-stream if !ok { return to } v := recv.Interface() // Present each channel item. if presenter, ok := r.Context().Value(presenterCtxKey).(Presenter); ok { r, v = presenter.Present(r, v) } to = append(to, v) } } }
func (n *N) collect(ch Chans) <-chan []EventInfo { done := make(chan []EventInfo) go func() { cases := make([]reflect.SelectCase, len(ch)) unique := make(map[<-chan EventInfo]EventInfo, len(ch)) for i := range ch { cases[i].Chan = reflect.ValueOf(ch[i]) cases[i].Dir = reflect.SelectRecv } for i := len(cases); i != 0; i = len(cases) { j, v, ok := reflect.Select(cases) if !ok { n.t.Fatal("unexpected chan close") } ch := cases[j].Chan.Interface().(chan EventInfo) got := v.Interface().(EventInfo) if ei, ok := unique[ch]; ok { n.t.Fatalf("duplicated event %v (previous=%v) received on collect", got, ei) } unique[ch] = got cases[j], cases = cases[i-1], cases[:i-1] } collected := make([]EventInfo, 0, len(ch)) for _, ch := range unique { collected = append(collected, ch) } done <- collected }() return done }
func (c Chans) Drain() (ei []EventInfo) { n := len(c) stop := make(chan struct{}) eich := make(chan EventInfo, n*buffer) go func() { defer close(eich) cases := make([]reflect.SelectCase, n+1) for i := range c { cases[i].Chan = reflect.ValueOf(c[i]) cases[i].Dir = reflect.SelectRecv } cases[n].Chan = reflect.ValueOf(stop) cases[n].Dir = reflect.SelectRecv for { i, v, ok := reflect.Select(cases) if i == n { return } if !ok { panic("(Chans).Drain(): unexpected chan close") } eich <- v.Interface().(EventInfo) } }() <-time.After(50 * time.Duration(n) * time.Millisecond) close(stop) for e := range eich { ei = append(ei, e) } return }
func receive(inputs []chan int) <-chan *Output { //START OMIT cases := make([]reflect.SelectCase, len(inputs)) output := make(chan *Output) for i, input := range inputs { cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(input)} } go func() { defer close(output) for { index, recv, ok := reflect.Select(cases) if !ok { cases[index] = cases[len(cases)-1] cases = cases[0 : len(cases)-1] if len(cases) == 0 { break } continue } output <- &Output{Index: index, Payload: int(recv.Int())} } }() //END OMIT return output }
// fix was to add a go func to write to out. I don't love this solution becuase it makes order // of stuff coming out of the out channel non-deterministic, so any other ideas are invited. func arbitraryFanIn(newChannels <-chan chan interface{}, out chan<- interface{}, removeOnEvent bool) { go func() { var ch <-chan interface{} chans := make([]reflect.SelectCase, 0) timeout := time.Tick(10 * time.Millisecond) chans = append(chans, reflect.SelectCase{ Dir: reflect.SelectRecv, Chan: reflect.ValueOf(timeout), }) for { select { case ch = <-newChannels: chans = append(chans, reflect.SelectCase{ Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch), }) default: chosen, value, ok := reflect.Select(chans) if chosen == 0 { continue } if removeOnEvent || !ok { lastIndex := len(chans) - 1 chans[chosen] = chans[lastIndex] chans = chans[:lastIndex] } if ok { go func() { out <- value.Interface() }() } } } }() }
// WaitForNetworkConnectivity uses a NetworkConnectivityChecker to // periodically check for network connectivity. It returns true if // no NetworkConnectivityChecker is provided (waiting is disabled) // or when NetworkConnectivityChecker.HasNetworkConnectivity() // indicates connectivity. It waits and polls the checker once a second. // If any stop is broadcast, false is returned immediately. func WaitForNetworkConnectivity( connectivityChecker NetworkConnectivityChecker, stopBroadcasts ...<-chan struct{}) bool { if connectivityChecker == nil || 1 == connectivityChecker.HasNetworkConnectivity() { return true } NoticeInfo("waiting for network connectivity") ticker := time.NewTicker(1 * time.Second) for { if 1 == connectivityChecker.HasNetworkConnectivity() { return true } selectCases := make([]reflect.SelectCase, 1+len(stopBroadcasts)) selectCases[0] = reflect.SelectCase{ Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ticker.C)} for i, stopBroadcast := range stopBroadcasts { selectCases[i+1] = reflect.SelectCase{ Dir: reflect.SelectRecv, Chan: reflect.ValueOf(stopBroadcast)} } chosen, _, ok := reflect.Select(selectCases) if chosen == 0 && ok { // Ticker case, so check again } else { // Stop case return false } } }
func (self *evPipe) Start() { // 开始后, 不能修改数组 self.arrayLock = true go func() { cases := make([]reflect.SelectCase, len(self.qarray)) // 按照队列(peer)数量开始做case for i, q := range self.qarray { cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(q.queue)} } for { if index, value, ok := reflect.Select(cases); ok { self.qarray[index].CallData(value.Interface()) } } }() }
func (matcher *BeClosedMatcher) Match(actual interface{}) (success bool, err error) { if !isChan(actual) { return false, fmt.Errorf("BeClosed matcher expects a channel. Got:\n%s", format.Object(actual, 1)) } channelType := reflect.TypeOf(actual) channelValue := reflect.ValueOf(actual) if channelType.ChanDir() == reflect.SendDir { return false, fmt.Errorf("BeClosed matcher cannot determine if a send-only channel is closed or open. Got:\n%s", format.Object(actual, 1)) } winnerIndex, _, open := reflect.Select([]reflect.SelectCase{ reflect.SelectCase{Dir: reflect.SelectRecv, Chan: channelValue}, reflect.SelectCase{Dir: reflect.SelectDefault}, }) var closed bool if winnerIndex == 0 { closed = !open } else if winnerIndex == 1 { closed = false } return closed, nil }
func (g *orderedGroup) waitForSignal(signals <-chan os.Signal, errTrace ErrorTrace) (os.Signal, ErrorTrace) { cases := make([]reflect.SelectCase, 0, len(g.pool)+1) for i := 0; i < len(g.pool); i++ { cases = append(cases, reflect.SelectCase{ Dir: reflect.SelectRecv, Chan: reflect.ValueOf(g.pool[g.members[i].Name].Wait()), }) } cases = append(cases, reflect.SelectCase{ Dir: reflect.SelectRecv, Chan: reflect.ValueOf(signals), }) chosen, recv, _ := reflect.Select(cases) if chosen == len(cases)-1 { return recv.Interface().(os.Signal), errTrace } var err error if !recv.IsNil() { err = recv.Interface().(error) } errTrace = append(errTrace, ExitEvent{ Member: g.members[chosen], Err: err, }) return g.terminationSignal, errTrace }
func loop(rc reflect.Value, wc reflect.Value) { readCase := reflect.SelectCase{} readCase.Dir = reflect.SelectRecv readCase.Chan = wc writeCase := reflect.SelectCase{} writeCase.Dir = reflect.SelectSend writeCase.Chan = rc cases := []reflect.SelectCase{readCase, writeCase} l := list.New() for { tc := cases[:1] if l.Len() > 0 { writeCase.Send = reflect.ValueOf(l.Front().Value) cases[1] = writeCase tc = cases[:2] } idx, v, ok := reflect.Select(tc) if idx == 0 { if ok { l.PushBack(v.Interface()) } else { //channel closed log.Println("Read channel closed") break } } else if idx == 1 { l.Remove(l.Front()) } } }
func benchReflectSelect(useDefault bool) timing { c := make(chan int, 0) caseCnt := 4 if useDefault { caseCnt = 5 } cases := make([]reflect.SelectCase, caseCnt) cases[0] = reflect.SelectCase{Dir: reflect.SelectSend, Chan: reflect.ValueOf(c), Send: reflect.ValueOf(0)} cases[1] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(c)} cases[2] = cases[0] cases[3] = cases[1] if useDefault { cases[4] = reflect.SelectCase{Dir: reflect.SelectDefault} } go func() { for { c <- 0 <-c } }() start := time.Now() for i := 0; i <= queueLen; i++ { reflect.Select(cases) } elapsed := time.Since(start) return timing(elapsed.Seconds()) }
func redirectChannelsToWithTimeout(inputChannels interface{}, outputChannel interface{}, timeout time.Duration) (chan bool, <-chan time.Time) { input := reflect.ValueOf(inputChannels) var timeoutInputChannel <-chan time.Time if timeout.Seconds() == 0 { timeoutInputChannel = nil } else { timeoutInputChannel = time.After(timeout) } output := reflect.ValueOf(outputChannel) timeoutOutputChannel := make(chan time.Time) killChannel := make(chan bool) if input.Kind() != reflect.Array && input.Kind() != reflect.Slice { panic("Incorrect input channels type") } if output.Kind() != reflect.Chan { panic("Incorrect output channel type") } cases := make([]reflect.SelectCase, input.Len()) for i := 0; i < input.Len(); i++ { if input.Index(i).Kind() == reflect.Ptr { cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(input.Index(i).Elem().Interface())} } else { cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(input.Index(i).Interface())} } } cases = append(cases, reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(killChannel)}) if timeoutInputChannel != nil { cases = append(cases, reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(timeoutInputChannel)}) } go func() { for { remaining := len(cases) for remaining > 0 { chosen, value, ok := reflect.Select(cases) if !ok { // The chosen channel has been closed, so zero out the channel to disable the case cases[chosen].Chan = reflect.ValueOf(nil) remaining -= 1 continue } if cases[chosen].Chan.Interface() == killChannel { return } if cases[chosen].Chan.Interface() == timeoutInputChannel { timeoutOutputChannel <- value.Interface().(time.Time) } output.Send(value) } } }() return killChannel, timeoutOutputChannel }
// SelectRecv loops on multiple receivers until it gets a value, // it blocks until a value is returned or all channels are closed. // this function doesn't panic. func SelectRecv(recvs []Receiver) (r Receiver, val interface{}) { defer func() { if recover() != nil { r = nil val = nil } }() cases := make([]reflect.SelectCase, len(recvs)) for i, rch := range recvs { cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv} switch rch := rch.(type) { case *Channel: cases[i].Chan = reflect.ValueOf(rch.r) case LocalReceiver: cases[i].Chan = reflect.ValueOf((<-chan interface{})(rch)) default: panic("SelectRecv only supports Channel and/or LocalReceiver") } } i, v, ok := reflect.Select(cases) if ok { r = recvs[i] val = v.Interface() if val, ok := val.(*pkt); ok { return r, val.Value } return } return }
func (cp *ConsumerPool) run() chan []common.MapStr { conn, err := amqp.Dial(cp.ServerURI) utils.FailOnError(err, "Failed to connect to RabbitMQ") defer conn.Close() ch, err := conn.Channel() utils.FailOnError(err, "Failed to open a channel") defer conn.Close() events := make(chan []common.MapStr) selCases := make([]reflect.SelectCase, len(cp.Consumers)) for i, c := range cp.Consumers { consumerChan := c.Run(ch) selCases[i].Dir = reflect.SelectRecv selCases[i].Chan = reflect.ValueOf(consumerChan) } go func() { for { _, recv, recvOK := reflect.Select(selCases) if recvOK { events <- recv.Interface().([]common.MapStr) } } }() return events }
func (s *Selector) Select() { for i, send := range s.toSend { if send != nil { s.selecting[i].Send = reflect.ValueOf(send()) } } n, recv, ok := reflect.Select(s.selecting) if s.selecting[n].Dir == reflect.SelectRecv { if ok { if s.cbs[n] != nil { switch cb := s.cbs[n].(type) { case func(): cb() case func(interface{}): cb(recv.Interface()) default: panic("unknown callback") } } } } else { if s.cbs[n] != nil { (s.cbs[n].(func()))() } } }
// choose returns the chosen event or nil if no event is ready. // wait is true if the choose should block for an available event. // If there are no regiestered then choose always returns immediately with nil. func (w *EventSet) choose(wait bool) *Event { // Configure the default case to block or not depending on wait. if wait { w.cases[0].Dir = reflect.SelectRecv } else { w.cases[0].Dir = reflect.SelectDefault } // Loop around until either: // 1.) An event is chosen, // 2.) All events have been unregistered, // 3.) The default case is selected (if !wait). for len(w.cases) > 1 { chosen, _, recvOK := reflect.Select(w.cases) // If there are no signalled events and we aren't blocking, then return immediately. if chosen == 0 { return nil } if recvOK { return w.events[chosen] } // The chosen event needs to be removed. w.remove(chosen) } // No events are registered so return immediately with nil. return nil }
func (matcher *BeClosedMatcher) Match(actual interface{}) (success bool, message string, err error) { if !isChan(actual) { return false, "", fmt.Errorf("BeClosed matcher expects a channel. Got: %s", formatObject(actual)) } channelType := reflect.TypeOf(actual) channelValue := reflect.ValueOf(actual) var closed bool if channelType.ChanDir() == reflect.SendDir { return false, "", fmt.Errorf("BeClosed matcher cannot determine if a send-only channel is closed or open. Got: %s", formatObject(actual)) } else { winnerIndex, _, open := reflect.Select([]reflect.SelectCase{ reflect.SelectCase{Dir: reflect.SelectRecv, Chan: channelValue}, reflect.SelectCase{Dir: reflect.SelectDefault}, }) if winnerIndex == 0 { closed = !open } else if winnerIndex == 1 { closed = false } } if closed { return true, formatMessage(actual, "to be open"), nil } else { return false, formatMessage(actual, "to be closed"), nil } }
// Associates the value pointed to by output // with all the Sources specified and creates // a new output channel in the location pointed // to by Output - this location is overwritten by // this call so doesn't need to be // (read shouldn't be) initialised. // A Goroutine is then started that uses the sources // to keep the model(s) updated and publishes new // versions through the output channel func New(output Output, sources []Source) { if err := Validate(output, sources); err != nil { panic(err) } channel := makeOutputChan(output) go func() { cases := buildCases(sources) for { choice, value, ok := reflect.Select(cases) if !ok { panic("Input closed") } source := sources[choice] update := reflect.ValueOf(source.Update) target, ok := source.getTarget(value) if ok { update.Call([]reflect.Value{target, value}) channel.Send(target.Elem()) } } }() }
func (self *Select) Eval(env *scope.Scope) Value { cases := make([]reflect.SelectCase, len(self.Clauses)) for i, clause := range self.Clauses { // parser guarantee the test case is a Call or Name // Call.Callee is either `<-chan' or `chan<-' // Name.Identifier must be `default' var test *Call var name *Name var args []Value var channel *Channel switch clause[0].(type) { case *Call: test, _ = clause[0].(*Call) name, _ = test.Callee.(*Name) args = EvalList(test.Args, env) _, ok := args[0].(*Channel) if ok { channel, _ = args[0].(*Channel) } else { panic(fmt.Sprintf("incorrect argument type for `%s', expected: channel, given: %s", name, args[0])) } case *Name: name, _ = clause[0].(*Name) } if name.Identifier == constants.CHAN_SEND { // send to chan `chan<-' cases[i].Send = reflect.ValueOf(args[1]) cases[i].Dir = reflect.SelectSend cases[i].Chan = reflect.ValueOf(channel.Value) } else if name.Identifier == constants.CHAN_RECV { // receive from chan `<-chan' cases[i].Dir = reflect.SelectRecv cases[i].Chan = reflect.ValueOf(channel.Value) } else if name.Identifier == constants.DEFAULT { // default cases[i].Dir = reflect.SelectDefault } } chosen, recv, ok := reflect.Select(cases) exprs := self.Clauses[chosen] if len(exprs) == 1 { if ok { return recv.Interface().(Value) } else { return nil } } else { exprs = exprs[1:] for i := 0; i < len(exprs)-1; i++ { exprs[i].Eval(env) } return exprs[len(exprs)-1].Eval(env) } }
/* Stream manufactures a `pkg/stream.Stream`, starts a worker pumping events out of decoding, and returns that. The 'outputCh' parameter must be a sendable channel. The "zero"-values of channel's content type will be created and used in the deserialization, then sent. The return values from `httpclient.RawReq` are probably a useful starting point for the 'res' parameter. Closing the returned `stream.Stream` shuts down the worker. */ func Stream(res *http.Response, outputCh interface{}) stream.Stream { stream := stream.New() var chanValue reflect.Value if v, ok := outputCh.(reflect.Value); ok { chanValue = v } else { chanValue = reflect.ValueOf(outputCh) } stopChanValue := reflect.ValueOf(stream.StopCh) msgType := chanValue.Type().Elem().Elem() go func() { done := make(chan struct{}) defer func() { chanValue.Close() close(done) }() go func() { select { case <-stream.StopCh: case <-done: } res.Body.Close() }() r := bufio.NewReader(res.Body) dec := sse.NewDecoder(r) for { msg := reflect.New(msgType) if err := dec.Decode(msg.Interface()); err != nil { if err != io.EOF { stream.Error = err } break } chosen, _, _ := reflect.Select([]reflect.SelectCase{ { Dir: reflect.SelectRecv, Chan: stopChanValue, }, { Dir: reflect.SelectSend, Chan: chanValue, Send: msg, }, }) switch chosen { case 0: return default: } } }() return stream }
func (g *parallelGroup) stop(signal os.Signal, errTrace ErrorTrace) ErrorTrace { errOccurred := false exited := map[string]struct{}{} if len(errTrace) > 0 { for _, exitEvent := range errTrace { exited[exitEvent.Member.Name] = struct{}{} if exitEvent.Err != nil { errOccurred = true } } } cases := make([]reflect.SelectCase, 0, len(g.members)) liveMembers := make([]Member, 0, len(g.members)) for _, member := range g.members { if _, found := exited[member.Name]; found { continue } if process, ok := g.pool[member.Name]; ok { process.Signal(signal) cases = append(cases, reflect.SelectCase{ Dir: reflect.SelectRecv, Chan: reflect.ValueOf(process.Wait()), }) liveMembers = append(liveMembers, member) } } numExited := 0 for { chosen, recv, _ := reflect.Select(cases) cases[chosen].Chan = reflect.Zero(cases[chosen].Chan.Type()) recvError, _ := recv.Interface().(error) errTrace = append(errTrace, ExitEvent{ Member: liveMembers[chosen], Err: recvError, }) if recvError != nil { errOccurred = true } numExited++ if numExited == len(cases) { break } } if errOccurred { return errTrace } return nil }
func main() { cases := make([]reflect.SelectCase, 1) ch1 := make(chan int) cases[0].Dir = reflect.SelectRecv cases[0].Chan = reflect.ValueOf(ch1) go myroutine(ch1) chosen, recv, recvok := reflect.Select(cases) fmt.Println(chosen, recv, recvok) }
func (h *DefaultHandler) Blpop(key string, keys ...string) (data [][]byte, err error) { keys = append([]string{key}, keys...) if h.Database == nil { h.Database = NewDatabase(nil) } if len(keys) == 0 { return nil, ErrParseTimeout } timeout, err := strconv.Atoi(keys[len(keys)-1]) if err != nil { return nil, ErrParseTimeout } keys = keys[:len(keys)-1] var timeoutChan <-chan time.Time if timeout > 0 { timeoutChan = time.After(time.Duration(timeout) * time.Second) } else { timeoutChan = make(chan time.Time) } finishedChan := make(chan struct{}) go func() { defer close(finishedChan) selectCases := []reflect.SelectCase{} for _, k := range keys { key := string(k) if _, exists := h.brstack[key]; !exists { h.brstack[key] = NewStack(k) } selectCases = append(selectCases, reflect.SelectCase{ Dir: reflect.SelectRecv, Chan: reflect.ValueOf(h.brstack[key].Chan), }) } _, recv, _ := reflect.Select(selectCases) s, ok := recv.Interface().(*Stack) if !ok { err = fmt.Errorf("Impossible to retrieve data. Wrong type.") return } data = [][]byte{[]byte(s.Key), s.PopFront()} }() select { case <-finishedChan: return data, err case <-timeoutChan: return nil, nil } return nil, nil }
func MakeChan(in interface{}) (ret interface{}) { outValue := reflect.MakeChan(reflect.TypeOf(in), 0) ret = outValue.Convert(reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(in).Elem())).Interface() inValue := reflect.ValueOf(in) if inValue.Kind() != reflect.Chan || outValue.Kind() != reflect.Chan { log.Fatal("MakeChan: argument is not a chan") } go func() { defer outValue.Close() buffer := list.New() for { if buffer.Len() > 0 { chosen, v, ok := reflect.Select([]reflect.SelectCase{reflect.SelectCase{ Dir: reflect.SelectSend, Chan: outValue, Send: buffer.Front().Value.(reflect.Value), }, reflect.SelectCase{ Dir: reflect.SelectRecv, Chan: inValue, }}) if chosen == 0 { // out buffer.Remove(buffer.Front()) } else { if !ok { return } buffer.PushBack(v) } } else { _, v, ok := reflect.Select([]reflect.SelectCase{reflect.SelectCase{ Dir: reflect.SelectRecv, Chan: inValue, }}) if !ok { return } buffer.PushBack(v) } } }() return }
// createSubscription will register a new subscription and waits for raised events. When an event is raised it will: // 1. test if the event is raised matches the criteria the user has (optionally) specified // 2. create a notification of the event and send it the client when it matches the criteria // It will unsubscribe the subscription when the socket is closed or the subscription is unsubscribed by the user. func (s *Server) createSubscription(c ServerCodec, req *serverRequest) (string, error) { args := []reflect.Value{req.callb.rcvr} if len(req.args) > 0 { args = append(args, req.args...) } subid, err := newSubscriptionId() if err != nil { return "", err } reply := req.callb.method.Func.Call(args) if reply[1].IsNil() { // no error if subscription, ok := reply[0].Interface().(Subscription); ok { s.muSubcriptions.Lock() s.subscriptions[subid] = subscription s.muSubcriptions.Unlock() go func() { cases := []reflect.SelectCase{ reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(subscription.Chan())}, // new event reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(c.Closed())}, // connection closed } for { idx, notification, recvOk := reflect.Select(cases) switch idx { case 0: // new event, or channel closed if recvOk { // send notification if event, ok := notification.Interface().(*event.Event); ok { if subscription.match == nil || subscription.match(event.Data) { sendNotification(c, subid, subscription.format(event.Data)) } } } else { // user send an eth_unsubscribe request return } case 1: // connection closed s.unsubscribe(subid) return } } }() } else { // unable to create subscription s.muSubcriptions.Lock() delete(s.subscriptions, subid) s.muSubcriptions.Unlock() } } else { return "", fmt.Errorf("Unable to create subscription") } return subid, nil }