in json/handler.go [127:177]
func (h *handler) Handle(tctx context.Context, call *tchannel.InboundCall) error {
var headers map[string]string
if err := tchannel.NewArgReader(call.Arg2Reader()).ReadJSON(&headers); err != nil {
return fmt.Errorf("arg2 read failed: %v", err)
}
tctx = tchannel.ExtractInboundSpan(tctx, call, headers, h.tracer())
ctx := WithHeaders(tctx, headers)
var arg3 reflect.Value
var callArg reflect.Value
if h.isArgMap {
arg3 = reflect.New(h.argType)
// New returns a pointer, but the method accepts the map directly.
callArg = arg3.Elem()
} else {
arg3 = reflect.New(h.argType.Elem())
callArg = arg3
}
if err := tchannel.NewArgReader(call.Arg3Reader()).ReadJSON(arg3.Interface()); err != nil {
return fmt.Errorf("arg3 read failed: %v", err)
}
args := []reflect.Value{reflect.ValueOf(ctx), callArg}
results := h.handler.Call(args)
res := results[0].Interface()
err := results[1].Interface()
// If an error was returned, we create an error arg3 to respond with.
if err != nil {
// TODO(prashantv): More consistent error handling between json/raw/thrift..
if serr, ok := err.(tchannel.SystemError); ok {
return call.Response().SendSystemError(serr)
}
call.Response().SetApplicationError()
// TODO(prashant): Allow client to customize the error in more ways.
res = struct {
Type string `json:"type"`
Message string `json:"message"`
}{
Type: "error",
Message: err.(error).Error(),
}
}
if err := tchannel.NewArgWriter(call.Response().Arg2Writer()).WriteJSON(ctx.ResponseHeaders()); err != nil {
return err
}
return tchannel.NewArgWriter(call.Response().Arg3Writer()).WriteJSON(res)
}