Botan::TLS::Channel::handshake_cb TlsPskAdaptor::handshakeCallback() { return [this](const Botan::TLS::Session& session) -> bool { KJ_LOG(INFO, "TLS handshake finished", session.ciphersuite().to_string()); handshakeCompletedFulfiller->fulfill(); return true; }; }
Botan::TLS::Channel::alert_cb TlsPskAdaptor::alertCallback() { return [this](Botan::TLS::Alert alert, const Botan::byte data[], size_t dataSize) { auto dataPtr = kj::ArrayPtr<const kj::byte>(reinterpret_cast<const kj::byte*>(data), dataSize); KJ_LOG(INFO, "TLS Alert", alert.type_string(), dataPtr, dataSize, alert.is_fatal(), alert.is_valid()); if (alert.is_fatal()) handleEof(); }; }
PurchaseWrapper* PurchaseContestRequestWrapper::submit() { updateContestants(); KJ_LOG(DBG, "Submitting purchase request", request, request.getRequest().getContestName()); auto promise = request.send(); auto purchase = promise.getPurchaseApi(); return new PurchaseWrapper(kj::mv(purchase), tasks, this); }
QJSValue DecisionGeneratorApi::getDecisions(int count) { if (count > std::numeric_limits<uint8_t>::max()) // Fail hard for this; the GUI should guarantee count is valid qFatal("Application bug: count must fit in a uint8_t"); KJ_LOG(DBG, "Requesting decisions", count); auto request = generator.getValuesRequest(); request.setCount(count); m_isFetchingDecisions = true; emit this->isFetchingDecisionsChanged(true); auto pass = [this](auto&& e) { KJ_DBG(e); m_isFetchingDecisions = false; emit this->isFetchingDecisionsChanged(false); return kj::mv(e); }; auto contestsPromise = request.send().then([this, count](capnp::Response<DecisionGenerator::GetValuesResults> r) { if (!r.hasValues() || r.getValues().size() < count) { m_isOutOfDecisions = true; emit this->isOutOfDecisionsChanged(true); } m_isFetchingDecisions = false; emit this->isFetchingDecisionsChanged(false); return kj::mv(r); }, pass); return converter.convert(kj::mv(contestsPromise), [](capnp::Response<DecisionGenerator::GetValuesResults> r) -> QVariant { KJ_LOG(DBG, "Got decisions", r.getValues().size()); QVariantList decisions; for (auto decisionWrapper : r.getValues()) { auto decision = decisionWrapper.getValue(); decisions.append( QVariantMap{ {"decisionId", QString(convertBlob(ReaderPacker(decision.getId()).array()).toHex())}, {"counted", decision.getCounted()} }); } return QVariant(decisions); }); }
QJSValue ContestGeneratorApi::getContests(int count) { KJ_LOG(DBG, "Requesting contests", count); auto request = generator.getValuesRequest(); request.setCount(count); m_isFetchingContests = true; emit this->isFetchingContestsChanged(true); auto pass = [this](auto&& e) { m_isFetchingContests = false; emit this->isFetchingContestsChanged(false); return kj::mv(e); }; auto contestsPromise = request.send().then([this, count](capnp::Response<ContestGenerator::GetValuesResults> r) { if (!r.hasValues() || r.getValues().size() < count) { m_isOutOfContests = true; emit this->isOutOfContestsChanged(true); } m_isFetchingContests = false; emit this->isFetchingContestsChanged(false); return kj::mv(r); }, pass); return converter.convert(kj::mv(contestsPromise), [this](capnp::Response<ContestGenerator::GetValuesResults> r) -> QVariant { KJ_LOG(DBG, "Got contests", r.getValues().size()); QVariantList contests; for (auto contestWrapper : r.getValues()) { auto contest = contestWrapper.getValue(); auto results = new ContestResultsApi(contest.getContestResults(), converter); QQmlEngine::setObjectOwnership(results, QQmlEngine::JavaScriptOwnership); // TODO: Set engagement notification API (when server defines it) contests.append( QVariantMap{ {"contestId", QString(convertBlob(ReaderPacker(contest.getContestId()).array()).toHex())}, {"votingStake", qint64(contest.getVotingStake())}, {"resultsApi", QVariant::fromValue(results)} }); } return {QVariant(contests)}; }); }
void TlsPskAdaptor::handleEof() { KJ_LOG(INFO, "Got EOF. Canceling reads."); processReadRequests(); hitEof = true; while (!readRequests.empty()) { if (readRequests.front().throwOnEof) readRequests.front().fulfiller->reject(KJ_EXCEPTION(DISCONNECTED, "EOF")); else readRequests.front().fulfiller->fulfill(0); readRequests.pop(); } }
kj::Promise<size_t> TlsPskAdaptor::tryRead(void* buffer, size_t minBytes, size_t maxBytes) { if (!channel) { KJ_LOG(ERROR, "tryRead with no channel"); return KJ_EXCEPTION(DISCONNECTED, "Adaptor cannot be used without a channel. Call setChannel first"); } if (hitEof) return size_t(0); auto paf = kj::newPromiseAndFulfiller<size_t>(); readRequests.emplace(ApplicationDataRequest{kj::mv(paf.fulfiller), kj::ArrayPtr<kj::byte>(static_cast<kj::byte*>(buffer), maxBytes), minBytes, false}); processReadRequests(); return kj::mv(paf.promise); }
QJSValue PromiseConverter::convert(kj::Promise<void> promise) { auto convertedPromise = kj::heap<QmlPromise>(promiseParent); auto responsePromise = promise.then( [convertedPromise = convertedPromise.get()] { convertedPromise->resolve(); }, [convertedPromise = convertedPromise.get()](kj::Exception&& exception) { convertedPromise->reject({QString::fromStdString(exception.getDescription())}); KJ_LOG(WARNING, "Exception in PromiseConverter", exception); }); QJSValue result = *convertedPromise; tasks.add(responsePromise.attach(kj::mv(convertedPromise))); return result; }
int main() { kj::UnixEventPort::captureSignal(SIGINT); TwoPartyServer server(kj::heap<BackendServer>()); auto asyncIo = kj::setupAsyncIo(); auto promise = asyncIo.provider->getNetwork().parseAddress("127.0.0.1", 2572).then( [&server](kj::Own<kj::NetworkAddress> addr) { auto listener = addr->listen(); std::cout << "Listening on port " << listener->getPort() << std::endl; return server.listen(kj::mv(listener)); }).eagerlyEvaluate([](kj::Exception&& e) { KJ_LOG(ERROR, e); exit(1); }); asyncIo.unixEventPort.onSignal(SIGINT).wait(asyncIo.waitScope); std::cout << "\nServer exiting.\n"; return 0; }
void TlsPskAdaptor::ErrorHandler::taskFailed(kj::Exception&& exception) { KJ_LOG(ERROR, "Exception when reading from wire", exception); adaptor.handleEof(); }