예제 #1
0
파일: labels.go 프로젝트: micro/go-platform
func main() {
	cmd.Init()

	r := router.NewRouter()
	c := client.NewClient(client.Selector(r))
	c = router.NewLabelWrapper(c)

	// Create new request to service go.micro.srv.greeter, method Say.Hello
	req := c.NewRequest("go.micro.srv.greeter", "Say.Hello", &hello.Request{
		Name: "John",
	})

	rsp := &hello.Response{}

	// Set arbitrary headers in context
	ctx := metadata.NewContext(context.Background(), map[string]string{
		router.LabelPrefix + "Greeter": "one",
	})

	// Call service
	if err := c.Call(ctx, req, rsp); err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(rsp.Msg)
}
예제 #2
0
func (c *clientWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	// retrieve token if one exists
	t, err := c.a.Introspect(ctx)
	if err != nil {
		// no? ok let's try make the call as ourself
		t, err = c.a.Token()
		if err != nil {
			return err
		}
	}

	// create new context with token
	newCtx := c.a.NewContext(ctx, t)

	// set metadata
	newCtx = metadata.NewContext(newCtx, c.a.NewHeader(map[string]string{}, t))

	// circuit break, check authorization here
	t, err = c.a.Authorized(newCtx, req)
	if err != nil {
		return ErrInvalidToken
	}

	// now just make a regular call down the stack
	err = c.Client.Call(newCtx, req, rsp, opts...)
	return err
}
예제 #3
0
func (s *rpcServer) accept(sock transport.Socket) {
	defer func() {
		// close socket
		sock.Close()

		if r := recover(); r != nil {
			log.Print(r, string(debug.Stack()))
		}
	}()

	for {
		var msg transport.Message
		if err := sock.Recv(&msg); err != nil {
			return
		}

		// we use this Timeout header to set a server deadline
		to := msg.Header["Timeout"]
		// we use this Content-Type header to identify the codec needed
		ct := msg.Header["Content-Type"]

		cf, err := s.newCodec(ct)
		// TODO: needs better error handling
		if err != nil {
			sock.Send(&transport.Message{
				Header: map[string]string{
					"Content-Type": "text/plain",
				},
				Body: []byte(err.Error()),
			})
			return
		}

		codec := newRpcPlusCodec(&msg, sock, cf)

		// strip our headers
		hdr := make(map[string]string)
		for k, v := range msg.Header {
			hdr[k] = v
		}
		delete(hdr, "Content-Type")
		delete(hdr, "Timeout")

		ctx := metadata.NewContext(context.Background(), hdr)

		// set the timeout if we have it
		if len(to) > 0 {
			if n, err := strconv.ParseUint(to, 10, 64); err == nil {
				ctx, _ = context.WithTimeout(ctx, time.Duration(n))
			}
		}

		// TODO: needs better error handling
		if err := s.rpc.serveRequest(ctx, codec, ct); err != nil {
			log.Printf("Unexpected error serving request, closing socket: %v", err)
			return
		}
	}
}
예제 #4
0
func RequestToContext(r *http.Request) context.Context {
	ctx := context.Background()
	md := make(metadata.Metadata)
	for k, v := range r.Header {
		md[k] = strings.Join(v, ",")
	}
	return metadata.NewContext(ctx, md)
}
예제 #5
0
func (c *clientWrapper) setHeaders(ctx context.Context) context.Context {
	md, ok := metadata.FromContext(ctx)
	if !ok {
		md = metadata.Metadata{}
	}
	for k, v := range c.headers {
		if _, ok := md[k]; !ok {
			md[k] = v
		}
	}
	return metadata.NewContext(ctx, md)
}
예제 #6
0
func pub(time int64, bid float64, ask float64, last float64) {
	tick := &tickRecorder.Tick{
		Time: time,
		Bid:  bid,
		Ask:  ask,
		Last: last,
	}
	p := service.Client().NewPublication("go.micro.srv.tickStream", tick)
	ctx := metadata.NewContext(context.Background(), map[string]string{
		"X-User-Id": "nii236",
		"X-From-Id": "tickSubscriber",
	})
	service.Client().Publish(ctx, p)

}
예제 #7
0
func (o *otWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	md, _ := metadata.FromContext(ctx)
	name := fmt.Sprintf("%s.%s", req.Service(), req.Method())
	var sp opentracing.Span
	wireContext, err := o.ot.Extract(opentracing.TextMap, opentracing.TextMapCarrier(md))
	if err != nil {
		sp = o.ot.StartSpan(name)
	} else {
		sp = o.ot.StartSpan(name, opentracing.ChildOf(wireContext))
	}
	defer sp.Finish()
	if err := sp.Tracer().Inject(sp.Context(), opentracing.TextMap, opentracing.TextMapCarrier(md)); err != nil {
		return err
	}
	ctx = metadata.NewContext(ctx, md)
	return o.Client.Call(ctx, req, rsp, opts...)
}
예제 #8
0
func TestWrapper(t *testing.T) {
	testData := []struct {
		existing  metadata.Metadata
		headers   metadata.Metadata
		overwrite bool
	}{
		{
			existing: metadata.Metadata{},
			headers: metadata.Metadata{
				"foo": "bar",
			},
			overwrite: true,
		},
		{
			existing: metadata.Metadata{
				"foo": "bar",
			},
			headers: metadata.Metadata{
				"foo": "baz",
			},
			overwrite: false,
		},
	}

	for _, d := range testData {
		c := &clientWrapper{
			headers: d.headers,
		}

		ctx := metadata.NewContext(context.Background(), d.existing)
		c.setHeaders(ctx)

		md, _ := metadata.FromContext(ctx)

		for k, v := range d.headers {
			if d.overwrite && md[k] != v {
				t.Fatalf("Expected %s=%s got %s=%s", k, v, k, md[k])
			}
			if !d.overwrite && md[k] != d.existing[k] {
				t.Fatalf("Expected %s=%s got %s=%s", k, d.existing[k], k, md[k])
			}
		}
	}

}
예제 #9
0
파일: pub.go 프로젝트: ZhuJingfa/go-micro
// publishes a message
func pub(i int) {
	msg := client.NewPublication("topic.go.micro.srv.example", &example.Message{
		Say: fmt.Sprintf("This is a publication %d", i),
	})

	// create context with metadata
	ctx := metadata.NewContext(context.Background(), map[string]string{
		"X-User-Id": "john",
		"X-From-Id": "script",
	})

	// publish message
	if err := client.Publish(ctx, msg); err != nil {
		fmt.Println("pub err: ", err)
		return
	}

	fmt.Printf("Published %d: %v\n", i, msg)
}
예제 #10
0
파일: util.go 프로젝트: micro/go-plugins
func newContext(ctx context.Context, s *awsxray.Segment) context.Context {
	md, _ := metadata.FromContext(ctx)

	// make copy to avoid races
	newMd := metadata.Metadata{}
	for k, v := range md {
		newMd[k] = v
	}

	// set trace id in header
	newMd[awsxray.TraceHeader] = awsxray.SetTraceId(newMd[awsxray.TraceHeader], s.TraceId)
	// set parent id in header
	newMd[awsxray.TraceHeader] = awsxray.SetParentId(newMd[awsxray.TraceHeader], s.ParentId)
	// store segment in context
	ctx = awsxray.NewContext(ctx, s)
	// store metadata in context
	ctx = metadata.NewContext(ctx, newMd)

	return ctx
}
예제 #11
0
func call(i int) {
	// Create new request to service go.micro.srv.example, method Example.Call
	req := client.NewRequest("go.micro.srv.example", "Example.Call", &example.Request{
		Name: "John",
	})

	// create context with metadata
	ctx := metadata.NewContext(context.Background(), map[string]string{
		"datacenter": "local",
	})

	rsp := &example.Response{}

	// Call service
	if err := client.Call(ctx, req, rsp); err != nil {
		fmt.Println("call err: ", err, rsp)
		return
	}

	fmt.Println("Call:", i, "rsp:", rsp.Msg)
}
예제 #12
0
// NewHandlerWrapper accepts an opentracing Tracer and returns a Handler Wrapper
func NewHandlerWrapper(ot opentracing.Tracer) server.HandlerWrapper {
	return func(h server.HandlerFunc) server.HandlerFunc {
		return func(ctx context.Context, req server.Request, rsp interface{}) error {
			md, _ := metadata.FromContext(ctx)
			name := fmt.Sprintf("%s.%s", req.Service(), req.Method())
			var sp opentracing.Span
			wireContext, err := ot.Extract(opentracing.TextMap, opentracing.TextMapCarrier(md))
			if err != nil {
				sp = ot.StartSpan(name)
			} else {
				sp = ot.StartSpan(name, opentracing.ChildOf(wireContext))
			}
			defer sp.Finish()
			if err := sp.Tracer().Inject(sp.Context(), opentracing.TextMap, opentracing.TextMapCarrier(md)); err != nil {
				return err
			}
			ctx = metadata.NewContext(ctx, md)
			return h(ctx, req, rsp)
		}
	}
}
예제 #13
0
파일: codegen.go 프로젝트: Zerak/micro
func main() {
	cmd.Init()

	// use the generated client stub
	cl := hello.NewSayClient("go.micro.srv.greeter", client.DefaultClient)

	// Set arbitrary headers in context
	ctx := metadata.NewContext(context.Background(), map[string]string{
		"X-User-Id": "john",
		"X-From-Id": "script",
	})

	rsp, err := cl.Hello(ctx, &hello.Request{
		Name: "John",
	})
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(rsp.Msg)
}
예제 #14
0
파일: client.go 프로젝트: Zerak/micro
func main() {
	cmd.Init()

	// Create new request to service go.micro.srv.greeter, method Say.Hello
	req := client.NewRequest("go.micro.srv.greeter", "Say.Hello", &hello.Request{
		Name: "John",
	})

	// Set arbitrary headers in context
	ctx := metadata.NewContext(context.Background(), map[string]string{
		"X-User-Id": "john",
		"X-From-Id": "script",
	})

	rsp := &hello.Response{}

	// Call service
	if err := client.Call(ctx, req, rsp); err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(rsp.Msg)
}
예제 #15
0
func (c *clientWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	var span *Span
	var ok, okk bool
	var err error
	md := metadata.Metadata{}

	// try pull span from context
	span, ok = c.t.FromContext(ctx)
	if !ok {
		// couldn't do that, try from the metadata

		// So get trace info from metadata
		var kk bool
		md, kk = metadata.FromContext(ctx)
		if !kk {
			// couldn't do that either

			// so this is a new span!
			md = metadata.Metadata{}
			span = c.t.NewSpan(nil)
		} else {
			// ok we got some md

			// can we get the span from the header?
			span, okk = c.t.FromHeader(md)
			if !okk {
				// no, ok create one!
				span = c.t.NewSpan(nil)
			}
		}
	}

	// got parent span from context or metadata
	if okk || ok {
		// setup the span with parent
		span = c.t.NewSpan(&Span{
			// same trace id
			TraceId: span.TraceId,
			// set parent id to parent span id
			ParentId: span.Id,
			// use previous debug
			Debug: span.Debug,
		})
	}

	// start the span
	span.Annotations = append(span.Annotations, &Annotation{
		Timestamp: time.Now(),
		Type:      AnnStart,
		Service:   c.s,
	})

	// and mark as debug? might want to do this based on a setting
	span.Debug = true
	// set uniq span name
	span.Name = req.Service() + "." + req.Method()
	// set source/dest
	span.Source = c.s
	span.Destination = &registry.Service{Name: req.Service()}

	// set context key
	newCtx := c.t.NewContext(ctx, span)
	// set metadata
	newCtx = metadata.NewContext(newCtx, c.t.NewHeader(md, span))

	// mark client request
	span.Annotations = append(span.Annotations, &Annotation{
		Timestamp: time.Now(),
		Type:      AnnClientRequest,
		Service:   c.s,
	})

	// defer the completion of the span
	defer func() {
		// mark client response
		span.Annotations = append(span.Annotations, &Annotation{
			Timestamp: time.Now(),
			Type:      AnnClientResponse,
			Service:   c.s,
		})

		// if we were the creator
		var debug map[string]string
		if err != nil {
			debug = map[string]string{"error": err.Error()}
		}
		// mark end of span
		span.Annotations = append(span.Annotations, &Annotation{
			Timestamp: time.Now(),
			Type:      AnnEnd,
			Service:   c.s,
			Debug:     debug,
		})

		span.Duration = time.Now().Sub(span.Timestamp)

		// flush the span to the collector on return
		c.t.Collect(span)
	}()

	// now just make a regular call down the stack
	err = c.Client.Call(newCtx, req, rsp, opts...)
	return err
}
예제 #16
0
func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broker.Handler {
	return func(p broker.Publication) error {
		msg := p.Message()
		ct := msg.Header["Content-Type"]
		cf, err := g.newCodec(ct)
		if err != nil {
			return err
		}

		hdr := make(map[string]string)
		for k, v := range msg.Header {
			hdr[k] = v
		}
		delete(hdr, "Content-Type")
		ctx := metadata.NewContext(context.Background(), hdr)

		for i := 0; i < len(sb.handlers); i++ {
			handler := sb.handlers[i]

			var isVal bool
			var req reflect.Value

			if handler.reqType.Kind() == reflect.Ptr {
				req = reflect.New(handler.reqType.Elem())
			} else {
				req = reflect.New(handler.reqType)
				isVal = true
			}
			if isVal {
				req = req.Elem()
			}

			b := &buffer{bytes.NewBuffer(msg.Body)}
			co := cf(b)
			defer co.Close()

			if err := co.ReadHeader(&codec.Message{}, codec.Publication); err != nil {
				return err
			}

			if err := co.ReadBody(req.Interface()); err != nil {
				return err
			}

			fn := func(ctx context.Context, msg server.Publication) error {
				var vals []reflect.Value
				if sb.typ.Kind() != reflect.Func {
					vals = append(vals, sb.rcvr)
				}
				if handler.ctxType != nil {
					vals = append(vals, reflect.ValueOf(ctx))
				}

				vals = append(vals, reflect.ValueOf(msg.Message()))

				returnValues := handler.method.Call(vals)
				if err := returnValues[0].Interface(); err != nil {
					return err.(error)
				}
				return nil
			}

			for i := len(opts.SubWrappers); i > 0; i-- {
				fn = opts.SubWrappers[i-1](fn)
			}

			go fn(ctx, &rpcPublication{
				topic:       sb.topic,
				contentType: ct,
				message:     req.Interface(),
			})
		}
		return nil
	}
}
예제 #17
0
func (t *traceWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	ctx = metadata.NewContext(ctx, map[string]string{
		"X-Trace-Id": fmt.Sprintf("%d", time.Now().Unix()),
	})
	return t.Client.Call(ctx, req, rsp)
}
예제 #18
0
파일: main.go 프로젝트: micro/micro
func (s *Hotel) Rates(ctx context.Context, req *hotel.Request, rsp *hotel.Response) error {
	// tracing
	tr := trace.New("api.v1", "Hotel.Rates")
	defer tr.Finish()

	// context
	ctx = trace.NewContext(ctx, tr)

	md, ok := metadata.FromContext(ctx)
	if !ok {
		md = metadata.Metadata{}
	}

	// add a unique request id to context
	if traceID, err := uuid.NewV4(); err == nil {
		// make copy
		tmd := metadata.Metadata{}
		for k, v := range md {
			tmd[k] = v
		}

		tmd["traceID"] = traceID.String()
		tmd["fromName"] = "api.v1"
		ctx = metadata.NewContext(ctx, tmd)
	}

	// token from request headers
	token, err := getToken(md)
	if err != nil {
		return merr.Forbidden("api.hotel.rates", err.Error())
	}

	// verify token w/ auth service
	authClient := auth.NewAuthClient("go.micro.srv.auth", s.Client)
	if _, err = authClient.VerifyToken(ctx, &auth.Request{AuthToken: token}); err != nil {
		return merr.Unauthorized("api.hotel.rates", "Unauthorized")
	}

	// checkin and checkout date query params
	inDate, outDate := req.InDate, req.OutDate
	if inDate == "" || outDate == "" {
		return merr.BadRequest("api.hotel.rates", "Please specify inDate/outDate params")
	}

	// finds nearby hotels
	// TODO(hw): use lat/lon from request params
	geoClient := geo.NewGeoClient("go.micro.srv.geo", s.Client)
	nearby, err := geoClient.Nearby(ctx, &geo.Request{
		Lat: 51.502973,
		Lon: -0.114723,
	})
	if err != nil {
		return merr.InternalServerError("api.hotel.rates", err.Error())
	}

	// make reqeusts for profiles and rates
	profileCh := getHotelProfiles(s.Client, ctx, nearby.HotelIds)
	rateCh := getRatePlans(s.Client, ctx, nearby.HotelIds, inDate, outDate)

	// wait on profiles reply
	profileReply := <-profileCh
	if err := profileReply.err; err != nil {
		return merr.InternalServerError("api.hotel.rates", err.Error())
	}

	// wait on rates reply
	rateReply := <-rateCh
	if err := rateReply.err; err != nil {
		return merr.InternalServerError("api.hotel.rates", err.Error())
	}

	rsp.Hotels = profileReply.hotels
	rsp.RatePlans = rateReply.ratePlans
	return nil
}
예제 #19
0
파일: grpc.go 프로젝트: micro/go-plugins
func (g *grpcServer) serveStream(t transport.ServerTransport, stream *transport.Stream) {
	serviceMethod := strings.Split(stream.Method(), ".")
	if len(serviceMethod) != 2 {
		if err := t.WriteStatus(stream, codes.InvalidArgument, fmt.Sprintf("malformed method name: %q", stream.Method())); err != nil {
			log.Printf("grpc: Server.serveStream failed to write status: %v", err)
		}
		return
	}

	g.rpc.mu.Lock()
	service := g.rpc.serviceMap[serviceMethod[0]]
	g.rpc.mu.Unlock()
	if service == nil {
		if err := t.WriteStatus(stream, codes.Unimplemented, fmt.Sprintf("unknown service %v", service)); err != nil {
			log.Printf("grpc: Server.serveStream failed to write status: %v", err)
		}
		return
	}

	mtype := service.method[serviceMethod[1]]
	if mtype == nil {
		if err := t.WriteStatus(stream, codes.Unimplemented, fmt.Sprintf("unknown service %v", service)); err != nil {
			log.Printf("grpc: Server.serveStream failed to write status: %v", err)
		}
	}

	// get grpc metadata
	gmd, ok := metadata.FromContext(stream.Context())
	if !ok {
		gmd = metadata.MD{}
	}

	// copy the metadata to go-micro.metadata
	md := meta.Metadata{}
	for k, v := range gmd {
		md[k] = strings.Join(v, ", ")
	}

	// get content type
	ct := defaultContentType
	if ctype, ok := md["x-content-type"]; ok {
		ct = ctype
	}

	// get codec
	codec, err := g.newGRPCCodec(ct)
	if err != nil {
		if errr := t.WriteStatus(stream, codes.Internal, err.Error()); errr != nil {
			log.Printf("grpc: Server.serveStream failed to write status: %v", errr)
		}
		return
	}

	// timeout for server deadline
	to := md["timeout"]

	delete(md, "x-content-type")
	delete(md, "timeout")

	// create new context
	ctx := meta.NewContext(stream.Context(), md)

	// set the timeout if we have it
	if len(to) > 0 {
		if n, err := strconv.ParseUint(to, 10, 64); err == nil {
			ctx, _ = context.WithTimeout(ctx, time.Duration(n))
		}
	}

	// process unary
	if !mtype.stream {
		g.processRequest(t, stream, service, mtype, codec, ct, ctx)
		return
	}

	// process strea
	g.processStream(t, stream, service, mtype, codec, ct, ctx)
}