void t_js_generator::generate_service_client()

in thrift/compiler/generate/t_js_generator.cc [979:1226]


void t_js_generator::generate_service_client(const t_service* tservice) {
  string extends = "";

  if (gen_node_) {
    f_service_ << js_namespace(tservice->program()) << service_name_
               << "Client = "
               << "exports.Client = function(output, pClass) {" << endl;
  } else {
    f_service_ << js_namespace(tservice->program()) << service_name_
               << "Client = function(input, output) {" << endl;
  }

  indent_up();

  if (gen_node_) {
    f_service_ << indent() << "  this.output = output;" << endl
               << indent() << "  this.pClass = pClass;" << endl
               << indent() << "  this.seqid = 0;" << endl
               << indent() << "  this._reqs = {};" << endl;
  } else {
    f_service_ << indent() << "  this.input = input;" << endl
               << indent() << "  this.output = (!output) ? input : output;"
               << endl
               << indent() << "  this.seqid = 0;" << endl;
  }

  indent_down();

  f_service_ << indent() << "};" << endl;

  if (tservice->get_extends() != nullptr) {
    indent(f_service_) << "Thrift.inherits("
                       << js_namespace(tservice->program()) << service_name_
                       << "Client, " << tservice->get_extends()->get_name()
                       << "Client)" << endl;
  } else {
    // init prototype
    indent(f_service_) << js_namespace(tservice->program()) << service_name_
                       << "Client.prototype = {};" << endl;
  }

  // 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) {
    const t_struct* arg_struct = (*f_iter)->get_paramlist();
    const vector<t_field*>& fields = arg_struct->get_members();
    vector<t_field*>::const_iterator fld_iter;
    string funname = (*f_iter)->get_name();
    string arglist = argument_list(arg_struct);

    // Open function
    f_service_ << js_namespace(tservice->program()) << service_name_
               << "Client.prototype."
               << function_signature(*f_iter, "", gen_node_ || gen_jquery_)
               << " {" << endl;

    indent_up();

    if (gen_node_) {
      f_service_ << indent() << "this.seqid += 1;" << endl
                 << indent() << "this._reqs[this.seqid] = callback;" << endl;
    } else if (gen_jquery_) {
      f_service_ << indent() << "if (callback === undefined) {" << endl;
      indent_up();
    }

    f_service_ << indent() << "this.send_" << funname << "(" << arglist << ");"
               << endl;

    if (!gen_node_ && (*f_iter)->qualifier() != t_function_qualifier::one_way) {
      f_service_ << indent();
      if (!(*f_iter)->get_returntype()->is_void()) {
        f_service_ << "return ";
      }
      f_service_ << "this.recv_" << funname << "();" << endl;
    }

    if (gen_jquery_) {
      indent_down();
      f_service_ << indent() << "} else {" << endl;
      indent_up();
      f_service_ << indent() << "var postData = this.send_" << funname << "("
                 << arglist << (arglist.empty() ? "" : ", ") << "true);"
                 << endl;
      f_service_ << indent() << "return this.output.getTransport()" << endl;
      indent_up();
      f_service_ << indent()
                 << ".jqRequest(this, postData, arguments, this.recv_"
                 << funname << ");" << endl;
      indent_down();
      indent_down();
      f_service_ << indent() << "}" << endl;
    }

    indent_down();

    f_service_ << "};" << endl << endl;

    // Send function
    f_service_ << js_namespace(tservice->program()) << service_name_
               << "Client.prototype.send_"
               << function_signature(*f_iter, "", gen_jquery_) << " {" << endl;

    indent_up();

    std::string outputVar;
    if (gen_node_) {
      f_service_ << indent() << "var output = new this.pClass(this.output);"
                 << endl;
      outputVar = "output";
    } else {
      outputVar = "this.output";
    }

    std::string argsname = js_namespace(program_) + service_name_ + "_" +
        (*f_iter)->get_name() + "_args";

    // Serialize the request header
    f_service_ << indent() << outputVar << ".writeMessageBegin('"
               << (*f_iter)->get_name()
               << "', Thrift.MessageType.CALL, this.seqid);" << endl;

    f_service_ << indent() << "var args = new " << argsname << "();" << endl;

    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
      f_service_ << indent() << "args." << (*fld_iter)->get_name() << " = "
                 << (*fld_iter)->get_name() << ";" << endl;
    }

    // Write to the stream
    f_service_ << indent() << "args.write(" << outputVar << ");" << endl
               << indent() << outputVar << ".writeMessageEnd();" << endl;

    if (gen_node_) {
      f_service_ << indent() << "return this.output.flush();" << endl;
    } else {
      if (gen_jquery_) {
        f_service_ << indent()
                   << "return this.output.getTransport().flush(callback);"
                   << endl;
      } else {
        f_service_ << indent() << "return this.output.getTransport().flush();"
                   << endl;
      }
    }

    indent_down();

    f_service_ << "};" << endl;

    if ((*f_iter)->qualifier() != t_function_qualifier::one_way) {
      std::string resultname = js_namespace(tservice->program()) +
          service_name_ + "_" + (*f_iter)->get_name() + "_result";

      if (gen_node_) {
        // Open function
        f_service_ << endl
                   << js_namespace(tservice->program()) << service_name_
                   << "Client.prototype.recv_" << (*f_iter)->get_name()
                   << " = function(input,mtype,rseqid) {" << endl;
      } else {
        t_function recv_function(
            (*f_iter)->get_returntype(),
            string("recv_") + (*f_iter)->get_name(),
            std::make_unique<t_paramlist>(program_));
        // Open function
        f_service_ << endl
                   << js_namespace(tservice->program()) << service_name_
                   << "Client.prototype." << function_signature(&recv_function)
                   << " {" << endl;
      }

      indent_up();

      std::string inputVar;
      if (gen_node_) {
        inputVar = "input";
      } else {
        inputVar = "this.input";
      }

      if (gen_node_) {
        f_service_ << indent()
                   << "var callback = this._reqs[rseqid] || function() {};"
                   << endl
                   << indent() << "delete this._reqs[rseqid];" << endl;
      } else {
        f_service_ << indent() << "var ret = this.input.readMessageBegin();"
                   << endl
                   << indent() << "var fname = ret.fname;" << endl
                   << indent() << "var mtype = ret.mtype;" << endl
                   << indent() << "var rseqid = ret.rseqid;" << endl;
      }

      f_service_ << indent() << "if (mtype == Thrift.MessageType.EXCEPTION) {"
                 << endl
                 << indent() << "  var x = new Thrift.TApplicationException();"
                 << endl
                 << indent() << "  x.read(" << inputVar << ");" << endl
                 << indent() << "  " << inputVar << ".readMessageEnd();" << endl
                 << indent() << "  " << render_recv_throw("x") << endl
                 << indent() << "}" << endl;

      f_service_ << indent() << "var result = new " << resultname << "();"
                 << endl
                 << indent() << "result.read(" << inputVar << ");" << endl;

      f_service_ << indent() << inputVar << ".readMessageEnd();" << endl
                 << endl;

      const t_struct* xs = (*f_iter)->get_xceptions();
      const std::vector<t_field*>& xceptions = xs->get_members();
      vector<t_field*>::const_iterator x_iter;
      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
        f_service_ << indent() << "if (null !== result."
                   << (*x_iter)->get_name() << ") {" << endl
                   << indent() << "  "
                   << render_recv_throw("result." + (*x_iter)->get_name())
                   << endl
                   << indent() << "}" << endl;
      }

      // Careful, only return result if not a void function
      if (!(*f_iter)->get_returntype()->is_void()) {
        f_service_ << indent() << "if (null !== result.success) {" << endl
                   << indent() << "  " << render_recv_return("result.success")
                   << endl
                   << indent() << "}" << endl;
        f_service_ << indent()
                   << render_recv_throw(
                          "'" + (*f_iter)->get_name() +
                          " failed: unknown result'")
                   << endl;
      } else {
        if (gen_node_) {
          indent(f_service_) << "callback(null)" << endl;
        } else {
          indent(f_service_) << "return;" << endl;
        }
      }

      // Close function
      indent_down();
      f_service_ << "};" << endl;
    }
  }
}