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); } }
void Connection::handleError(const boost::system::error_code& error) { if(error != asio::error::operation_aborted) { m_error = error; if(m_errorCallback) m_errorCallback(error); if(m_connected || m_connecting) close(); } }
task<bool> SandboxJSExecutor::ConnectAsync(std::shared_ptr<SandboxEndpoint> endpoint, const std::function<void(std::string)>& errorCallback) { m_errorCallback = std::move(errorCallback); auto t = task_from_result(); return t.then([=]() -> bool { int retryCount = ConnectRetryCount; while (true) { try { cancellation_token_source timer_cts; auto timeoutT = create_delayed_task(std::chrono::milliseconds(ConnectTimeoutMilliseconds), [=]() -> string { throw std::runtime_error("timeout"); }, timer_cts.get_token()); if (!IsConnected()) { try { m_sandboxEndpoint = nullptr; } catch (std::exception& /*e*/) { // Don't care what happens with the old client at this point } // TODO: Pass as param m_sandboxEndpoint = endpoint; m_sandboxEndpoint->RegisterReplyHandler([this](int64_t replyId) { OnReplyMessage(replyId); }); m_sandboxEndpoint->RegisterNativeModuleCallHandler([this](folly::dynamic&& calls) { OnNativeModuleCallMessage(std::move(calls)); }); if (m_sandboxEndpoint->Start(EndpointType::Host)) { SetState(State::Connected); timer_cts.cancel(); } } else { PrepareJavaScriptRuntimeAsync().then([=](bool success) { if (success) { SetState(State::Running); timer_cts.cancel(); } else { SetState(State::Error); } }); } auto status = timeoutT.wait(); if (status != canceled) { throw new std::exception("Timeout"); } if (IsRunning()) { return true; } } catch (std::exception& /*e*/) { retryCount--; if (retryCount == 0) { m_errorCallback(IsConnected() ? "Timeout: preparing JS runtime" : "Timeout: Failed to connect to dev server"); SetState(State::Error); return false; } } } }); }