예제 #1
0
파일: chanof.go 프로젝트: upccup/cuplearn
func main() {
	var i int
	var recvDir reflect.ChanDir = reflect.RecvDir
	var chanOf reflect.Type = reflect.ChanOf(recvDir, reflect.TypeOf(i))
	fmt.Println(chanOf.Kind())    // chan
	fmt.Println(chanOf.ChanDir()) // <-chan
	fmt.Println(chanOf.String())  // <-chan int

	var i1 int
	var recvDir1 reflect.ChanDir = reflect.SendDir
	var chanOf1 reflect.Type = reflect.ChanOf(recvDir1, reflect.TypeOf(i1))
	fmt.Println(chanOf1.Kind(), chanOf1.ChanDir(), chanOf1.String())
	// chan chan<- chan<- int

	var i2 int
	var recvDir2 reflect.ChanDir = reflect.BothDir
	var chanOf2 reflect.Type = reflect.ChanOf(recvDir2, reflect.TypeOf(i2))
	fmt.Println(chanOf2.Kind(), chanOf2.ChanDir(), chanOf2.String())
	// chan chan chan int

	var i3 string
	var recvDir3 reflect.ChanDir = reflect.BothDir
	var chanOf3 reflect.Type = reflect.ChanOf(recvDir3, reflect.TypeOf(i3))
	fmt.Println(chanOf3.Kind(), chanOf3.ChanDir(), chanOf3.String())
	// chan chan chan string
}
예제 #2
0
func Test_InjectorInvoke(t *testing.T) {
	injector := inject.New()
	expect(t, injector == nil, false)

	dep := "some dependency"
	injector.Map(dep)
	dep2 := "another dep"
	injector.MapTo(dep2, (*SpecialString)(nil))
	dep3 := make(chan *SpecialString)
	dep4 := make(chan *SpecialString)
	typRecv := reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(dep3).Elem())
	typSend := reflect.ChanOf(reflect.SendDir, reflect.TypeOf(dep4).Elem())
	injector.Set(typRecv, reflect.ValueOf(dep3))
	injector.Set(typSend, reflect.ValueOf(dep4))

	_, err := injector.Invoke(func(d1 string, d2 SpecialString, d3 <-chan *SpecialString, d4 chan<- *SpecialString) {
		expect(t, d1, dep)
		expect(t, d2, dep2)
		expect(t, reflect.TypeOf(d3).Elem(), reflect.TypeOf(dep3).Elem())
		expect(t, reflect.TypeOf(d4).Elem(), reflect.TypeOf(dep4).Elem())
		expect(t, reflect.TypeOf(d3).ChanDir(), reflect.RecvDir)
		expect(t, reflect.TypeOf(d4).ChanDir(), reflect.SendDir)
	})

	expect(t, err, nil)
}
예제 #3
0
// Helper method to map default channels in the context
func (c *Connection) mapDefaultChannels(context martini.Context) {
	// Map the Error Channel to a <-chan error for the next Handler(s)
	context.Set(reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(c.Error).Elem()), reflect.ValueOf(c.Error))

	// Map the Disconnect Channel to a chan<- bool for the next Handler(s)
	context.Set(reflect.ChanOf(reflect.SendDir, reflect.TypeOf(c.Disconnect).Elem()), reflect.ValueOf(c.Disconnect))

	// Map the Done Channel to a <-chan bool for the next Handler(s)
	context.Set(reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(c.Done).Elem()), reflect.ValueOf(c.Done))
}
예제 #4
0
파일: channel.go 프로젝트: vuleetu/misc
func NewChan(typ interface{}) (interface{}, interface{}) {
	rc := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, reflect.TypeOf(typ)), 0)
	wc := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, reflect.TypeOf(typ)), 0)

	go loop(rc, wc)

	vrc := rc.Convert(reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(typ)))

	vwc := wc.Convert(reflect.ChanOf(reflect.SendDir, reflect.TypeOf(typ)))

	return vrc.Interface(), vwc.Interface()
}
예제 #5
0
파일: inject_test.go 프로젝트: pulcy/robin
func Test_Injector_Invoke(t *testing.T) {
	Convey("Invokes function", t, func() {
		injector := inject.New()
		So(injector, ShouldNotBeNil)

		dep := "some dependency"
		injector.Map(dep)
		dep2 := "another dep"
		injector.MapTo(dep2, (*SpecialString)(nil))
		dep3 := make(chan *SpecialString)
		dep4 := make(chan *SpecialString)
		typRecv := reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(dep3).Elem())
		typSend := reflect.ChanOf(reflect.SendDir, reflect.TypeOf(dep4).Elem())
		injector.Set(typRecv, reflect.ValueOf(dep3))
		injector.Set(typSend, reflect.ValueOf(dep4))

		_, err := injector.Invoke(func(d1 string, d2 SpecialString, d3 <-chan *SpecialString, d4 chan<- *SpecialString) {
			So(d1, ShouldEqual, dep)
			So(d2, ShouldEqual, dep2)
			So(reflect.TypeOf(d3).Elem(), ShouldEqual, reflect.TypeOf(dep3).Elem())
			So(reflect.TypeOf(d4).Elem(), ShouldEqual, reflect.TypeOf(dep4).Elem())
			So(reflect.TypeOf(d3).ChanDir(), ShouldEqual, reflect.RecvDir)
			So(reflect.TypeOf(d4).ChanDir(), ShouldEqual, reflect.SendDir)
		})
		So(err, ShouldBeNil)

		_, err = injector.Invoke(myFastInvoker(func(string) {}))
		So(err, ShouldBeNil)
	})

	Convey("Invokes function with return value", t, func() {
		injector := inject.New()
		So(injector, ShouldNotBeNil)

		dep := "some dependency"
		injector.Map(dep)
		dep2 := "another dep"
		injector.MapTo(dep2, (*SpecialString)(nil))

		result, err := injector.Invoke(func(d1 string, d2 SpecialString) string {
			So(d1, ShouldEqual, dep)
			So(d2, ShouldEqual, dep2)
			return "Hello world"
		})

		So(result[0].String(), ShouldEqual, "Hello world")
		So(err, ShouldBeNil)
	})
}
예제 #6
0
func TestGetChannel(t *testing.T) {

	b := &Broadcaster{RoutineMaxClients: 10}

	var uids []string
	var tids []int

	for i := 0; i < 10; i++ {

		tuid, ttid := b.AddClient()

		uids = append(uids, tuid)
		tids = append(tids, ttid)
	}

	ch, err := b.GetChannel(uids[1], tids[1])

	if err != nil {

		t.Errorf("Test encountered the following error: %v", err)

	}
	if reflect.TypeOf(ch) != reflect.ChanOf(reflect.BothDir, reflect.TypeOf("")) {

		t.Errorf("Test expected to retrieve channel, but received %v", reflect.TypeOf(ch))
	}

	ch, err = b.GetChannel("asd", 3)
	if err == nil {

		t.Error("An error was expected, but not received")

	}
}
예제 #7
0
func chanOfUnknown() {
	// Unknown channel direction: assume all three.
	// MakeChan only works on the bi-di channel type.
	t := reflect.ChanOf(unknownDir, reflect.TypeOf(&a))
	print(reflect.Zero(t).Interface())        // @types <-chan *int | chan<- *int | chan *int
	print(reflect.MakeChan(t, 0).Interface()) // @types chan *int
}
예제 #8
0
func chanOfSend() {
	// MakeChan(chan<-) is a no-op.
	t := reflect.ChanOf(reflect.SendDir, reflect.TypeOf(&a))
	print(reflect.Zero(t).Interface())                      // @types <-chan *int | chan<- *int | chan *int
	print(reflect.MakeChan(t, 0).Interface().(chan<- *int)) // @pointsto
	print(reflect.MakeChan(t, 0).Interface().(chan *int))   // @pointsto <alloc in reflect.MakeChan>
}
예제 #9
0
파일: chanreflect.go 프로젝트: 2722/lantern
func chanOfRecv() {
	// MakeChan(<-chan) is a no-op.
	t := reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(&a))
	print(reflect.Zero(t).Interface())                      // @types <-chan *int
	print(reflect.MakeChan(t, 0).Interface().(<-chan *int)) // @pointsto
	print(reflect.MakeChan(t, 0).Interface().(chan *int))   // @pointsto
}
예제 #10
0
파일: local_db.go 프로젝트: hahan/cockroach
// executeCmd runs Store.ExecuteCmd in a goroutine. A channel with
// element type equal to the reply type is created and returned
// immediately. The reply is sent to the channel once the cmd has been
// executed by the store. The store is looked up from the store map
// if specified by header.Replica; otherwise, the command is being
// executed locally, and the replica is determined via lookup of
// header.Key in the ranges slice.
func (db *LocalDB) executeCmd(method string, header *storage.RequestHeader, args, reply interface{}) interface{} {
	chanVal := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, reflect.TypeOf(reply)), 1)
	replyVal := reflect.ValueOf(reply)
	go func() {
		// If the replica isn't specified in the header, look it up.
		var err error

		var store *storage.Store
		// If we aren't given a Replica, then a little bending over backwards here. We need to find the Store, but all
		// we have is the Key. So find its Range locally, and pull out its Replica which we use to find the Store.
		// This lets us use the same codepath below (store.ExecuteCmd) for both locally and remotely originated
		// commands.
		if header.Replica.NodeID == 0 {
			if repl := db.lookupReplica(header.Key); repl != nil {
				header.Replica = *repl
			} else {
				err = util.Errorf("unable to lookup range replica for key %q", string(header.Key))
			}
		}
		if err == nil {
			store, err = db.GetStore(&header.Replica)
		}
		if err != nil {
			reflect.Indirect(replyVal).FieldByName("Error").Set(reflect.ValueOf(err))
		} else {
			store.ExecuteCmd(method, header, args, reply)
		}
		chanVal.Send(replyVal)
	}()
	return chanVal.Interface()
}
예제 #11
0
// tysubst attempts to substitute all type variables within a single return
// type with their corresponding Go type from the type environment.
//
// tysubst will panic if a type variable is unbound, or if it encounters a
// type that cannot be dynamically created. Such types include arrays,
// functions and structs. (A limitation of the `reflect` package.)
func (rt returnType) tysubst(typ reflect.Type) reflect.Type {
	if tyname := tyvarName(typ); len(tyname) > 0 {
		if thetype, ok := rt.tyenv[tyname]; !ok {
			rt.panic("Unbound type variable %s.", tyname)
		} else {
			return thetype
		}
	}

	switch typ.Kind() {
	case reflect.Array:
		rt.panic("Cannot dynamically create Array types.")
	case reflect.Chan:
		return reflect.ChanOf(typ.ChanDir(), rt.tysubst(typ.Elem()))
	case reflect.Func:
		rt.panic("Cannot dynamically create Function types.")
	case reflect.Interface:
		rt.panic("TODO")
	case reflect.Map:
		return reflect.MapOf(rt.tysubst(typ.Key()), rt.tysubst(typ.Elem()))
	case reflect.Ptr:
		return reflect.PtrTo(rt.tysubst(typ.Elem()))
	case reflect.Slice:
		return reflect.SliceOf(rt.tysubst(typ.Elem()))
	case reflect.Struct:
		rt.panic("Cannot dynamically create Struct types.")
	case reflect.UnsafePointer:
		rt.panic("Cannot dynamically create unsafe.Pointer types.")
	}

	// We've covered all the composite types, so we're only left with
	// base types.
	return typ
}
예제 #12
0
func main() {
	t := reflect.TypeOf(3)
	chtype := reflect.ChanOf(reflect.RecvDir, t)
	inst := *(reflect.New(chtype).Interface().(*<-chan int))

	fmt.Println(inst)
}
예제 #13
0
// executeCmd runs Store.ExecuteCmd in a goroutine. A channel with
// element type equal to the reply type is created and returned
// immediately. The reply is sent to the channel once the cmd has been
// executed by the store. The store is looked up from the store map
// if specified by header.Replica; otherwise, the command is being
// executed locally, and the replica is determined via lookup of
// header.Key in the ranges slice.
func (db *LocalDB) executeCmd(method string, header *storage.RequestHeader, args, reply interface{}) interface{} {
	chanVal := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, reflect.TypeOf(reply)), 1)
	replyVal := reflect.ValueOf(reply)
	go func() {
		// If the replica isn't specified in the header, look it up.
		var err error
		var store *storage.Store
		if header.Replica.NodeID == 0 {
			if repl := db.lookupReplica(header.Key); repl != nil {
				header.Replica = *repl
			} else {
				err = util.Errorf("unable to lookup range replica for key %q", string(header.Key))
			}
		}
		if err == nil {
			store, err = db.GetStore(&header.Replica)
		}
		if err != nil {
			reflect.Indirect(replyVal).FieldByName("Error").Set(reflect.ValueOf(err))
		} else {
			store.ExecuteCmd(method, header, args, reply)
		}
		chanVal.Send(replyVal)
	}()
	return chanVal.Interface()
}
예제 #14
0
// FlattenChan is of type: func(input chan []T) chan T.
// Takes a chan of arrays, and concatenates them together, putting each element
// onto the output chan. After input is closed, output is also closed. If input
// is chan T instead of type chan []T, then this is a no-op.
func FlattenChan(input interface{}) interface{} {
	inputValue := reflect.ValueOf(input)

	if inputValue.Kind() != reflect.Chan {
		panic(fmt.Sprintf("FlattenChan called on invalid type: %s", inputValue.Type()))
	}

	elemType := inputValue.Type().Elem()
	if elemType.Kind() != reflect.Array &&
		elemType.Kind() != reflect.Slice {
		return input
	}

	outputType := reflect.ChanOf(reflect.BothDir, elemType.Elem())
	output := reflect.MakeChan(outputType, 0)
	go func() {
		for {
			value, ok := inputValue.Recv()
			if !ok {
				break
			}

			for i := 0; i < value.Len(); i++ {
				output.Send(value.Index(i))
			}
		}
		output.Close()
	}()
	return output.Interface()
}
예제 #15
0
// makeWorkerChans makes a buffered channel of the specified type
func makeWorkerChans(t reflect.Type) (chan []reflect.Value, reflect.Value) {
	// display(reflect.TypeOf([]reflect.Value{}))
	// job := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, reflect.TypeOf(&channeller{})), 100)
	// job := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, reflect.TypeOf([]reflect.Value{})), 100)
	job := make(chan []reflect.Value)
	res := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, t), 100)
	return job, res
}
예제 #16
0
func main() {
	c := reflect.ChanOf(reflect.SendDir|reflect.RecvDir, Int)
	fmt.Println(c)

	t := reflect.TypeOf(make(chan int)).Elem()
	fmt.Println(t)

}
예제 #17
0
파일: chan.go 프로젝트: ttthzy/qlang
func chanOf(elem interface{}) interface{} {

	if t, ok := elem.(qlang.GoTyper); ok {
		tchan := reflect.ChanOf(reflect.BothDir, t.GoType())
		return qlang.NewType(tchan)
	}
	panic(fmt.Sprintf("invalid chan T: `%v` isn't a qlang type", elem))
}
예제 #18
0
func Test_InjectorSet(t *testing.T) {
	injector := inject.New()
	typ := reflect.TypeOf("string")
	typSend := reflect.ChanOf(reflect.SendDir, typ)
	typRecv := reflect.ChanOf(reflect.RecvDir, typ)

	// instantiating unidirectional channels is not possible using reflect
	// http://golang.org/src/pkg/reflect/value.go?s=60463:60504#L2064
	chanRecv := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0)
	chanSend := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0)

	injector.Set(typSend, chanSend)
	injector.Set(typRecv, chanRecv)

	expect(t, injector.Get(typSend).IsValid(), true)
	expect(t, injector.Get(typRecv).IsValid(), true)
	expect(t, injector.Get(chanSend.Type()).IsValid(), false)
}
예제 #19
0
// Make makes a channel from the parameters in ChannelDescriptor struct.
func (c *ChannelDescriptor) Make(both bool) reflect.Value {
	dir := c.Dir
	if both {
		dir = reflect.BothDir
	}
	elem := types.MakeNew(c.TypeName, c.Size)
	typ := reflect.ChanOf(dir, elem.Type())
	return reflect.MakeChan(typ, c.Size)
}
예제 #20
0
파일: chan.go 프로젝트: ttthzy/qlang
func Mkchan(typ interface{}, buffer ...int) *qlang.Chan {

	n := 0
	if len(buffer) > 0 {
		n = buffer[0]
	}
	t := reflect.ChanOf(reflect.BothDir, types.Reflect(typ))
	return &qlang.Chan{Data: reflect.MakeChan(t, n)}
}
예제 #21
0
// JSON returns a websocket handling middleware. It can only be used
// in handlers for HTTP GET.
// IMPORTANT: The last handler in your handler chain must block in order for the
// connection to be kept alive.
// It accepts an empty struct it will copy and try to populate
// with data received from the client using the JSON Marshaler, as well
// as it will serialize your structs to JSON and send them to the client.
// For the following, it is assumed you passed a struct named Message
// to the handler.
// It maps four channels for you to use in the follow-up Handler(s):
// - A receiving string channel (<-chan *Message) on which you will
//   receive all incoming structs from the client
// - A sending string channel (chan<- *Message) on which you will be
//   able to send structs to the client.
// - A receiving error channel (<-chan error) on which you will receive
//   errors occurring while sending & receiving
// - A receiving disconnect channel  (<-chan bool) on which you will receive
//   a message only if the connection is about to be closed following an
//   error or a client disconnect.
// - A sending done channel  (chan<- bool) on which you can send as soon as you wish
//   to disconnect the connection.
// The middleware handles the following for you:
// - Checking the request for cross origin access
// - Doing the websocket handshake
// - Setting sensible options for the Gorilla websocket connection
// - Starting and terminating the necessary goroutines
// An optional sockets.Options object can be passed to Messages to overwrite
// default options mentioned in the documentation of the Options object.
func JSON(bindStruct interface{}, options ...*Options) martini.Handler {
	o := newOptions(options)

	return func(context martini.Context, resp http.ResponseWriter, req *http.Request) {
		// Check the request for cross origin access or HTTP methods other than GET
		status, err := checkRequest(req, o)
		if err != nil {
			resp.WriteHeader(status)
			resp.Write([]byte(err.Error()))
			return
		}

		// Do handshake with the client and upgrade the connection to a websocket
		ws, err := doHandshake(resp, req, o)
		if err != nil {
			resp.WriteHeader(http.StatusBadRequest)
			resp.Write([]byte(err.Error()))
			return
		}

		// Set up the JSON connection
		c := newJSONConnection(bindStruct, ws, o)

		// Set the options for the gorilla websocket package
		c.setSocketOptions()

		// Map the Sender to a chan<- *Message for the next Handler(s)
		context.Set(reflect.ChanOf(reflect.SendDir, c.typ), c.Sender)

		// Map the Receiver to a <-chan *Message for the next Handler(s)
		context.Set(reflect.ChanOf(reflect.RecvDir, c.typ), c.Receiver)

		// Map the Channels <-chan error, <-chan bool and chan<- bool
		c.mapDefaultChannels(context)

		// start the send and receive goroutines
		go c.send()
		go c.recv()
		go waitForDisconnect(c)

		// call the next handler, which must block
		context.Next()
	}
}
예제 #22
0
func chanOfBoth() {
	t := reflect.ChanOf(reflect.BothDir, reflect.TypeOf(&a))
	print(reflect.Zero(t).Interface()) // @types <-chan *int | chan<- *int | chan *int
	ch := reflect.MakeChan(t, 0)
	print(ch.Interface().(chan *int)) // @pointsto <alloc in reflect.MakeChan>
	ch.Send(reflect.ValueOf(&b))
	ch.Interface().(chan *int) <- &a
	r, _ := ch.Recv()
	print(r.Interface().(*int))         // @pointsto main.a | main.b
	print(<-ch.Interface().(chan *int)) // @pointsto main.a | main.b
}
예제 #23
0
// invokeMethod sends the specified RPC asynchronously and returns a
// channel which receives the reply struct when the call is
// complete. Returns a channel of the same type as "reply".
func (db *LocalDB) invokeMethod(method string, args, reply interface{}) interface{} {
	chanVal := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, reflect.TypeOf(reply)), 1)
	replyVal := reflect.ValueOf(reply)
	reflect.ValueOf(db.rng).MethodByName(method).Call([]reflect.Value{
		reflect.ValueOf(args),
		replyVal,
	})
	chanVal.Send(replyVal)

	return chanVal.Interface()
}
예제 #24
0
func sendSlice(slice interface{}) (channel interface{}) {
	sliceValue := reflect.ValueOf(slice)
	chanType := reflect.ChanOf(reflect.BothDir, sliceValue.Type().Elem())
	chanValue := reflect.MakeChan(chanType, 0)
	go func() {
		for i := 0; i < sliceValue.Len(); i++ {
			chanValue.Send(sliceValue.Index(i))
		}
		chanValue.Close()
	}()
	return chanValue.Interface()
}
예제 #25
0
func (d *Dataset) SetupShard(n int) {
	ctype := reflect.ChanOf(reflect.BothDir, d.Type)
	for i := 0; i < n; i++ {
		ds := &DatasetShard{
			Id:        i,
			Parent:    d,
			WriteChan: reflect.MakeChan(ctype, 0),
		}
		// println("created shard", ds.Name())
		d.Shards = append(d.Shards, ds)
	}
}
예제 #26
0
func Test_Injector_Set(t *testing.T) {
	Convey("Set and get type", t, func() {
		injector := inject.New()
		So(injector, ShouldNotBeNil)

		typ := reflect.TypeOf("string")
		typSend := reflect.ChanOf(reflect.SendDir, typ)
		typRecv := reflect.ChanOf(reflect.RecvDir, typ)

		// instantiating unidirectional channels is not possible using reflect
		// http://golang.org/src/pkg/reflect/value.go?s=60463:60504#L2064
		chanRecv := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0)
		chanSend := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0)

		injector.Set(typSend, chanSend)
		injector.Set(typRecv, chanRecv)

		So(injector.GetVal(typSend).IsValid(), ShouldBeTrue)
		So(injector.GetVal(typRecv).IsValid(), ShouldBeTrue)
		So(injector.GetVal(chanSend.Type()).IsValid(), ShouldBeFalse)
	})
}
예제 #27
0
파일: func.go 프로젝트: benashford/go-func
func pMapChan(dataChan interface{}, f interface{}) (resultChan interface{}) {
	fType := reflect.TypeOf(f)
	fRetType := fType.Out(0)
	dataChanType := reflect.TypeOf(dataChan)
	dataChanElemType := dataChanType.Elem()
	inChans := make([]reflect.Value, cpus)
	outChans := make([]reflect.Value, cpus)
	for i := 0; i < cpus; i++ {
		inChans[i] = reflect.MakeChan(reflect.ChanOf(reflect.BothDir, dataChanElemType), cpus)
		outChans[i] = reflect.MakeChan(reflect.ChanOf(reflect.BothDir, fRetType), cpus)

		go pMapChanInt(inChans[i], f, outChans[i])
	}
	go pMapFeedInChans(dataChan, inChans)

	resultChanValue := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, fRetType), 0)
	resultChan = resultChanValue.Interface()

	go pMapDrainOutChans(outChans, resultChanValue)

	return
}
예제 #28
0
// Invoke calls the method's handler with the given input.  Each encoded output
// from the method is passed to out, and the final result is returned.  Invoke
// will panic if it is unable to encode an output from the handler.
//
// Returns ErrNoSuchMethod if m == nil.
func (m *Method) Invoke(ctx Context, in []byte, out func([]byte)) error {
	if m == nil {
		return ErrNoSuchMethod
	}
	inValue, err := decode(in, m.input)
	if err != nil {
		return &protocol.Error{
			Code:    protocol.ErrorInvalidParams,
			Message: fmt.Sprintf("unable to decode params: %v", err),
		}
	}

	if m.Stream {
		outChan := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, m.output), 0)
		var wg sync.WaitGroup
		wg.Add(1)
		go func() {
			defer wg.Done()
			for {
				v, ok := outChan.Recv()
				if !ok {
					break
				}
				bits, err := json.Marshal(v.Interface())
				if err != nil {
					panic(err) // Not expected to occur
				}
				out(bits)
			}
		}()

		err = m.callStream(ctx, inValue, outChan)
		outChan.Close()
		wg.Wait()
		return err
	}

	// Non-streaming case
	v, err := m.call(ctx, inValue)
	if err != nil {
		return err
	}
	bits, err := json.Marshal(v)
	if err != nil {
		panic(err) // Not expected to occur
	}
	out(bits)
	return nil
}
예제 #29
0
// Slice accepts a slice and send values to tasks via Channel()
func (fc *FlowContext) Slice(slice interface{}) (ret *Dataset) {
	sliceValue, sliceType := reflect.ValueOf(slice), reflect.TypeOf(slice)
	sliceLen := sliceValue.Len()
	chType := reflect.ChanOf(reflect.BothDir, sliceType.Elem())
	chValue := reflect.MakeChan(chType, 16)

	go func() {
		for i := 0; i < sliceLen; i++ {
			chValue.Send(sliceValue.Index(i))
		}
		chValue.Close()
	}()

	return fc.doChannel(chValue, chType)
}
예제 #30
0
파일: db.go 프로젝트: hahan/cockroach
// routeRPC verifies permissions and looks up the appropriate range
// based on the supplied key and sends the RPC according to the
// specified options. routeRPC sends asynchronously and returns a
// channel which receives the reply struct when the call is
// complete. Returns a channel of the same type as "reply".
func (db *DistDB) routeRPC(method string, header *storage.RequestHeader, args, reply interface{}) interface{} {
	chanVal := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, reflect.TypeOf(reply)), 1)

	// Verify permissions.
	if err := db.verifyPermissions(method, header); err != nil {
		replyVal := reflect.ValueOf(reply)
		reflect.Indirect(replyVal).FieldByName("Error").Set(reflect.ValueOf(err))
		chanVal.Send(replyVal)
		return chanVal.Interface()
	}

	// Retry logic for lookup of range by key and RPCs to range replicas.
	go func() {
		retryOpts := util.RetryOptions{
			Tag:         fmt.Sprintf("routing %s rpc", method),
			Backoff:     retryBackoff,
			MaxBackoff:  maxRetryBackoff,
			Constant:    2,
			MaxAttempts: 0, // retry indefinitely
		}
		err := util.RetryWithBackoff(retryOpts, func() (bool, error) {
			rangeMeta, err := db.rangeCache.LookupRangeMetadata(header.Key)
			if err == nil {
				err = db.sendRPC(rangeMeta.Replicas, method, args, chanVal.Interface())
			}
			if err != nil {
				// Range metadata might be out of date - evict it.
				db.rangeCache.EvictCachedRangeMetadata(header.Key)

				// If retryable, allow outer loop to retry.
				if retryErr, ok := err.(util.Retryable); ok && retryErr.CanRetry() {
					glog.Warningf("failed to invoke %s: %v", method, err)
					return false, nil
				}
				// TODO(mtracy): Make sure that errors that clearly result from
				// a stale metadata cache are retryable.
			}
			return true, err
		})
		if err != nil {
			replyVal := reflect.ValueOf(reply)
			reflect.Indirect(replyVal).FieldByName("Error").Set(reflect.ValueOf(err))
			chanVal.Send(replyVal)
		}
	}()

	return chanVal.Interface()
}