void t_kotlin_generator::generate_service_process_function()

in compiler/cpp/src/thrift/generate/t_kotlin_generator.cc [1652:1827]


void t_kotlin_generator::generate_service_process_function(ostream& out,
                                                           t_service* tservice,
                                                           t_function* tfunc) {
  string args_name = tservice->get_name() + "FunctionArgs." + tfunc->get_name() + "_args";
  string rtype = type_name(tfunc->get_returntype(), true);
  string resultname = tservice->get_name() + "FunctionResult." + tfunc->get_name() + "_result";

  indent(out) << "class " << tfunc->get_name() << "<I : " << tservice->get_name()
              << ">(private val scope: kotlinx.coroutines.CoroutineScope) : "
                 "org.apache.thrift.AsyncProcessFunction<I, "
              << args_name << ", " << rtype << ", "
              << (tfunc->is_oneway() ? "org.apache.thrift.TBase<*, *>" : resultname)
              << ">(\"" << tfunc->get_name() << "\"), ProcessFunction {"
              << '\n';
  indent_up();
  {
    indent(out) << "override fun isOneway() = " << (tfunc->is_oneway() ? "true" : "false") << '\n';
    indent(out) << "override fun getEmptyArgsInstance() = " << args_name << "()" << '\n';
    indent(out) << "override fun getEmptyResultInstance() = ";
    if (tfunc->is_oneway()) {
      out << "null" << '\n';
    }
    else {
      out << resultname << "()" << '\n';
    }
    indent(out) << '\n';
    indent(out) << "override fun start(iface: I, args: " << args_name
                << ", resultHandler: org.apache.thrift.async.AsyncMethodCallback<" << rtype
                << ">) {" << '\n';
    indent_up();
    indent(out) << "scope.future {" << '\n';
    indent_up();
    indent(out) << "iface." << tfunc->get_name() << "(";
    {
      auto arguments = tfunc->get_arglist();
      bool first = true;
      for (t_field* tfield : arguments->get_members()) {
        if (first) {
          first = false;
        } else {
          out << ", ";
        }
        out << "args." << tfield->get_name() << "!!";
      }
    }
    out << ")" << '\n';
    indent_down();
    indent(out) << "}.whenComplete { r, t ->" << '\n';
    {
      indent_up();
      indent(out) << "if (t != null) {" << '\n';
      indent_up();
      indent(out) << "resultHandler.onError(t as java.lang.Exception)" << '\n';
      indent_down();
      indent(out) << "} else {" << '\n';
      indent_up();
      indent(out) << "resultHandler.onComplete(r)" << '\n';
    }
    scope_down(out);
    scope_down(out);
    scope_down(out);

    indent(out) << "override fun getResultHandler(fb: "
                   "org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer, seqid: "
                   "Int) ="
                << '\n';
    indent_up();
    {
      indent(out) << "object : org.apache.thrift.async.AsyncMethodCallback<" << rtype << ">{"
                  << '\n';
      indent_up();
      {
        indent(out) << "override fun onComplete(response: " << rtype << ") {" << '\n';
        indent_up();
        if (tfunc->is_oneway()) {
          indent(out) << "// one way function, no result handling" << '\n';
        } else {
          string result_name
              = tservice->get_name() + "FunctionResult." + tfunc->get_name() + "_result";
          indent(out) << "val result = " << result_name << "()" << '\n';
          if (!tfunc->get_returntype()->is_void()) {
            indent(out) << "result.success = response" << '\n';
          }
          indent(out) << "try {" << '\n';
          indent_up();
          indent(out)
              << "sendResponse(fb, result, org.apache.thrift.protocol.TMessageType.REPLY, seqid)"
              << '\n';
          indent_down();
          indent(out) << "} catch (e: org.apache.thrift.transport.TTransportException) {" << '\n';
          indent_up();
          indent(out) << "logger.error(\"TTransportException writing to internal frame buffer\", e)"
                      << '\n';
          indent(out) << "fb.close()" << '\n';
          indent_down();
          indent(out) << "} catch (e: Exception) {" << '\n';
          indent_up();
          indent(out) << "logger.error(\"Exception writing to internal frame buffer\", e)" << '\n';
          indent(out) << "onError(e)" << '\n';
          scope_down(out);
        }
        scope_down(out);
      }
      {
        indent(out) << "override fun onError(exception: kotlin.Exception) {" << '\n';
        indent_up();
        if (tfunc->is_oneway()) {
          indent(out) << "if (exception is org.apache.thrift.transport.TTransportException) {"
                      << '\n';
          indent_up();
          indent(out) << "logger.error(\"TTransportException inside handler\", exception)" << '\n';
          indent(out) << "fb.close()" << '\n';
          indent_down();
          indent(out) << "} else {" << '\n';
          indent_up();
          indent(out) << "logger.error(\"Exception inside oneway handler\", exception)" << '\n';
          scope_down(out);
        } else {
          indent(out) << "val (msgType, msg) = when (exception) {" << '\n';
          indent_up();

          auto xceptions = tfunc->get_xceptions()->get_members();
          for (auto xception : xceptions) {
            indent(out) << "is " << type_name(xception->get_type()) << " -> {" << '\n';
            indent_up();
            string result_name
                = tservice->get_name() + "FunctionResult." + tfunc->get_name() + "_result";
            indent(out) << "val result = " << result_name << "()" << '\n';
            indent(out) << "result." << xception->get_name() << " = exception" << '\n';
            indent(out) << "org.apache.thrift.protocol.TMessageType.REPLY to result" << '\n';
            scope_down(out);
          }

          indent(out) << "is org.apache.thrift.transport.TTransportException -> {" << '\n';
          indent_up();
          indent(out) << "logger.error(\"TTransportException inside handler\", exception)" << '\n';
          indent(out) << "fb.close()" << '\n';
          indent(out) << "return" << '\n';
          scope_down(out);

          indent(out) << "is org.apache.thrift.TApplicationException -> {" << '\n';
          indent_up();
          indent(out) << "logger.error(\"TApplicationException inside handler\", exception)"
                      << '\n';
          indent(out) << "org.apache.thrift.protocol.TMessageType.EXCEPTION to exception" << '\n';
          scope_down(out);

          indent(out) << "else -> {" << '\n';
          indent_up();
          indent(out) << "logger.error(\"Exception inside handler\", exception)" << '\n';
          indent(out) << "org.apache.thrift.protocol.TMessageType.EXCEPTION to "
                         "org.apache.thrift.TApplicationException(org.apache.thrift."
                         "TApplicationException.INTERNAL_ERROR, exception.message)"
                      << '\n';
          scope_down(out);
          scope_down(out);

          indent(out) << "try {" << '\n';
          indent_up();
          indent(out) << "sendResponse(fb, msg, msgType, seqid)" << '\n';
          indent_down();
          indent(out) << "} catch (ex: java.lang.Exception) {" << '\n';
          indent_up();
          indent(out) << "logger.error(\"Exception writing to internal frame buffer\", ex)" << '\n';
          indent(out) << "fb.close()" << '\n';
          scope_down(out);
        }

        scope_down(out);
      }
      scope_down(out);
    }
    indent_down();
  }
  scope_down(out);
}