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) }
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 }
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 } } }
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) }
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) }
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) }
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...) }
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]) } } } }
// 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) }
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 }
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) }
// 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) } } }
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) }
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) }
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 = ®istry.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 }
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 } }
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) }
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 }
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) }