Skip to content

Commit

Permalink
Merge pull request #8118 from brave/ksmith-ledger-context
Browse files Browse the repository at this point in the history
Add AsyncResult and BATLedgerContext classes to bat-native-ledger
  • Loading branch information
zenparsing authored Mar 6, 2021
2 parents 414c96d + e32894d commit 4f55ccd
Show file tree
Hide file tree
Showing 15 changed files with 838 additions and 28 deletions.
4 changes: 4 additions & 0 deletions vendor/bat-native-ledger/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ source_set("ledger") {
"src/bat/ledger/internal/contribution/contribution_util.h",
"src/bat/ledger/internal/contribution/unverified.cc",
"src/bat/ledger/internal/contribution/unverified.h",
"src/bat/ledger/internal/core/async_result.h",
"src/bat/ledger/internal/core/bat_ledger_context.cc",
"src/bat/ledger/internal/core/bat_ledger_context.h",
"src/bat/ledger/internal/core/bat_ledger_task.h",
"src/bat/ledger/internal/credentials/credentials.h",
"src/bat/ledger/internal/credentials/credentials_common.cc",
"src/bat/ledger/internal/credentials/credentials_common.h",
Expand Down
122 changes: 122 additions & 0 deletions vendor/bat-native-ledger/src/bat/ledger/internal/core/async_result.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/* Copyright (c) 2021 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef BRAVE_VENDOR_BAT_NATIVE_LEDGER_SRC_BAT_LEDGER_INTERNAL_CORE_ASYNC_RESULT_H_
#define BRAVE_VENDOR_BAT_NATIVE_LEDGER_SRC_BAT_LEDGER_INTERNAL_CORE_ASYNC_RESULT_H_

#include <list>
#include <memory>
#include <utility>

#include "base/callback.h"
#include "base/optional.h"
#include "base/threading/sequenced_task_runner_handle.h"

namespace ledger {

// Represents the result of an asynchronous operation.
//
// Example:
// AsyncResult<int>::Resolver resolver;
// resolver.Complete(42);
//
// AsyncResult<int> result = resolver.result();
// result.Listen(base::BindOnce([](const int& value) {}));
//
// Listeners are called on the current SequencedTaskRunner, and are guaranteed
// to be called asynchronously. AsyncResult and Resolver objects are internally
// reference counted and can be passed between sequences; the internal data
// structures are updated on the sequence that created the Resolver.
template <typename T>
class AsyncResult {
public:
using CompleteType = T;
using CompleteCallback = base::OnceCallback<void(const T&)>;

void Listen(CompleteCallback on_complete) {
Listener listener = {.on_complete = std::move(on_complete),
.task_runner = base::SequencedTaskRunnerHandle::Get()};

task_runner_->PostTask(FROM_HERE, base::BindOnce(AddListenerInTask, store_,
std::move(listener)));
}

class Resolver {
public:
Resolver() {}
void Complete(T&& value) { result_.Complete(std::move(value)); }
AsyncResult result() const { return result_; }

private:
AsyncResult result_;
};

private:
AsyncResult()
: store_(new Store()),
task_runner_(base::SequencedTaskRunnerHandle::Get()) {}

enum class State { kPending, kComplete };

struct Listener {
CompleteCallback on_complete;
scoped_refptr<base::SequencedTaskRunner> task_runner;
};

struct Store {
Store() {}
State state = State::kPending;
base::Optional<T> value;
std::list<Listener> listeners;
};

void Complete(T&& value) {
task_runner_->PostTask(
FROM_HERE, base::BindOnce(SetCompleteInTask, store_, std::move(value)));
}

static void AddListenerInTask(std::shared_ptr<Store> store,
Listener listener) {
switch (store->state) {
case State::kComplete:
listener.task_runner->PostTask(
FROM_HERE, base::BindOnce(RunCompleteCallback, store,
std::move(listener.on_complete)));
break;
case State::kPending:
store->listeners.emplace_back(std::move(listener));
break;
}
}

static void SetCompleteInTask(std::shared_ptr<Store> store, T value) {
if (store->state != State::kPending)
return;

store->state = State::kComplete;
store->value = std::move(value);

for (auto& listener : store->listeners) {
listener.task_runner->PostTask(
FROM_HERE, base::BindOnce(RunCompleteCallback, store,
std::move(listener.on_complete)));
}

store->listeners.clear();
}

static void RunCompleteCallback(std::shared_ptr<Store> store,
CompleteCallback on_complete) {
DCHECK(store->value);
std::move(on_complete).Run(*store->value);
}

std::shared_ptr<Store> store_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
};

} // namespace ledger

#endif // BRAVE_VENDOR_BAT_NATIVE_LEDGER_SRC_BAT_LEDGER_INTERNAL_CORE_ASYNC_RESULT_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* Copyright (c) 2021 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "bat/ledger/internal/core/async_result.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ledger {

class AsyncResultTest : public testing::Test {
protected:
base::test::TaskEnvironment task_environment_;
};

TEST_F(AsyncResultTest, CompleteResultSentInFutureTurn) {
AsyncResult<int>::Resolver resolver;
resolver.Complete(10);
int value = 0;
resolver.result().Listen(
base::BindLambdaForTesting([&value](const int& v) { value = v; }));
ASSERT_EQ(value, 0);
task_environment_.RunUntilIdle();
ASSERT_EQ(value, 10);
}

TEST_F(AsyncResultTest, CompleteCallbacksExecutedInFutureTurn) {
AsyncResult<int>::Resolver resolver;
int value = 0;
resolver.result().Listen(
base::BindLambdaForTesting([&value](const int& v) { value = v; }));
resolver.Complete(1);
ASSERT_EQ(value, 0);
task_environment_.RunUntilIdle();
ASSERT_EQ(value, 1);
}

} // namespace ledger
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* Copyright (c) 2021 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "bat/ledger/internal/core/bat_ledger_context.h"

#include <utility>

#include "bat/ledger/internal/ledger_impl.h"
#include "bat/ledger/ledger_client.h"

namespace ledger {

namespace {

size_t g_next_component_key = 0;

} // namespace

BATLedgerContext::BATLedgerContext(LedgerImpl* ledger_impl)
: ledger_client_(ledger_impl->ledger_client()), ledger_impl_(ledger_impl) {
DCHECK(ledger_client_);
}

BATLedgerContext::BATLedgerContext(LedgerClient* ledger_client)
: ledger_client_(ledger_client) {
DCHECK(ledger_client_);
}

BATLedgerContext::~BATLedgerContext() = default;

using Component = BATLedgerContext::Component;
using ComponentKey = BATLedgerContext::ComponentKey;

ComponentKey::ComponentKey() : value_(g_next_component_key++) {}

Component::Component(BATLedgerContext* context) : context_(context) {}

Component::~Component() = default;

using LogStream = BATLedgerContext::LogStream;

LogStream::LogStream(BATLedgerContext* context,
base::Location location,
LogLevel log_level)
: context_(context), location_(location), log_level_(log_level) {}

LogStream::LogStream(LogStream&& other)
: context_(other.context_),
location_(other.location_),
log_level_(other.log_level_),
stream_(std::move(other.stream_)) {
other.moved_ = true;
}

LogStream& LogStream::operator=(LogStream&& other) {
context_ = other.context_;
location_ = other.location_;
log_level_ = other.log_level_;
stream_ = std::move(other.stream_);

other.moved_ = true;
return *this;
}

LogStream::~LogStream() {
if (!moved_) {
context_->GetLedgerClient()->Log(
location_.file_name(), location_.line_number(),
static_cast<int>(log_level_), stream_.str());
}
}

LogStream BATLedgerContext::Log(base::Location location, LogLevel log_level) {
return LogStream(this, location, log_level);
}

LogStream BATLedgerContext::LogError(base::Location location) {
return LogStream(this, location, LogLevel::kError);
}

LogStream BATLedgerContext::LogInfo(base::Location location) {
return LogStream(this, location, LogLevel::kInfo);
}

LogStream BATLedgerContext::LogVerbose(base::Location location) {
return LogStream(this, location, LogLevel::kVerbose);
}

LogStream BATLedgerContext::LogFull(base::Location location) {
return LogStream(this, location, LogLevel::kFull);
}

} // namespace ledger
Loading

0 comments on commit 4f55ccd

Please sign in to comment.