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;
}
Example #9
0
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();
}