void SandboxJSExecutor::loadApplicationScript(std::unique_ptr<const JSBigString> script, uint64_t /*scriptVersion*/, std::string sourceURL, std::string&& /*bytecodeFileName*/) {
  auto requestId = GetNextRequestId();
  task_completion_event<void> callback;
  m_callbacks.emplace(requestId, callback);

  folly::dynamic request = folly::dynamic::object
    ("script", script->c_str())
    ("inject", m_injectedObjects)
    ("url", sourceURL);

  try {
    SendMessageAsync(requestId, "executeApplicationScript", request).then([callback](bool success) {
      if (success) {
        // Return task to wait for reply.
        return task<void>(callback);
      } else {
        throw new exception("Failed to send");
      }
    }).get();
  }
  //TODO: handle exceptions in a better way
  catch (exception& e) {
    m_errorCallback(e.what());
    SetState(State::Error);
  }
}
// NOTE: This function synchronously waiting until get reply back from the sandbox.
// TODO: Indefinite waiting can cause SDX to become unresponsive. We need to implement timeout mechanism.
void SandboxJSExecutor::Call(const std::string& methodName, folly::dynamic& arguments) {
  auto requestId = GetNextRequestId();
  task_completion_event<void> callback;
  m_callbacks.emplace(requestId, callback);

  try {
    std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();

    SendMessageAsync(requestId, methodName, arguments).then([callback](bool sent) {
      if (sent) {
        // Return task to wait for reply.
        return task<void>(callback);
      } else {
        throw new exception("Failed to send");
      }
    }).get();  // wait until get reply

    std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count();

    char buffer[256];
    sprintf_s(buffer, "(%03I64d) CallFunction, elapsed time = %d us\n", requestId, (int)duration);
    OutputDebugStringA(buffer);
  }
  //TODO: handle exceptions in a better way
  catch (exception& e) {
    m_errorCallback(e.what());
    SetState(State::Error);
  }
}
task<bool> SandboxJSExecutor::PrepareJavaScriptRuntimeAsync() {
  task_completion_event<void> callback;
  auto requestId = GetNextRequestId();
  m_callbacks.emplace(requestId, callback);
  folly::dynamic argument;
  return SendMessageAsync(requestId, "prepareJSRuntime", argument);
}
mtpRequestId ConcurrentSender::RequestBuilder::send() {
	const auto requestId = GetNextRequestId();
	const auto dcId = _dcId;
	const auto msCanWait = _canWait;
	const auto afterRequestId = _afterRequestId;

	_sender->senderRequestRegister(requestId, std::move(_handlers));
	_sender->with_instance([
		=,
		request = std::move(_serialized),
		done = std::make_shared<RPCDoneHandler>(_sender, _sender->_runner),
		fail = std::make_shared<RPCFailHandler>(
			_sender,
			_sender->_runner,
			_failSkipPolicy)
	](not_null<Instance*> instance) mutable {
		instance->sendSerialized(
			requestId,
			std::move(request),
			RPCResponseHandler(std::move(done), std::move(fail)),
			dcId,
			msCanWait,
			afterRequestId);
	});

	return requestId;
}