in compiler/cpp/src/thrift/generate/t_go_generator.cc [2057:2286]
void t_go_generator::generate_service_client(t_service* tservice) {
string extends = "";
string extends_field = "";
string extends_client = "";
string extends_client_new = "";
string serviceName(publicize(tservice->get_name()));
if (tservice->get_extends() != nullptr) {
extends = type_name(tservice->get_extends());
size_t index = extends.rfind(".");
if (index != string::npos) {
extends_client = extends.substr(0, index + 1) + publicize(extends.substr(index + 1))
+ "Client";
extends_client_new = extends.substr(0, index + 1) + "New"
+ publicize(extends.substr(index + 1)) + "Client";
} else {
extends_client = publicize(extends) + "Client";
extends_client_new = "New" + extends_client;
}
}
extends_field = extends_client.substr(extends_client.find(".") + 1);
generate_go_docstring(f_types_, tservice);
generate_deprecation_comment(f_types_, tservice->annotations_);
f_types_ << indent() << "type " << serviceName << "Client struct {" << '\n';
indent_up();
if (!extends_client.empty()) {
f_types_ << indent() << "*" << extends_client << '\n';
} else {
f_types_ << indent() << "c thrift.TClient" << '\n';
f_types_ << indent() << "meta thrift.ResponseMeta" << '\n';
}
indent_down();
f_types_ << indent() << "}" << '\n' << '\n';
// Legacy constructor function
generate_deprecation_comment(f_types_, tservice->annotations_);
f_types_ << indent() << "func New" << serviceName
<< "ClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *" << serviceName
<< "Client {" << '\n';
indent_up();
f_types_ << indent() << "return &" << serviceName << "Client";
if (!extends.empty()) {
f_types_ << "{" << extends_field << ": " << extends_client_new << "Factory(t, f)}";
} else {
indent_up();
f_types_ << "{" << '\n';
f_types_ << indent() << "c: thrift.NewTStandardClient(f.GetProtocol(t), f.GetProtocol(t))," << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
}
indent_down();
f_types_ << indent() << "}" << '\n' << '\n';
// Legacy constructor function with custom input & output protocols
generate_deprecation_comment(f_types_, tservice->annotations_);
f_types_
<< indent() << "func New" << serviceName
<< "ClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *"
<< serviceName << "Client {" << '\n';
indent_up();
f_types_ << indent() << "return &" << serviceName << "Client";
if (!extends.empty()) {
f_types_ << "{" << extends_field << ": " << extends_client_new << "Protocol(t, iprot, oprot)}"
<< '\n';
} else {
indent_up();
f_types_ << "{" << '\n';
f_types_ << indent() << "c: thrift.NewTStandardClient(iprot, oprot)," << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
}
indent_down();
f_types_ << indent() << "}" << '\n' << '\n';
// Constructor function
generate_deprecation_comment(f_types_, tservice->annotations_);
f_types_ << indent() << "func New" << serviceName
<< "Client(c thrift.TClient) *" << serviceName << "Client {" << '\n';
indent_up();
f_types_ << indent() << "return &" << serviceName << "Client{" << '\n';
indent_up();
if (!extends.empty()) {
f_types_ << indent() << extends_field << ": " << extends_client_new << "(c)," << '\n';
} else {
f_types_ << indent() << "c: c," << '\n';
}
indent_down();
f_types_ << indent() << "}" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n' << '\n';
if (extends.empty()) {
f_types_ << indent() << "func (p *" << serviceName << "Client) Client_() thrift.TClient {" << '\n';
indent_up();
f_types_ << indent() << "return p.c" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n' << '\n';
f_types_ << indent() << "func (p *" << serviceName << "Client) LastResponseMeta_() thrift.ResponseMeta {" << '\n';
indent_up();
f_types_ << indent() << "return p.meta" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n' << '\n';
f_types_ << indent() << "func (p *" << serviceName << "Client) SetLastResponseMeta_(meta thrift.ResponseMeta) {" << '\n';
indent_up();
f_types_ << indent() << "p.meta = meta" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n' << '\n';
}
// Generate client method implementations
vector<t_function*> functions = tservice->get_functions();
vector<t_function*>::const_iterator f_iter;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
t_struct* arg_struct = (*f_iter)->get_arglist();
const vector<t_field*>& fields = arg_struct->get_members();
vector<t_field*>::const_iterator fld_iter;
string funname = publicize((*f_iter)->get_name());
// Open function
generate_go_docstring(f_types_, (*f_iter));
generate_deprecation_comment(f_types_, (*f_iter)->annotations_);
f_types_ << indent() << "func (p *" << serviceName << "Client) "
<< function_signature_if(*f_iter, "", true) << " {" << '\n';
indent_up();
std::string method = (*f_iter)->get_name();
std::string argsType = publicize(method + "_args", true);
std::string argsName = tmp("_args");
f_types_ << indent() << "var " << argsName << " " << argsType << '\n';
for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
f_types_ << indent() << argsName << "." << publicize((*fld_iter)->get_name())
<< " = " << variable_name_to_go_name((*fld_iter)->get_name()) << '\n';
}
if (!(*f_iter)->is_oneway()) {
std::string metaName = tmp("_meta");
std::string resultName = tmp("_result");
std::string resultType = publicize(method + "_result", true);
f_types_ << indent() << "var " << resultName << " " << resultType << '\n';
f_types_ << indent() << "var " << metaName << " thrift.ResponseMeta" << '\n';
f_types_ << indent() << metaName << ", _err = p.Client_().Call(ctx, \""
<< method << "\", &" << argsName << ", &" << resultName << ")" << '\n';
f_types_ << indent() << "p.SetLastResponseMeta_(" << metaName << ")" << '\n';
f_types_ << indent() << "if _err != nil {" << '\n';
indent_up();
f_types_ << indent() << "return" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
t_struct* xs = (*f_iter)->get_xceptions();
const std::vector<t_field*>& xceptions = xs->get_members();
vector<t_field*>::const_iterator x_iter;
if (!xceptions.empty()) {
f_types_ << indent() << "switch {" << '\n';
for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
const std::string pubname = publicize((*x_iter)->get_name());
const std::string field = resultName + "." + pubname;
f_types_ << indent() << "case " << field << "!= nil:" << '\n';
indent_up();
if (!(*f_iter)->get_returntype()->is_void()) {
f_types_ << indent() << "return _r, " << field << '\n';
} else {
f_types_ << indent() << "return "<< field << '\n';
}
indent_down();
}
f_types_ << indent() << "}" << '\n' << '\n';
}
if ((*f_iter)->get_returntype()->is_struct()) {
// Check if the result is nil, which likely means we have a new
// exception added but unknown to the client yet
// (e.g. client hasn't updated the thrift file).
// Sadly this check can only be reliable done when the return type is a
// struct in go.
std::string retName = tmp("_ret");
f_types_ << indent() << "if " << retName << " := " << resultName
<< ".GetSuccess(); " << retName << " != nil {" << '\n';
indent_up();
f_types_ << indent() << "return " << retName << ", nil" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
f_types_ << indent() << "return nil, "
<< "thrift.NewTApplicationException(thrift.MISSING_RESULT, \""
<< method << " failed: unknown result\")" << '\n';
} else if (!(*f_iter)->get_returntype()->is_void()) {
f_types_ << indent() << "return " << resultName << ".GetSuccess(), nil" << '\n';
} else {
f_types_ << indent() << "return nil" << '\n';
}
} else {
// Since we don't have response meta for oneway calls, overwrite it with
// an empty one to avoid users getting the meta from last call and
// mistaken it as from the oneway call.
f_types_ << indent() << "p.SetLastResponseMeta_(thrift.ResponseMeta{})" << '\n';
// TODO: would be nice to not to duplicate the call generation
f_types_ << indent() << "if _, err := p.Client_().Call(ctx, \""
<< method << "\", &" << argsName << ", nil); err != nil {" << '\n';
indent_up();
f_types_ << indent() << "return err" << '\n';
indent_down();
f_types_ << indent() << "}" << '\n';
f_types_ << indent() << "return nil" << '\n';
}
indent_down();
f_types_ << "}" << '\n' << '\n';
}
}