in compiler/cpp/src/thrift/generate/t_go_generator.cc [2997:3293]
void t_go_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
// Open function
string processorName = privatize(tservice->get_name()) + "Processor"
+ publicize(tfunction->get_name());
string argsname = publicize(tfunction->get_name() + "_args", true);
string resultname = publicize(tfunction->get_name() + "_result", true);
// t_struct* xs = tfunction->get_xceptions();
// const std::vector<t_field*>& xceptions = xs->get_members();
f_types_ << indent() << "type " << processorName << " struct {" << '\n';
indent_up();
f_types_ << indent() << "handler " << publicize(tservice->get_name()) << '\n';
indent_down();
f_types_ << indent() << "}" << '\n' << '\n';
f_types_ << indent() << "func (p *" << processorName
<< ") Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err "
"thrift.TException) {" << '\n';
indent_up();
string write_err;
if (!tfunction->is_oneway()) {
write_err = tmp("_write_err");
f_types_ << indent() << "var " << write_err << " thrift.TException" << '\n';
}
f_types_ << indent() << "args := " << argsname << "{}" << '\n';
f_types_ << indent() << "if err2 := args." << read_method_name_ << "(ctx, iprot); err2 != nil {" << '\n';
indent_up();
f_types_ << indent() << "iprot.ReadMessageEnd(ctx)" << '\n';
if (!tfunction->is_oneway()) {
f_types_ << indent()
<< "x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err2.Error())"
<< '\n';
f_types_ << indent() << "oprot.WriteMessageBegin(ctx, \"" << escape_string(tfunction->get_name())
<< "\", thrift.EXCEPTION, seqId)" << '\n';
f_types_ << indent() << "x.Write(ctx, oprot)" << '\n';
f_types_ << indent() << "oprot.WriteMessageEnd(ctx)" << '\n';
f_types_ << indent() << "oprot.Flush(ctx)" << '\n';
}
f_types_ << indent() << "return false, thrift.WrapTException(err2)" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
f_types_ << indent() << "iprot.ReadMessageEnd(ctx)" << '\n' << '\n';
// Even though we never create the goroutine in oneway handlers,
// always have (nop) tickerCancel defined makes the writing part of code
// generating easier and less error-prone.
f_types_ << indent() << "tickerCancel := func() {}" << '\n';
// Only create the goroutine for non-oneways.
if (!tfunction->is_oneway()) {
f_types_ << indent() << "// Start a goroutine to do server side connectivity check." << '\n';
f_types_ << indent() << "if thrift.ServerConnectivityCheckInterval > 0 {" << '\n';
indent_up();
f_types_ << indent() << "var cancel context.CancelCauseFunc" << '\n';
f_types_ << indent() << "ctx, cancel = context.WithCancelCause(ctx)" << '\n';
f_types_ << indent() << "defer cancel(nil)" << '\n';
f_types_ << indent() << "var tickerCtx context.Context" << '\n';
f_types_ << indent() << "tickerCtx, tickerCancel = context.WithCancel(context.Background())" << '\n';
f_types_ << indent() << "defer tickerCancel()" << '\n';
f_types_ << indent() << "go func(ctx context.Context, cancel context.CancelCauseFunc) {" << '\n';
indent_up();
f_types_ << indent() << "ticker := time.NewTicker(thrift.ServerConnectivityCheckInterval)" << '\n';
f_types_ << indent() << "defer ticker.Stop()" << '\n';
f_types_ << indent() << "for {" << '\n';
indent_up();
f_types_ << indent() << "select {" << '\n';
f_types_ << indent() << "case <-ctx.Done():" << '\n';
indent_up();
f_types_ << indent() << "return" << '\n';
indent_down();
f_types_ << indent() << "case <-ticker.C:" << '\n';
indent_up();
f_types_ << indent() << "if !iprot.Transport().IsOpen() {" << '\n';
indent_up();
f_types_ << indent() << "cancel(thrift.ErrAbandonRequest)" << '\n';
f_types_ << indent() << "return" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
indent_down();
f_types_ << indent() << "}(tickerCtx, cancel)" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n' << '\n';
} else {
// Make sure we don't get the defined but unused compiling error.
f_types_ << indent() << "_ = tickerCancel" << '\n' << '\n';
}
if (!tfunction->is_oneway()) {
f_types_ << indent() << "result := " << resultname << "{}" << '\n';
}
bool need_reference = type_need_reference(tfunction->get_returntype());
f_types_ << indent() << "if ";
if (!tfunction->is_oneway()) {
if (!tfunction->get_returntype()->is_void()) {
f_types_ << "retval, ";
}
}
// Generate the function call
t_struct* arg_struct = tfunction->get_arglist();
const std::vector<t_field*>& fields = arg_struct->get_members();
vector<t_field*>::const_iterator f_iter;
f_types_ << "err2 := p.handler." << publicize(tfunction->get_name()) << "(";
bool first = true;
f_types_ << "ctx";
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
if (first) {
first = false;
f_types_ << ", ";
} else {
f_types_ << ", ";
}
f_types_ << "args." << publicize((*f_iter)->get_name());
}
f_types_ << "); err2 != nil {" << '\n';
indent_up();
f_types_ << indent() << "tickerCancel()" << '\n';
f_types_ << indent() << "err = thrift.WrapTException(err2)" << '\n';
t_struct* exceptions = tfunction->get_xceptions();
const vector<t_field*>& x_fields = exceptions->get_members();
if (!x_fields.empty()) {
f_types_ << indent() << "switch v := err2.(type) {" << '\n';
vector<t_field*>::const_iterator xf_iter;
for (xf_iter = x_fields.begin(); xf_iter != x_fields.end(); ++xf_iter) {
f_types_ << indent() << "case " << type_to_go_type(((*xf_iter)->get_type())) << ":"
<< '\n';
indent_up();
f_types_ << indent() << "result." << publicize((*xf_iter)->get_name()) << " = v" << '\n';
indent_down();
}
f_types_ << indent() << "default:" << '\n';
indent_up();
}
if (!tfunction->is_oneway()) {
// Avoid writing the error to the wire if it's ErrAbandonRequest
f_types_ << indent() << "if errors.Is(err2, thrift.ErrAbandonRequest) {" << '\n';
indent_up();
f_types_ << indent() << "return false, &thrift.ProcessorError{" << '\n';
indent_up();
f_types_ << indent() << "WriteError: thrift.WrapTException(err2)," << '\n';
f_types_ << indent() << "EndpointError: err," << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
f_types_ << indent() << "if errors.Is(err2, context.Canceled) {" << '\n';
indent_up();
f_types_ << indent() << "if err3 := context.Cause(ctx); errors.Is(err3, thrift.ErrAbandonRequest) {" << '\n';
indent_up();
f_types_ << indent() << "return false, &thrift.ProcessorError{" << '\n';
indent_up();
f_types_ << indent() << "WriteError: thrift.WrapTException(err3)," << '\n';
f_types_ << indent() << "EndpointError: err," << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
string exc(tmp("_exc"));
f_types_ << indent() << exc << " := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "
"\"Internal error processing " << escape_string(tfunction->get_name())
<< ": \" + err2.Error())" << '\n';
f_types_ << indent() << "if err2 := oprot.WriteMessageBegin(ctx, \"" << escape_string(tfunction->get_name())
<< "\", thrift.EXCEPTION, seqId); err2 != nil {" << '\n';
indent_up();
f_types_ << indent() << write_err << " = thrift.WrapTException(err2)" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
f_types_ << indent() << "if err2 := " << exc << ".Write(ctx, oprot); "
<< write_err << " == nil && err2 != nil {" << '\n';
indent_up();
f_types_ << indent() << write_err << " = thrift.WrapTException(err2)" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
f_types_ << indent() << "if err2 := oprot.WriteMessageEnd(ctx); "
<< write_err << " == nil && err2 != nil {" << '\n';
indent_up();
f_types_ << indent() << write_err << " = thrift.WrapTException(err2)" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
f_types_ << indent() << "if err2 := oprot.Flush(ctx); "
<< write_err << " == nil && err2 != nil {" << '\n';
indent_up();
f_types_ << indent() << write_err << " = thrift.WrapTException(err2)" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
f_types_ << indent() << "if " << write_err << " != nil {" << '\n';
indent_up();
f_types_ << indent() << "return false, &thrift.ProcessorError{" << '\n';
indent_up();
f_types_ << indent() << "WriteError: " << write_err << "," << '\n';
f_types_ << indent() << "EndpointError: err," << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
// return success=true as long as writing to the wire was successful.
f_types_ << indent() << "return true, err" << '\n';
}
if (!x_fields.empty()) {
indent_down();
f_types_ << indent() << "}" << '\n'; // closes switch
}
indent_down();
f_types_ << indent() << "}"; // closes err2 != nil
if (!tfunction->is_oneway()) {
if (!tfunction->get_returntype()->is_void()) {
f_types_ << " else {" << '\n'; // make sure we set Success retval only on success
indent_up();
f_types_ << indent() << "result.Success = ";
if (need_reference) {
f_types_ << "&";
}
f_types_ << "retval" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
} else {
f_types_ << '\n';
}
f_types_ << indent() << "tickerCancel()" << '\n';
f_types_ << indent() << "if err2 := oprot.WriteMessageBegin(ctx, \""
<< escape_string(tfunction->get_name()) << "\", thrift.REPLY, seqId); err2 != nil {"
<< '\n';
indent_up();
f_types_ << indent() << write_err << " = thrift.WrapTException(err2)" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
f_types_ << indent() << "if err2 := result." << write_method_name_ << "(ctx, oprot); "
<< write_err << " == nil && err2 != nil {" << '\n';
indent_up();
f_types_ << indent() << write_err << " = thrift.WrapTException(err2)" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
f_types_ << indent() << "if err2 := oprot.WriteMessageEnd(ctx); "
<< write_err << " == nil && err2 != nil {" << '\n';
indent_up();
f_types_ << indent() << write_err << " = thrift.WrapTException(err2)" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
f_types_ << indent() << "if err2 := oprot.Flush(ctx); " << write_err << " == nil && err2 != nil {" << '\n';
indent_up();
f_types_ << indent() << write_err << " = thrift.WrapTException(err2)" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
f_types_ << indent() << "if " << write_err << " != nil {" << '\n';
indent_up();
f_types_ << indent() << "return false, &thrift.ProcessorError{" << '\n';
indent_up();
f_types_ << indent() << "WriteError: " << write_err << "," << '\n';
f_types_ << indent() << "EndpointError: err," << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
// return success=true as long as writing to the wire was successful.
f_types_ << indent() << "return true, err" << '\n';
} else {
f_types_ << '\n';
f_types_ << indent() << "tickerCancel()" << '\n';
f_types_ << indent() << "return true, err" << '\n';
}
indent_down();
f_types_ << indent() << "}" << '\n' << '\n';
}