func (w *wrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { if !w.whitelist[req.Service()] { return errors.Forbidden("go.micro.rpc", "forbidden") } return w.Client.Call(ctx, req, rsp, opts...) }
func (c *clientWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { // execute client wrapper? if !c.endpoints[req.Method()] { // no return c.Client.Call(ctx, req, rsp, opts...) } // yes return c.wrapper(c.Client).Call(ctx, req, rsp, opts...) }
func (x *xrayWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { var err error s := getSegment(x.opts.Name, ctx) defer func() { setCallStatus(s, req.Service(), req.Method(), err) go record(x.x, s) }() ctx = newContext(ctx, s) err = x.Client.Call(ctx, req, rsp, opts...) return err }
func (g *grpcClient) stream(ctx context.Context, address string, req client.Request, opts client.CallOptions) (client.Streamer, error) { header := make(map[string]string) if md, ok := metadata.FromContext(ctx); ok { for k, v := range md { header[k] = v } } // set timeout in nanoseconds header["timeout"] = fmt.Sprintf("%d", opts.RequestTimeout) // set the content type for the request header["x-content-type"] = req.ContentType() md := gmetadata.New(header) ctx = gmetadata.NewContext(ctx, md) cf, err := g.newGRPCCodec(req.ContentType()) if err != nil { return nil, errors.InternalServerError("go.micro.client", err.Error()) } // TODO: do not use insecure cc, err := grpc.Dial(address, grpc.WithCodec(cf), grpc.WithTimeout(opts.DialTimeout), grpc.WithInsecure()) if err != nil { return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) } desc := &grpc.StreamDesc{ StreamName: req.Service() + req.Method(), ClientStreams: true, ServerStreams: true, } st, err := grpc.NewClientStream(ctx, desc, cc, req.Method()) if err != nil { return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err)) } return &grpcStream{ context: ctx, request: req, closed: make(chan bool), stream: st, conn: cc, }, nil }
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 (m *MockClient) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { m.Lock() defer m.Unlock() response, ok := m.Response[req.Service()] if !ok { return errors.NotFound("go.micro.client.mock", "service not found") } for _, r := range response { if r.Method != req.Method() { continue } if r.Error != nil { return r.Error } v := reflect.ValueOf(rsp) if t := reflect.TypeOf(rsp); t.Kind() == reflect.Ptr { v = reflect.Indirect(v) } v.Set(reflect.ValueOf(r.Response)) return nil } return fmt.Errorf("rpc: can't find service %s", req.Method()) }
func (g *grpcClient) call(ctx context.Context, address string, req client.Request, rsp interface{}, opts client.CallOptions) error { header := make(map[string]string) if md, ok := metadata.FromContext(ctx); ok { for k, v := range md { header[k] = v } } // set timeout in nanoseconds header["timeout"] = fmt.Sprintf("%d", opts.RequestTimeout) // set the content type for the request header["x-content-type"] = req.ContentType() md := gmetadata.New(header) ctx = gmetadata.NewContext(ctx, md) cf, err := g.newGRPCCodec(req.ContentType()) if err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } var grr error // TODO: do not use insecure cc, err := grpc.Dial(address, grpc.WithCodec(cf), grpc.WithTimeout(opts.DialTimeout), grpc.WithInsecure()) if err != nil { return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) } defer cc.Close() ch := make(chan error, 1) go func() { ch <- grpc.Invoke(ctx, req.Method(), req.Request(), rsp, cc) }() select { case err := <-ch: grr = err case <-ctx.Done(): grr = ctx.Err() } return grr }
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 *grpcClient) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Streamer, error) { // make a copy of call opts callOpts := g.opts.CallOptions for _, opt := range opts { opt(&callOpts) } // get next nodes from the selector next, err := g.opts.Selector.Select(req.Service(), callOpts.SelectOptions...) if err != nil && err == selector.ErrNotFound { return nil, errors.NotFound("go.micro.client", err.Error()) } else if err != nil { return nil, errors.InternalServerError("go.micro.client", err.Error()) } // check if we already have a deadline d, ok := ctx.Deadline() if !ok { // no deadline so we create a new one ctx, _ = context.WithTimeout(ctx, callOpts.RequestTimeout) } else { // got a deadline so no need to setup context // but we need to set the timeout we pass along opt := client.WithRequestTimeout(d.Sub(time.Now())) opt(&callOpts) } // should we noop right here? select { case <-ctx.Done(): return nil, errors.New("go.micro.client", fmt.Sprintf("%v", ctx.Err()), 408) default: } call := func(i int) (client.Streamer, error) { // call backoff first. Someone may want an initial start delay t, err := callOpts.Backoff(ctx, req, i) if err != nil { return nil, errors.InternalServerError("go.micro.client", err.Error()) } // only sleep if greater than 0 if t.Seconds() > 0 { time.Sleep(t) } node, err := next() if err != nil && err == selector.ErrNotFound { return nil, errors.NotFound("go.micro.client", err.Error()) } else if err != nil { return nil, errors.InternalServerError("go.micro.client", err.Error()) } addr := node.Address if node.Port > 0 { addr = fmt.Sprintf("%s:%d", addr, node.Port) } stream, err := g.stream(ctx, addr, req, callOpts) g.opts.Selector.Mark(req.Service(), node, err) return stream, err } type response struct { stream client.Streamer err error } ch := make(chan response, callOpts.Retries) var grr error for i := 0; i < callOpts.Retries; i++ { go func() { s, err := call(i) ch <- response{s, err} }() select { case <-ctx.Done(): return nil, errors.New("go.micro.client", fmt.Sprintf("%v", ctx.Err()), 408) case rsp := <-ch: // if the call succeeded lets bail early if rsp.err == nil { return rsp.stream, nil } retry, rerr := callOpts.Retry(ctx, req, i, err) if rerr != nil { return nil, rerr } if !retry { return nil, rsp.err } grr = rsp.err } } return nil, grr }
func (g *grpcClient) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { // make a copy of call opts callOpts := g.opts.CallOptions for _, opt := range opts { opt(&callOpts) } // get next nodes from the selector next, err := g.opts.Selector.Select(req.Service(), callOpts.SelectOptions...) if err != nil && err == selector.ErrNotFound { return errors.NotFound("go.micro.client", err.Error()) } else if err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } // check if we already have a deadline d, ok := ctx.Deadline() if !ok { // no deadline so we create a new one ctx, _ = context.WithTimeout(ctx, callOpts.RequestTimeout) } else { // got a deadline so no need to setup context // but we need to set the timeout we pass along opt := client.WithRequestTimeout(d.Sub(time.Now())) opt(&callOpts) } // should we noop right here? select { case <-ctx.Done(): return errors.New("go.micro.client", fmt.Sprintf("%v", ctx.Err()), 408) default: } // make copy of call method gcall := g.call // wrap the call in reverse for i := len(callOpts.CallWrappers); i > 0; i-- { gcall = callOpts.CallWrappers[i-1](gcall) } // return errors.New("go.micro.client", "request timeout", 408) call := func(i int) error { // call backoff first. Someone may want an initial start delay t, err := callOpts.Backoff(ctx, req, i) if err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } // only sleep if greater than 0 if t.Seconds() > 0 { time.Sleep(t) } // select next node node, err := next() if err != nil && err == selector.ErrNotFound { return errors.NotFound("go.micro.client", err.Error()) } else if err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } // set the address addr := node.Address if node.Port > 0 { addr = fmt.Sprintf("%s:%d", addr, node.Port) } // make the call err = gcall(ctx, addr, req, rsp, callOpts) g.opts.Selector.Mark(req.Service(), node, err) return err } ch := make(chan error, callOpts.Retries) var gerr error for i := 0; i < callOpts.Retries; i++ { go func() { ch <- call(i) }() select { case <-ctx.Done(): return errors.New("go.micro.client", fmt.Sprintf("%v", ctx.Err()), 408) case err := <-ch: // if the call succeeded lets bail early if err == nil { return nil } retry, rerr := callOpts.Retry(ctx, req, i, err) if rerr != nil { return rerr } if !retry { return err } gerr = err } } return gerr }
func (c *clientWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { return hystrix.Do(req.Service()+"."+req.Method(), func() error { return c.Client.Call(ctx, req, rsp, opts...) }, nil) }
func (l *logWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { md, _ := c.GetMetadata(ctx) fmt.Printf("[Log Wrapper] ctx: %v service: %s method: %s\n", md, req.Service(), req.Method()) return l.Client.Call(ctx, req, rsp) }