Refactored namespaces

This commit is contained in:
emeric
2024-03-12 08:32:08 +01:00
parent 487960b413
commit 4b7c4295ec
501 changed files with 12605 additions and 12631 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ target_include_directories(lmsfeedback PRIVATE
)
target_link_libraries(lmsfeedback PRIVATE
lmsutils
lmscore
)
target_link_libraries(lmsfeedback PUBLIC
@@ -29,12 +29,12 @@
#include "database/StarredTrack.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "utils/ILogger.hpp"
#include "core/ILogger.hpp"
#include "internal/InternalBackend.hpp"
#include "listenbrainz/ListenBrainzBackend.hpp"
namespace Feedback
namespace lms::feedback
{
std::unique_ptr<IFeedbackService> createFeedbackService(boost::asio::io_context& ioContext, Db& db)
{
@@ -45,8 +45,8 @@ namespace Feedback
: _db{ db }
{
LMS_LOG(SCROBBLING, INFO, "Starting service...");
_backends.emplace(Database::FeedbackBackend::Internal, std::make_unique<InternalBackend>(_db));
_backends.emplace(Database::FeedbackBackend::ListenBrainz, std::make_unique<ListenBrainz::ListenBrainzBackend>(ioContext, _db));
_backends.emplace(db::FeedbackBackend::Internal, std::make_unique<InternalBackend>(_db));
_backends.emplace(db::FeedbackBackend::ListenBrainz, std::make_unique<listenBrainz::ListenBrainzBackend>(ioContext, _db));
LMS_LOG(SCROBBLING, INFO, "Service started!");
}
@@ -55,9 +55,9 @@ namespace Feedback
LMS_LOG(SCROBBLING, INFO, "Service stopped!");
}
std::optional<Database::FeedbackBackend> FeedbackService::getUserFeedbackBackend(UserId userId)
std::optional<db::FeedbackBackend> FeedbackService::getUserFeedbackBackend(UserId userId)
{
std::optional<Database::FeedbackBackend> feedbackBackend;
std::optional<db::FeedbackBackend> feedbackBackend;
Session& session{ _db.getTLSSession() };
auto transaction{ session.createReadTransaction() };
@@ -25,54 +25,54 @@
#include "services/feedback/IFeedbackService.hpp"
#include "IFeedbackBackend.hpp"
namespace Database
namespace lms::db
{
class Db;
}
namespace Feedback
namespace lms::feedback
{
class FeedbackService : public IFeedbackService
{
public:
FeedbackService(boost::asio::io_context& ioContext, Database::Db& db);
FeedbackService(boost::asio::io_context& ioContext, db::Db& db);
~FeedbackService();
private:
FeedbackService(const FeedbackService&) = delete;
FeedbackService& operator=(const FeedbackService&) = delete;
void star(Database::UserId userId, Database::ArtistId artistId) override;
void unstar(Database::UserId userId, Database::ArtistId artistId) override;
bool isStarred(Database::UserId userId, Database::ArtistId artistId) override;
Wt::WDateTime getStarredDateTime(Database::UserId userId, Database::ArtistId artistId) override;
void star(db::UserId userId, db::ArtistId artistId) override;
void unstar(db::UserId userId, db::ArtistId artistId) override;
bool isStarred(db::UserId userId, db::ArtistId artistId) override;
Wt::WDateTime getStarredDateTime(db::UserId userId, db::ArtistId artistId) override;
ArtistContainer findStarredArtists(const ArtistFindParameters& params) override;
void star(Database::UserId userId, Database::ReleaseId releaseId) override;
void unstar(Database::UserId userId, Database::ReleaseId releaseId) override;
bool isStarred(Database::UserId userId, Database::ReleaseId releasedId) override;
Wt::WDateTime getStarredDateTime(Database::UserId userId, Database::ReleaseId releasedId) override;
void star(db::UserId userId, db::ReleaseId releaseId) override;
void unstar(db::UserId userId, db::ReleaseId releaseId) override;
bool isStarred(db::UserId userId, db::ReleaseId releasedId) override;
Wt::WDateTime getStarredDateTime(db::UserId userId, db::ReleaseId releasedId) override;
ReleaseContainer findStarredReleases(const FindParameters& params) override;
void star(Database::UserId userId, Database::TrackId trackId) override;
void unstar(Database::UserId userId, Database::TrackId trackId) override;
bool isStarred(Database::UserId userId, Database::TrackId trackId) override;
Wt::WDateTime getStarredDateTime(Database::UserId userId, Database::TrackId trackId) override;
void star(db::UserId userId, db::TrackId trackId) override;
void unstar(db::UserId userId, db::TrackId trackId) override;
bool isStarred(db::UserId userId, db::TrackId trackId) override;
Wt::WDateTime getStarredDateTime(db::UserId userId, db::TrackId trackId) override;
TrackContainer findStarredTracks(const FindParameters& params) override;
std::optional<Database::FeedbackBackend> getUserFeedbackBackend(Database::UserId userId);
std::optional<db::FeedbackBackend> getUserFeedbackBackend(db::UserId userId);
template <typename ObjType, typename ObjIdType, typename StarredObjType>
void star(Database::UserId userId, ObjIdType id);
void star(db::UserId userId, ObjIdType id);
template <typename ObjType, typename ObjIdType, typename StarredObjType>
void unstar(Database::UserId userId, ObjIdType id);
void unstar(db::UserId userId, ObjIdType id);
template <typename ObjType, typename ObjIdType, typename StarredObjType>
bool isStarred(Database::UserId userId, ObjIdType id);
bool isStarred(db::UserId userId, ObjIdType id);
template <typename ObjType, typename ObjIdType, typename StarredObjType>
Wt::WDateTime getStarredDateTime(Database::UserId userId, ObjIdType id);
Wt::WDateTime getStarredDateTime(db::UserId userId, ObjIdType id);
Database::Db& _db;
std::unordered_map<Database::FeedbackBackend, std::unique_ptr<IFeedbackBackend>> _backends;
db::Db& _db;
std::unordered_map<db::FeedbackBackend, std::unique_ptr<IFeedbackBackend>> _backends;
};
} // ns Feedback
@@ -23,9 +23,9 @@
#include "database/Session.hpp"
#include "database/User.hpp"
namespace Feedback
namespace lms::feedback
{
using namespace Database;
using namespace db;
template <typename ObjType, typename ObjIdType, typename StarredObjType>
void FeedbackService::star(UserId userId, ObjIdType objId)
@@ -23,19 +23,19 @@
#include "database/StarredReleaseId.hpp"
#include "database/StarredTrackId.hpp"
namespace Feedback
namespace lms::feedback
{
class IFeedbackBackend
{
public:
virtual ~IFeedbackBackend() = default;
virtual void onStarred(Database::StarredArtistId) = 0;
virtual void onUnstarred(Database::StarredArtistId) = 0;
virtual void onStarred(Database::StarredReleaseId) = 0;
virtual void onUnstarred(Database::StarredReleaseId) = 0;
virtual void onStarred(Database::StarredTrackId) = 0;
virtual void onUnstarred(Database::StarredTrackId) = 0;
virtual void onStarred(db::StarredArtistId) = 0;
virtual void onUnstarred(db::StarredArtistId) = 0;
virtual void onStarred(db::StarredReleaseId) = 0;
virtual void onUnstarred(db::StarredReleaseId) = 0;
virtual void onStarred(db::StarredTrackId) = 0;
virtual void onUnstarred(db::StarredTrackId) = 0;
};
std::unique_ptr<IFeedbackBackend> createFeedbackBackend(std::string_view backendName);
@@ -25,21 +25,21 @@
#include "database/StarredRelease.hpp"
#include "database/StarredTrack.hpp"
namespace Feedback
namespace lms::feedback
{
namespace details
{
template <typename StarredObjType>
void onStarred(Database::Session& session, typename StarredObjType::IdType id)
void onStarred(db::Session& session, typename StarredObjType::IdType id)
{
auto transaction{ session.createWriteTransaction() };
if (auto starredObj{ StarredObjType::find(session, id) })
starredObj.modify()->setSyncState(Database::SyncState::Synchronized);
starredObj.modify()->setSyncState(db::SyncState::Synchronized);
}
template <typename StarredObjType>
void onUnstarred(Database::Session& session, typename StarredObjType::IdType id)
void onUnstarred(db::Session& session, typename StarredObjType::IdType id)
{
auto transaction{ session.createWriteTransaction() };
@@ -48,37 +48,37 @@ namespace Feedback
}
}
InternalBackend::InternalBackend(Database::Db& db)
InternalBackend::InternalBackend(db::Db& db)
: _db{ db }
{}
void InternalBackend::onStarred(Database::StarredArtistId starredArtistId)
void InternalBackend::onStarred(db::StarredArtistId starredArtistId)
{
details::onStarred<Database::StarredArtist>(_db.getTLSSession(), starredArtistId);
details::onStarred<db::StarredArtist>(_db.getTLSSession(), starredArtistId);
}
void InternalBackend::onUnstarred(Database::StarredArtistId starredArtistId)
void InternalBackend::onUnstarred(db::StarredArtistId starredArtistId)
{
details::onUnstarred<Database::StarredArtist>(_db.getTLSSession(), starredArtistId);
details::onUnstarred<db::StarredArtist>(_db.getTLSSession(), starredArtistId);
}
void InternalBackend::onStarred(Database::StarredReleaseId starredReleaseId)
void InternalBackend::onStarred(db::StarredReleaseId starredReleaseId)
{
details::onStarred<Database::StarredRelease>(_db.getTLSSession(), starredReleaseId);
details::onStarred<db::StarredRelease>(_db.getTLSSession(), starredReleaseId);
}
void InternalBackend::onUnstarred(Database::StarredReleaseId starredReleaseId)
void InternalBackend::onUnstarred(db::StarredReleaseId starredReleaseId)
{
details::onUnstarred<Database::StarredRelease>(_db.getTLSSession(), starredReleaseId);
details::onUnstarred<db::StarredRelease>(_db.getTLSSession(), starredReleaseId);
}
void InternalBackend::onStarred(Database::StarredTrackId starredTrackId)
void InternalBackend::onStarred(db::StarredTrackId starredTrackId)
{
details::onStarred<Database::StarredTrack>(_db.getTLSSession(), starredTrackId);
details::onStarred<db::StarredTrack>(_db.getTLSSession(), starredTrackId);
}
void InternalBackend::onUnstarred(Database::StarredTrackId starredTrackId)
void InternalBackend::onUnstarred(db::StarredTrackId starredTrackId)
{
details::onUnstarred<Database::StarredTrack>(_db.getTLSSession(), starredTrackId);
details::onUnstarred<db::StarredTrack>(_db.getTLSSession(), starredTrackId);
}
} // Feedback
@@ -21,27 +21,27 @@
#include "IFeedbackBackend.hpp"
namespace Database
namespace lms::db
{
class Db;
}
namespace Feedback
namespace lms::feedback
{
class InternalBackend final : public IFeedbackBackend
{
public:
InternalBackend(Database::Db& db);
InternalBackend(db::Db& db);
private:
void onStarred(Database::StarredArtistId) override;
void onUnstarred(Database::StarredArtistId) override;
void onStarred(Database::StarredReleaseId) override;
void onUnstarred(Database::StarredReleaseId) override;
void onStarred(Database::StarredTrackId) override;
void onUnstarred(Database::StarredTrackId) override;
void onStarred(db::StarredArtistId) override;
void onUnstarred(db::StarredArtistId) override;
void onStarred(db::StarredReleaseId) override;
void onUnstarred(db::StarredReleaseId) override;
void onStarred(db::StarredTrackId) override;
void onUnstarred(db::StarredTrackId) override;
Database::Db& _db;
db::Db& _db;
};
} // Feedback
@@ -21,11 +21,11 @@
#include "services/feedback/Exception.hpp"
namespace Feedback::ListenBrainz
namespace lms::feedback::listenBrainz
{
class Exception : public ::Feedback::Exception
class Exception : public feedback::Exception
{
public:
using ::Feedback::Exception::Exception;
using feedback::Exception::Exception;
};
}
@@ -19,7 +19,7 @@
#include "FeedbackTypes.hpp"
namespace Feedback::ListenBrainz
namespace lms::feedback::listenBrainz
{
std::ostream&
operator<<(std::ostream& os, const Feedback& feedback)
@@ -27,4 +27,4 @@ namespace Feedback::ListenBrainz
os << "created = '" << feedback.created.toString() << "', recording MBID = '" << feedback.recordingMBID.getAsString() << "', score = " << static_cast<int>(feedback.score);
return os;
}
} // Feedback::ListenBrainz
} // feedback::ListenBrainz
@@ -21,9 +21,9 @@
#include <ostream>
#include <Wt/WDateTime.h>
#include "utils/UUID.hpp"
#include "core/UUID.hpp"
namespace Feedback::ListenBrainz
namespace lms::feedback::listenBrainz
{
// See https://listenbrainz.readthedocs.io/en/production/dev/feedback-json/#feedback-json-doc
enum class FeedbackType
@@ -36,10 +36,10 @@ namespace Feedback::ListenBrainz
struct Feedback
{
Wt::WDateTime created;
UUID recordingMBID;
core::UUID recordingMBID;
FeedbackType score;
};
std::ostream& operator<<(std::ostream& os, const Feedback& feedback);
} // Feedback::ListenBrainz
} // feedback::ListenBrainz
@@ -27,13 +27,13 @@
#include "Exception.hpp"
#include "Utils.hpp"
namespace Feedback::ListenBrainz
namespace lms::feedback::listenBrainz
{
namespace
{
Feedback parseFeedback(const Wt::Json::Object& feedbackObj)
{
const std::optional<UUID> recordingMBID{ UUID::fromString(static_cast<std::string>(feedbackObj.get("recording_mbid"))) };
const std::optional<core::UUID> recordingMBID{ core::UUID::fromString(static_cast<std::string>(feedbackObj.get("recording_mbid"))) };
if (!recordingMBID)
throw Exception{ "MBID not found!" };
@@ -87,4 +87,4 @@ namespace Feedback::ListenBrainz
return res;
}
} // Feedback::ListenBrainz
} // feedback::ListenBrainz
@@ -23,7 +23,7 @@
#include "FeedbackTypes.hpp"
namespace Feedback::ListenBrainz
namespace lms::feedback::listenBrainz
{
class FeedbacksParser
{
@@ -37,4 +37,4 @@ namespace Feedback::ListenBrainz
static Result parse(std::string_view msgBody);
};
} // Feedback::ListenBrainz
} // feedback::ListenBrainz
@@ -30,15 +30,15 @@
#include "database/StarredTrack.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "utils/IConfig.hpp"
#include "utils/http/IClient.hpp"
#include "utils/Service.hpp"
#include "core/IConfig.hpp"
#include "core/http/IClient.hpp"
#include "core/Service.hpp"
#include "Exception.hpp"
#include "FeedbacksParser.hpp"
#include "Utils.hpp"
namespace Feedback::ListenBrainz
namespace lms::feedback::listenBrainz
{
namespace
{
@@ -59,37 +59,37 @@ namespace Feedback::ListenBrainz
}
}
FeedbacksSynchronizer::FeedbacksSynchronizer(boost::asio::io_context& ioContext, Database::Db& db, Http::IClient& client)
FeedbacksSynchronizer::FeedbacksSynchronizer(boost::asio::io_context& ioContext, db::Db& db, core::http::IClient& client)
: _ioContext{ ioContext }
, _db{ db }
, _client{ client }
, _maxSyncFeedbackCount{ Service<IConfig>::get()->getULong("listenbrainz-max-sync-feedback-count", 1000) }
, _syncFeedbacksPeriod{ Service<IConfig>::get()->getULong("listenbrainz-sync-feedbacks-period-hours", 1) }
, _maxSyncFeedbackCount{ core::Service<core::IConfig>::get()->getULong("listenbrainz-max-sync-feedback-count", 1000) }
, _syncFeedbacksPeriod{ core::Service<core::IConfig>::get()->getULong("listenbrainz-sync-feedbacks-period-hours", 1) }
{
LOG(INFO, "Starting Feedbacks synchronizer, maxSyncFeedbackCount = " << _maxSyncFeedbackCount << ", _syncFeedbacksPeriod = " << _syncFeedbacksPeriod.count() << " hours");
scheduleSync(std::chrono::seconds{ 30 });
}
void FeedbacksSynchronizer::enqueFeedback(FeedbackType type, Database::StarredTrackId starredTrackId)
void FeedbacksSynchronizer::enqueFeedback(FeedbackType type, db::StarredTrackId starredTrackId)
{
try
{
Database::Session& session{ _db.getTLSSession() };
db::Session& session{ _db.getTLSSession() };
auto transaction{ session.createWriteTransaction() };
Database::StarredTrack::pointer starredTrack{ Database::StarredTrack::find(session, starredTrackId) };
db::StarredTrack::pointer starredTrack{ db::StarredTrack::find(session, starredTrackId) };
if (!starredTrack)
return;
std::optional<UUID> recordingMBID{ starredTrack->getTrack()->getRecordingMBID() };
std::optional<core::UUID> recordingMBID{ starredTrack->getTrack()->getRecordingMBID() };
switch (type)
{
case FeedbackType::Love:
if (starredTrack->getSyncState() != Database::SyncState::PendingAdd)
starredTrack.modify()->setSyncState(Database::SyncState::PendingAdd);
if (starredTrack->getSyncState() != db::SyncState::PendingAdd)
starredTrack.modify()->setSyncState(db::SyncState::PendingAdd);
break;
case FeedbackType::Erase:
@@ -102,7 +102,7 @@ namespace Feedback::ListenBrainz
{
// Send the erase order even if it is not on the remote LB server (it may be
// queued for add, or not)
starredTrack.modify()->setSyncState(Database::SyncState::PendingRemove);
starredTrack.modify()->setSyncState(db::SyncState::PendingRemove);
}
break;
@@ -116,11 +116,11 @@ namespace Feedback::ListenBrainz
return;
}
const std::optional<UUID> listenBrainzToken{ starredTrack->getUser()->getListenBrainzToken() };
const std::optional<core::UUID> listenBrainzToken{ starredTrack->getUser()->getListenBrainzToken() };
if (!listenBrainzToken)
return;
Http::ClientPOSTRequestParameters request;
core::http::ClientPOSTRequestParameters request;
request.relativeUrl = "/1/feedback/recording-feedback";
request.message.addHeader("Authorization", "Token " + std::string{ listenBrainzToken->getAsString() });
@@ -146,14 +146,14 @@ namespace Feedback::ListenBrainz
}
}
void FeedbacksSynchronizer::onFeedbackSent(FeedbackType type, Database::StarredTrackId starredTrackId)
void FeedbacksSynchronizer::onFeedbackSent(FeedbackType type, db::StarredTrackId starredTrackId)
{
assert(_strand.running_in_this_thread());
Database::Session& session{ _db.getTLSSession() };
db::Session& session{ _db.getTLSSession() };
auto transaction{ session.createWriteTransaction() };
Database::StarredTrack::pointer starredTrack{ Database::StarredTrack::find(session, starredTrackId) };
db::StarredTrack::pointer starredTrack{ db::StarredTrack::find(session, starredTrackId) };
if (!starredTrack)
{
LOG(DEBUG, "Starred track not found. deleted?");
@@ -165,7 +165,7 @@ namespace Feedback::ListenBrainz
switch (type)
{
case FeedbackType::Love:
starredTrack.modify()->setSyncState(Database::SyncState::Synchronized);
starredTrack.modify()->setSyncState(db::SyncState::Synchronized);
LOG(DEBUG, "State set to synchronized");
if (userContext.feedbackCount)
@@ -193,20 +193,20 @@ namespace Feedback::ListenBrainz
void FeedbacksSynchronizer::enquePendingFeedbacks()
{
using namespace Database;
using namespace db;
auto processPendingFeedbacks{ [this](SyncState scrobblingState, FeedbackType feedbackType)
{
RangeResults<StarredTrackId> pendingFeedbacks;
{
Database::Session& session {_db.getTLSSession()};
db::Session& session {_db.getTLSSession()};
auto transaction {session.createReadTransaction()};
StarredTrack::FindParameters params;
params.setFeedbackBackend(Database::FeedbackBackend::ListenBrainz, scrobblingState)
.setRange(Database::Range {0, 100}); // don't flood too much?
params.setFeedbackBackend(db::FeedbackBackend::ListenBrainz, scrobblingState)
.setRange(db::Range {0, 100}); // don't flood too much?
pendingFeedbacks = StarredTrack::find(session, params);
}
@@ -221,7 +221,7 @@ namespace Feedback::ListenBrainz
processPendingFeedbacks(SyncState::PendingRemove, FeedbackType::Erase);
}
FeedbacksSynchronizer::UserContext& FeedbacksSynchronizer::getUserContext(Database::UserId userId)
FeedbacksSynchronizer::UserContext& FeedbacksSynchronizer::getUserContext(db::UserId userId)
{
assert(_strand.running_in_this_thread());
@@ -274,14 +274,14 @@ namespace Feedback::ListenBrainz
enquePendingFeedbacks();
Database::RangeResults<Database::UserId> userIds;
db::RangeResults<db::UserId> userIds;
{
Database::Session& session{ _db.getTLSSession() };
db::Session& session{ _db.getTLSSession() };
auto transaction{ session.createReadTransaction() };
userIds = Database::User::find(_db.getTLSSession(), Database::User::FindParameters{}.setFeedbackBackend(Database::FeedbackBackend::ListenBrainz));
userIds = db::User::find(_db.getTLSSession(), db::User::FindParameters{}.setFeedbackBackend(db::FeedbackBackend::ListenBrainz));
}
for (const Database::UserId userId : userIds.results)
for (const db::UserId userId : userIds.results)
startSync(getUserContext(userId));
if (!isSyncing())
@@ -315,20 +315,20 @@ namespace Feedback::ListenBrainz
{
assert(context.listenBrainzUserName.empty());
const std::optional<UUID> listenBrainzToken{ ListenBrainz::Utils::getListenBrainzToken(_db.getTLSSession(), context.userId) };
const std::optional<core::UUID> listenBrainzToken{ utils::getListenBrainzToken(_db.getTLSSession(), context.userId) };
if (!listenBrainzToken)
{
onSyncEnded(context);
return;
}
Http::ClientGETRequestParameters request;
request.priority = Http::ClientRequestParameters::Priority::Low;
core::http::ClientGETRequestParameters request;
request.priority = core::http::ClientRequestParameters::Priority::Low;
request.relativeUrl = "/1/validate-token";
request.headers = { {"Authorization", "Token " + std::string {listenBrainzToken->getAsString()}} };
request.onSuccessFunc = [this, &context](std::string_view msgBody)
{
context.listenBrainzUserName = ListenBrainz::Utils::parseValidateToken(msgBody);
context.listenBrainzUserName = utils::parseValidateToken(msgBody);
if (context.listenBrainzUserName.empty())
{
onSyncEnded(context);
@@ -348,9 +348,9 @@ namespace Feedback::ListenBrainz
{
assert(!context.listenBrainzUserName.empty());
Http::ClientGETRequestParameters request;
core::http::ClientGETRequestParameters request;
request.relativeUrl = "/1/feedback/user/" + std::string{ context.listenBrainzUserName } + "/get-feedback?score=1&count=0";
request.priority = Http::ClientRequestParameters::Priority::Low;
request.priority = core::http::ClientRequestParameters::Priority::Low;
request.onSuccessFunc = [this, &context](std::string_view msgBody)
{
std::string msgBodyCopy{ msgBody };
@@ -383,9 +383,9 @@ namespace Feedback::ListenBrainz
{
assert(!context.listenBrainzUserName.empty());
Http::ClientGETRequestParameters request;
core::http::ClientGETRequestParameters request;
request.relativeUrl = "/1/feedback/user/" + context.listenBrainzUserName + "/get-feedback?offset=" + std::to_string(context.fetchedFeedbackCount);
request.priority = Http::ClientRequestParameters::Priority::Low;
request.priority = core::http::ClientRequestParameters::Priority::Low;
request.onSuccessFunc = [this, &context](std::string_view msgBody)
{
std::string msgBodyCopy{ msgBody };
@@ -429,7 +429,7 @@ namespace Feedback::ListenBrainz
void FeedbacksSynchronizer::tryImportFeedback(const Feedback& feedback, UserContext& context)
{
using namespace Database;
using namespace db;
Session& session{ _db.getTLSSession() };
@@ -451,7 +451,7 @@ namespace Feedback::ListenBrainz
}
trackId = tracks.front()->getId();
needImport = !StarredTrack::exists(session, trackId, context.userId, Database::FeedbackBackend::ListenBrainz);
needImport = !StarredTrack::exists(session, trackId, context.userId, db::FeedbackBackend::ListenBrainz);
// don't update starred date time
// no need to update state if it was found as not synchronized
@@ -473,7 +473,7 @@ namespace Feedback::ListenBrainz
if (!user)
return;
StarredTrack::pointer starredTrack{ session.create<StarredTrack>(track, user, Database::FeedbackBackend::ListenBrainz) };
StarredTrack::pointer starredTrack{ session.create<StarredTrack>(track, user, db::FeedbackBackend::ListenBrainz) };
starredTrack.modify()->setSyncState(SyncState::Synchronized);
starredTrack.modify()->setDateTime(feedback.created);
@@ -485,4 +485,4 @@ namespace Feedback::ListenBrainz
context.matchedFeedbackCount++;
}
}
} // namespace Feedback::ListenBrainz
} // namespace lms::feedback::listenBrainz
@@ -31,38 +31,40 @@
#include "FeedbackTypes.hpp"
namespace Database
{
class Db;
}
namespace Http
namespace lms
{
namespace core::http
{
class IClient;
}
namespace db
{
class Db;
}
}
namespace Feedback::ListenBrainz
namespace lms::feedback::listenBrainz
{
class FeedbacksSynchronizer
{
public:
FeedbacksSynchronizer(boost::asio::io_context& ioContext, Database::Db& db, Http::IClient& client);
FeedbacksSynchronizer(boost::asio::io_context& ioContext, db::Db& db, core::http::IClient& client);
void enqueFeedback(FeedbackType type, Database::StarredTrackId starredTrackId);
void enqueFeedback(FeedbackType type, db::StarredTrackId starredTrackId);
private:
void onFeedbackSent(FeedbackType type, Database::StarredTrackId starredTrackId);
void onFeedbackSent(FeedbackType type, db::StarredTrackId starredTrackId);
void enquePendingFeedbacks();
struct UserContext
{
UserContext(Database::UserId id) : userId{ id } {}
UserContext(db::UserId id) : userId{ id } {}
UserContext(const UserContext&) = delete;
UserContext& operator=(const UserContext&) = delete;
const Database::UserId userId;
const db::UserId userId;
bool syncing{};
std::optional<std::size_t> feedbackCount{};
@@ -75,7 +77,7 @@ namespace Feedback::ListenBrainz
std::size_t importedFeedbackCount{};
};
UserContext& getUserContext(Database::UserId userId);
UserContext& getUserContext(db::UserId userId);
bool isSyncing() const;
void scheduleSync(std::chrono::seconds fromNow);
void startSync();
@@ -89,14 +91,14 @@ namespace Feedback::ListenBrainz
boost::asio::io_context& _ioContext;
boost::asio::io_context::strand _strand{ _ioContext };
Database::Db& _db;
db::Db& _db;
boost::asio::steady_timer _syncTimer{ _ioContext };
Http::IClient& _client;
core::http::IClient& _client;
std::unordered_map<Database::UserId, UserContext> _userContexts;
std::unordered_map<db::UserId, UserContext> _userContexts;
const std::size_t _maxSyncFeedbackCount;
const std::chrono::hours _syncFeedbacksPeriod;
};
} // Feedback::ListenBrainz
} // feedback::ListenBrainz
@@ -24,30 +24,30 @@
#include "database/StarredArtist.hpp"
#include "database/StarredRelease.hpp"
#include "database/Track.hpp"
#include "utils/IConfig.hpp"
#include "utils/http/IClient.hpp"
#include "utils/ILogger.hpp"
#include "utils/Service.hpp"
#include "core/IConfig.hpp"
#include "core/http/IClient.hpp"
#include "core/ILogger.hpp"
#include "core/Service.hpp"
#include "Utils.hpp"
namespace Feedback::ListenBrainz
namespace lms::feedback::listenBrainz
{
namespace details
{
template <typename StarredObjType>
void onStarred(Database::Session& session, typename StarredObjType::IdType id)
void onStarred(db::Session& session, typename StarredObjType::IdType id)
{
auto transaction{ session.createWriteTransaction() };
if (auto starredObj{ StarredObjType::find(session, id) })
{
// maybe in the future this will be supported by ListenBrainz so set it to PendingAdd for all types
starredObj.modify()->setSyncState(Database::SyncState::PendingAdd);
starredObj.modify()->setSyncState(db::SyncState::PendingAdd);
}
}
template <typename StarredObjType>
void onUnstarred(Database::Session& session, typename StarredObjType::IdType id)
void onUnstarred(db::Session& session, typename StarredObjType::IdType id)
{
auto transaction{ session.createWriteTransaction() };
@@ -56,11 +56,11 @@ namespace Feedback::ListenBrainz
}
}
ListenBrainzBackend::ListenBrainzBackend(boost::asio::io_context& ioContext, Database::Db& db)
ListenBrainzBackend::ListenBrainzBackend(boost::asio::io_context& ioContext, db::Db& db)
: _ioContext{ ioContext }
, _db{ db }
, _baseAPIUrl{ Service<IConfig>::get()->getString("listenbrainz-api-base-url", "https://api.listenbrainz.org") }
, _client{ Http::createClient(_ioContext, _baseAPIUrl) }
, _baseAPIUrl{ core::Service<core::IConfig>::get()->getString("listenbrainz-api-base-url", "https://api.listenbrainz.org") }
, _client{ core::http::createClient(_ioContext, _baseAPIUrl) }
, _feedbacksSynchronizer{ _ioContext, db, *_client }
{
LOG(INFO, "Starting ListenBrainz feedback backend... API endpoint = '" << _baseAPIUrl << "'");
@@ -71,33 +71,33 @@ namespace Feedback::ListenBrainz
LOG(INFO, "Stopped ListenBrainz feedback backend!");
}
void ListenBrainzBackend::onStarred(Database::StarredArtistId starredArtistId)
void ListenBrainzBackend::onStarred(db::StarredArtistId starredArtistId)
{
details::onStarred<Database::StarredArtist>(_db.getTLSSession(), starredArtistId);
details::onStarred<db::StarredArtist>(_db.getTLSSession(), starredArtistId);
}
void ListenBrainzBackend::onUnstarred(Database::StarredArtistId starredArtistId)
void ListenBrainzBackend::onUnstarred(db::StarredArtistId starredArtistId)
{
details::onUnstarred<Database::StarredArtist>(_db.getTLSSession(), starredArtistId);
details::onUnstarred<db::StarredArtist>(_db.getTLSSession(), starredArtistId);
}
void ListenBrainzBackend::onStarred(Database::StarredReleaseId starredReleaseId)
void ListenBrainzBackend::onStarred(db::StarredReleaseId starredReleaseId)
{
details::onStarred<Database::StarredRelease>(_db.getTLSSession(), starredReleaseId);
details::onStarred<db::StarredRelease>(_db.getTLSSession(), starredReleaseId);
}
void ListenBrainzBackend::onUnstarred(Database::StarredReleaseId starredReleaseId)
void ListenBrainzBackend::onUnstarred(db::StarredReleaseId starredReleaseId)
{
details::onUnstarred<Database::StarredRelease>(_db.getTLSSession(), starredReleaseId);
details::onUnstarred<db::StarredRelease>(_db.getTLSSession(), starredReleaseId);
}
void ListenBrainzBackend::onStarred(Database::StarredTrackId starredTrackId)
void ListenBrainzBackend::onStarred(db::StarredTrackId starredTrackId)
{
_feedbacksSynchronizer.enqueFeedback(FeedbackType::Love, starredTrackId);
}
void ListenBrainzBackend::onUnstarred(Database::StarredTrackId starredtrackId)
void ListenBrainzBackend::onUnstarred(db::StarredTrackId starredtrackId)
{
_feedbacksSynchronizer.enqueFeedback(FeedbackType::Erase, starredtrackId);
}
} // namespace Scrobbling::ListenBrainz
} // namespace lms::scrobbling::listenBrainz
@@ -26,35 +26,34 @@
#include "IFeedbackBackend.hpp"
#include "FeedbacksSynchronizer.hpp"
namespace Database
namespace lms::db
{
class Db;
}
namespace Feedback::ListenBrainz
namespace lms::feedback::listenBrainz
{
class ListenBrainzBackend final : public IFeedbackBackend
{
public:
ListenBrainzBackend(boost::asio::io_context& ioContext, Database::Db& db);
ListenBrainzBackend(boost::asio::io_context& ioContext, db::Db& db);
~ListenBrainzBackend() override;
private:
ListenBrainzBackend(const ListenBrainzBackend&) = delete;
ListenBrainzBackend& operator=(const ListenBrainzBackend&) = delete;
void onStarred(Database::StarredArtistId starredArtistId) override;
void onUnstarred(Database::StarredArtistId starredArtistId) override;
void onStarred(Database::StarredReleaseId starredReleaseId) override;
void onUnstarred(Database::StarredReleaseId starredReleaseId) override;
void onStarred(Database::StarredTrackId starredTrackId) override;
void onUnstarred(Database::StarredTrackId starredTrackId) override;
void onStarred(db::StarredArtistId starredArtistId) override;
void onUnstarred(db::StarredArtistId starredArtistId) override;
void onStarred(db::StarredReleaseId starredReleaseId) override;
void onUnstarred(db::StarredReleaseId starredReleaseId) override;
void onStarred(db::StarredTrackId starredTrackId) override;
void onUnstarred(db::StarredTrackId starredTrackId) override;
boost::asio::io_context& _ioContext;
Database::Db& _db;
db::Db& _db;
std::string _baseAPIUrl;
std::unique_ptr<Http::IClient> _client;
std::unique_ptr<core::http::IClient> _client;
FeedbacksSynchronizer _feedbacksSynchronizer;
};
} // Feedback::ListenBrainz
}
@@ -25,13 +25,13 @@
#include "database/Session.hpp"
#include "database/User.hpp"
namespace Feedback::ListenBrainz::Utils
namespace lms::feedback::listenBrainz::utils
{
std::optional<UUID> getListenBrainzToken(Database::Session& session, Database::UserId userId)
std::optional<core::UUID> getListenBrainzToken(db::Session& session, db::UserId userId)
{
auto transaction{ session.createReadTransaction() };
const Database::User::pointer user{ Database::User::find(session, userId) };
const db::User::pointer user{ db::User::find(session, userId) };
if (!user)
return std::nullopt;
@@ -20,18 +20,18 @@
#pragma once
#include "database/UserId.hpp"
#include "utils/ILogger.hpp"
#include "utils/UUID.hpp"
#include "core/ILogger.hpp"
#include "core/UUID.hpp"
#define LOG(sev, message) LMS_LOG(FEEDBACK, sev, "[listenbrainz] " << message)
namespace Database
namespace lms::db
{
class Session;
}
namespace Feedback::ListenBrainz::Utils
namespace lms::feedback::listenBrainz::utils
{
std::optional<UUID> getListenBrainzToken(Database::Session& session, Database::UserId userId);
std::optional<core::UUID> getListenBrainzToken(db::Session& session, db::UserId userId);
std::string parseValidateToken(std::string_view msgBody);
}
@@ -19,11 +19,11 @@
#pragma once
#include "utils/Exception.hpp"
#include "core/Exception.hpp"
namespace Feedback
namespace lms::feedback
{
class Exception : public LmsException
class Exception : public core::LmsException
{
public:
using LmsException::LmsException;
@@ -33,67 +33,67 @@
#include "database/UserId.hpp"
#include "database/Types.hpp"
namespace Database
namespace lms::db
{
class Db;
}
namespace Feedback
namespace lms::feedback
{
class IFeedbackService
{
public:
virtual ~IFeedbackService() = default;
using ArtistContainer = Database::RangeResults<Database::ArtistId>;
using ReleaseContainer = Database::RangeResults<Database::ReleaseId>;
using TrackContainer = Database::RangeResults<Database::TrackId>;
using ArtistContainer = db::RangeResults<db::ArtistId>;
using ReleaseContainer = db::RangeResults<db::ReleaseId>;
using TrackContainer = db::RangeResults<db::TrackId>;
struct FindParameters
{
Database::UserId user;
std::vector<Database::ClusterId> clusters; // if non empty, at least one artist that belongs to these clusters
std::optional<Database::Range> range;
Database::MediaLibraryId library;
db::UserId user;
std::vector<db::ClusterId> clusters; // if non empty, at least one artist that belongs to these clusters
std::optional<db::Range> range;
db::MediaLibraryId library;
FindParameters& setUser(const Database::UserId _user) { user = _user; return *this; }
FindParameters& setClusters(const std::vector<Database::ClusterId>& _clusters) { clusters = _clusters; return *this; }
FindParameters& setRange(std::optional<Database::Range> _range) { range = _range; return *this; }
FindParameters& setMediaLibrary(Database::MediaLibraryId _library) { library = _library; return *this; }
FindParameters& setUser(const db::UserId _user) { user = _user; return *this; }
FindParameters& setClusters(const std::vector<db::ClusterId>& _clusters) { clusters = _clusters; return *this; }
FindParameters& setRange(std::optional<db::Range> _range) { range = _range; return *this; }
FindParameters& setMediaLibrary(db::MediaLibraryId _library) { library = _library; return *this; }
};
// Artists
struct ArtistFindParameters : public FindParameters
{
std::optional<Database::TrackArtistLinkType> linkType; // if set, only artists that have produced at least one track with this link type
Database::ArtistSortMethod sortMethod{ Database::ArtistSortMethod::None };
std::optional<db::TrackArtistLinkType> linkType; // if set, only artists that have produced at least one track with this link type
db::ArtistSortMethod sortMethod{ db::ArtistSortMethod::None };
ArtistFindParameters& setLinkType(std::optional<Database::TrackArtistLinkType> _linkType) { linkType = _linkType; return *this; }
ArtistFindParameters& setSortMethod(Database::ArtistSortMethod _sortMethod) { sortMethod = _sortMethod; return *this; }
ArtistFindParameters& setLinkType(std::optional<db::TrackArtistLinkType> _linkType) { linkType = _linkType; return *this; }
ArtistFindParameters& setSortMethod(db::ArtistSortMethod _sortMethod) { sortMethod = _sortMethod; return *this; }
};
virtual void star(Database::UserId userId, Database::ArtistId artistId) = 0;
virtual void unstar(Database::UserId userId, Database::ArtistId artistId) = 0;
virtual bool isStarred(Database::UserId userId, Database::ArtistId artistId) = 0;
virtual Wt::WDateTime getStarredDateTime(Database::UserId userId, Database::ArtistId artistId) = 0;
virtual void star(db::UserId userId, db::ArtistId artistId) = 0;
virtual void unstar(db::UserId userId, db::ArtistId artistId) = 0;
virtual bool isStarred(db::UserId userId, db::ArtistId artistId) = 0;
virtual Wt::WDateTime getStarredDateTime(db::UserId userId, db::ArtistId artistId) = 0;
virtual ArtistContainer findStarredArtists(const ArtistFindParameters& params) = 0;
// Releases
virtual void star(Database::UserId userId, Database::ReleaseId releaseId) = 0;
virtual void unstar(Database::UserId userId, Database::ReleaseId releaseId) = 0;
virtual bool isStarred(Database::UserId userId, Database::ReleaseId artistId) = 0;
virtual Wt::WDateTime getStarredDateTime(Database::UserId userId, Database::ReleaseId artistId) = 0;
virtual void star(db::UserId userId, db::ReleaseId releaseId) = 0;
virtual void unstar(db::UserId userId, db::ReleaseId releaseId) = 0;
virtual bool isStarred(db::UserId userId, db::ReleaseId artistId) = 0;
virtual Wt::WDateTime getStarredDateTime(db::UserId userId, db::ReleaseId artistId) = 0;
virtual ReleaseContainer findStarredReleases(const FindParameters& params) = 0;
// Tracks
virtual void star(Database::UserId userId, Database::TrackId trackId) = 0;
virtual void unstar(Database::UserId userId, Database::TrackId trackId) = 0;
virtual bool isStarred(Database::UserId userId, Database::TrackId artistId) = 0;
virtual Wt::WDateTime getStarredDateTime(Database::UserId userId, Database::TrackId artistId) = 0;
virtual void star(db::UserId userId, db::TrackId trackId) = 0;
virtual void unstar(db::UserId userId, db::TrackId trackId) = 0;
virtual bool isStarred(db::UserId userId, db::TrackId artistId) = 0;
virtual Wt::WDateTime getStarredDateTime(db::UserId userId, db::TrackId artistId) = 0;
virtual TrackContainer findStarredTracks(const FindParameters& params) = 0;
};
std::unique_ptr<IFeedbackService> createFeedbackService(boost::asio::io_service& ioService, Database::Db& db);
std::unique_ptr<IFeedbackService> createFeedbackService(boost::asio::io_service& ioService, db::Db& db);
} // ns Feedback