예제 #1
0
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
}
예제 #2
0
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
		}
	}
}
예제 #3
0
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)
		}
	}
}
예제 #4
0
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
	}
}
예제 #5
0
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()))()
		}
	}
}
예제 #6
0
파일: render.go 프로젝트: pressly/chi
// 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)
		}
	}
}
예제 #7
0
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
}
예제 #8
0
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
}
예제 #10
0
파일: client.go 프로젝트: vichetuc/gobox
// 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() }()
				}
			}
		}
	}()
}
예제 #11
0
// 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
		}
	}
}
예제 #12
0
파일: pipe.go 프로젝트: CaiGuaiNi/cellnet
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())
			}

		}

	}()

}
예제 #13
0
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
}
예제 #14
0
파일: ordered.go 프로젝트: qinguoan/vulcan
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
}
예제 #15
0
파일: channel.go 프로젝트: vuleetu/misc
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())
		}
	}
}
예제 #16
0
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())
}
예제 #17
0
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
}
예제 #18
0
파일: select.go 프로젝트: OneOfOne/netchan
// 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
}
예제 #19
0
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
}
예제 #20
0
파일: select.go 프로젝트: reusee/selector
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()))()
		}
	}
}
예제 #21
0
// 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
	}
}
예제 #23
0
파일: junction.go 프로젝트: toshaf/junction
// 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())
			}
		}
	}()
}
예제 #24
0
파일: select.go 프로젝트: kedebug/LispEx
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)
	}
}
예제 #25
0
/*
	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
}
예제 #26
0
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
}
예제 #27
0
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)
}
예제 #28
0
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
}
예제 #29
0
파일: chan.go 프로젝트: eurry/gotunnel2
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
}
예제 #30
0
// 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
}