diff --git a/src/core/c_context.cpp b/src/core/c_context.cpp index 697a458bc..bf2150b17 100644 --- a/src/core/c_context.cpp +++ b/src/core/c_context.cpp @@ -172,7 +172,7 @@ mcsdk_export void mcsdk_context_init(mcsdk_context** context) { auto internal = new mcsdk_context_internal(); LibraryFactory::Initialize(internal->message_queue); - internal->library = LibraryFactory::Instance().Default(); + internal->library = LibraryFactory::Instance().DefaultLocalLibrary(); internal->playback = new PlaybackService(internal->message_queue, internal->library); internal->metadata = new LocalMetadataProxy(internal->library); internal->preferences = Preferences::ForComponent(prefs::components::Settings); diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index e80104a5c..7f3819bd3 100755 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -498,6 +498,7 @@ + @@ -581,6 +582,7 @@ + diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index 735d2b9f3..f176db733 100755 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -256,6 +256,9 @@ src\library\query + + src\library + @@ -627,5 +630,8 @@ src\library\query + + src\library + \ No newline at end of file diff --git a/src/core/library/ILibrary.h b/src/core/library/ILibrary.h index e7619edf7..c3baecd2c 100755 --- a/src/core/library/ILibrary.h +++ b/src/core/library/ILibrary.h @@ -79,11 +79,7 @@ namespace musik { namespace core { virtual ~ILibrary() { } - virtual int Enqueue( - QueryPtr query, - unsigned int options = 0, - Callback = Callback()) = 0; - + virtual int Enqueue(QueryPtr query, unsigned int options = 0, Callback = Callback()) = 0; virtual IIndexer *Indexer() = 0; virtual int Id() = 0; virtual const std::string& Name() = 0; diff --git a/src/core/library/Indexer.cpp b/src/core/library/Indexer.cpp index b269db646..8590d4eff 100644 --- a/src/core/library/Indexer.cpp +++ b/src/core/library/Indexer.cpp @@ -914,7 +914,7 @@ void Indexer::RunAnalyzers() { getNextTrack.ResetAndUnbind(); auto track = std::make_shared(trackId); - TrackMetadataQuery query(track, LibraryFactory::Instance().Default()); + TrackMetadataQuery query(track, LibraryFactory::Instance().DefaultLocalLibrary()); query.Run(this->dbConnection); if (query.GetStatus() == IQuery::Finished) { diff --git a/src/core/library/LibraryFactory.cpp b/src/core/library/LibraryFactory.cpp index a1e2897e2..98403abde 100644 --- a/src/core/library/LibraryFactory.cpp +++ b/src/core/library/LibraryFactory.cpp @@ -58,7 +58,8 @@ LibraryFactory& LibraryFactory::Instance() { }; LibraryFactory::LibraryFactory() { - this->CreateLibrary("Local Library", ILibrary::Type::Local); + this->CreateLibrary("default-local-library", ILibrary::Type::Local); + this->CreateLibrary("default-remote-library", ILibrary::Type::Remote); } LibraryFactory::~LibraryFactory() { @@ -133,10 +134,19 @@ LibraryFactory::LibraryVector LibraryFactory::Libraries() { return LibraryFactory::Instance().libraries; } -ILibraryPtr LibraryFactory::Default() { +ILibraryPtr LibraryFactory::DefaultLocalLibrary() { return LibraryFactory::Instance().libraries.at(0); } +ILibraryPtr LibraryFactory::DefaultRemoteLibrary() { + return LibraryFactory::Instance().libraries.at(1); +} + +ILibraryPtr LibraryFactory::DefaultLibrary(ILibrary::Type type) { + return type == ILibrary::Type::Local + ? DefaultLocalLibrary() : DefaultRemoteLibrary(); +} + ILibraryPtr LibraryFactory::GetLibrary(int identifier) { if (identifier) { LibraryMap::iterator lib = this->libraryMap.find(identifier); diff --git a/src/core/library/LibraryFactory.h b/src/core/library/LibraryFactory.h index 153963971..3fd9791ae 100644 --- a/src/core/library/LibraryFactory.h +++ b/src/core/library/LibraryFactory.h @@ -58,7 +58,10 @@ namespace musik { namespace core { static LibraryFactory& Instance(); static void Shutdown(); - ILibraryPtr Default(); + ILibraryPtr DefaultLocalLibrary(); + ILibraryPtr DefaultRemoteLibrary(); + ILibraryPtr DefaultLibrary(ILibrary::Type type); + LibraryVector Libraries(); ILibraryPtr CreateLibrary(const std::string& name, ILibrary::Type type); diff --git a/src/core/library/LocalMetadataProxy.cpp b/src/core/library/LocalMetadataProxy.cpp index 07a5bf942..1ef124ae5 100644 --- a/src/core/library/LocalMetadataProxy.cpp +++ b/src/core/library/LocalMetadataProxy.cpp @@ -785,7 +785,7 @@ bool LocalMetadataProxy::SendRawQuery( { try { nlohmann::json json = nlohmann::json::parse(query); - auto localLibrary = LibraryFactory::Instance().Default(); + auto localLibrary = LibraryFactory::Instance().DefaultLocalLibrary(); std::string name = json["name"]; auto libraryQuery = QueryRegistry::CreateLocalQueryFor(name, query, localLibrary); if (libraryQuery) { diff --git a/src/core/library/MasterLibrary.cpp b/src/core/library/MasterLibrary.cpp new file mode 100644 index 000000000..808ee89cd --- /dev/null +++ b/src/core/library/MasterLibrary.cpp @@ -0,0 +1,133 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2004-2019 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#include "pch.hpp" + +#include "MasterLibrary.h" +#include "LibraryFactory.h" +#include +#include + +using namespace musik::core; +using namespace musik::core::library; +using namespace musik::core::runtime; + +MasterLibrary::MasterLibrary() { + this->LoadDefaultLibrary(); +} + +MasterLibrary::~MasterLibrary() { +} + +ILibraryPtr MasterLibrary::Get() const { + std::unique_locklibraryMutex)> lock(this->libraryMutex); + return this->wrappedLibrary; +} + +int MasterLibrary::Enqueue(QueryPtr query, unsigned int options, Callback callback) { + return Get()->Enqueue(query, options, callback); +} + +IIndexer* MasterLibrary::Indexer() { + return Get()->Indexer(); +} + +int MasterLibrary::Id() { + return Get()->Id(); +} + +const std::string& MasterLibrary::Name() { + return Get()->Name(); +} + +void MasterLibrary::SetMessageQueue(IMessageQueue& queue) { + this->Get()->SetMessageQueue(queue); +} + +IMessageQueue& MasterLibrary::GetMessageQueue() { + return Get()->GetMessageQueue(); +} + +MasterLibrary::IResourceLocator& MasterLibrary::GetResourceLocator() { + return Get()->GetResourceLocator(); +} + +bool MasterLibrary::IsConfigured() { + return Get()->IsConfigured(); +} + +MasterLibrary::ConnectionState MasterLibrary::GetConnectionState() const { + return Get()->GetConnectionState(); +} + +MasterLibrary::Type MasterLibrary::GetType() const { + return Get()->GetType(); +} + +void MasterLibrary::Close() { + Get()->Close(); +} + +void MasterLibrary::LoadDefaultLibrary() { + std::unique_locklibraryMutex)> lock(this->libraryMutex); + + auto prevWrappedLibrary = this->wrappedLibrary; + + auto prefs = Preferences::ForComponent(prefs::components::Settings); + + auto libraryType = (ILibrary::Type) prefs->GetInt( + prefs::keys::LibraryType, (int) ILibrary::Type::Local); + + this->wrappedLibrary = LibraryFactory::Instance().DefaultLibrary(libraryType); + + if (prevWrappedLibrary != wrappedLibrary) { + if (prevWrappedLibrary) { + prevWrappedLibrary->QueryCompleted.disconnect(this); + prevWrappedLibrary->ConnectionStateChanged.disconnect(this); + } + + if (this->wrappedLibrary) { + this->wrappedLibrary->QueryCompleted.connect(this, &MasterLibrary::OnQueryCompleted); + this->wrappedLibrary->ConnectionStateChanged.connect(this, &MasterLibrary::OnConectionStateChanged); + } + } +} + +void MasterLibrary::OnQueryCompleted(musik::core::db::IQuery* query) { + this->QueryCompleted(query); +} + +void MasterLibrary::OnConectionStateChanged(ConnectionState state) { + this->ConnectionStateChanged(state); +} diff --git a/src/core/library/MasterLibrary.h b/src/core/library/MasterLibrary.h new file mode 100644 index 000000000..af38bc8a1 --- /dev/null +++ b/src/core/library/MasterLibrary.h @@ -0,0 +1,83 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2004-2019 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +namespace musik { namespace core { namespace library { + + class MasterLibrary: public ILibrary, public sigslot::has_slots<> { + public: + MasterLibrary(); + virtual ~MasterLibrary(); + + virtual int Enqueue(QueryPtr query, unsigned int options = 0, Callback = Callback()) override; + virtual musik::core::IIndexer *Indexer() override; + virtual int Id() override; + virtual const std::string& Name() override; + virtual void SetMessageQueue(musik::core::runtime::IMessageQueue& queue) override; + virtual musik::core::runtime::IMessageQueue& GetMessageQueue() override; + virtual IResourceLocator& GetResourceLocator() override; + virtual bool IsConfigured() override; + virtual ConnectionState GetConnectionState() const override; + virtual Type GetType() const override; + virtual void Close() override; + + ILibraryPtr Wrapped() const { return Get(); } + + void LoadDefaultLibrary(); + + private: + + ILibraryPtr Get() const; + + void OnQueryCompleted(musik::core::db::IQuery* query); + void OnConectionStateChanged(ConnectionState state); + + ILibraryPtr wrappedLibrary; + mutable std::recursive_mutex libraryMutex; + }; + +} } } diff --git a/src/core/library/RemoteLibrary.cpp b/src/core/library/RemoteLibrary.cpp index de30bbc63..3c021e22b 100644 --- a/src/core/library/RemoteLibrary.cpp +++ b/src/core/library/RemoteLibrary.cpp @@ -142,7 +142,7 @@ void RemoteLibrary::Close() { } bool RemoteLibrary::IsConfigured() { - return LibraryFactory::Instance().Default()->IsConfigured(); /* CAL TODO FIXME */ + return LibraryFactory::Instance().DefaultLocalLibrary()->IsConfigured(); /* CAL TODO FIXME */ } static inline bool isQueryDone(RemoteLibrary::Query query) { @@ -166,7 +166,7 @@ bool RemoteLibrary::IsQueryInFlight(Query query) { int RemoteLibrary::Enqueue(QueryPtr query, unsigned int options, Callback callback) { if (QueryRegistry::IsLocalOnlyQuery(query->Name())) { - auto defaultLocalLibrary = LibraryFactory::Instance().Default(); + auto defaultLocalLibrary = LibraryFactory::Instance().DefaultLocalLibrary(); return defaultLocalLibrary->Enqueue(query, options, callback); } @@ -275,7 +275,7 @@ void RemoteLibrary::RunQueryOnLoopback(QueryContextPtr context) { locally, serialize the result, then deserialize it again to emulate the entire flow. */ - auto localLibrary = LibraryFactory::Instance().Default(); + auto localLibrary = LibraryFactory::Instance().DefaultLocalLibrary(); localLibrary->SetMessageQueue(*this->messageQueue); auto localQuery = QueryRegistry::CreateLocalQueryFor( diff --git a/src/musikcube/Main.cpp b/src/musikcube/Main.cpp index 95259da71..a9192958a 100644 --- a/src/musikcube/Main.cpp +++ b/src/musikcube/Main.cpp @@ -53,7 +53,7 @@ #include #include #include -#include +#include #include #include #include @@ -118,8 +118,7 @@ int main(int argc, char* argv[]) { musik::debug::Start({ fileLogger, consoleLogger }); LibraryFactory::Initialize(Window::MessageQueue()); - //ILibraryPtr library = LibraryFactory::Instance().Default(); - ILibraryPtr library = LibraryFactory::Instance().CreateLibrary("remote", ILibrary::Type::Remote); + auto library = std::make_shared(); { auto prefs = Preferences::ForComponent( diff --git a/src/musikcube/app/layout/LibraryNotConnectedLayout.cpp b/src/musikcube/app/layout/LibraryNotConnectedLayout.cpp index c03b54e8b..66d160b6b 100644 --- a/src/musikcube/app/layout/LibraryNotConnectedLayout.cpp +++ b/src/musikcube/app/layout/LibraryNotConnectedLayout.cpp @@ -50,15 +50,17 @@ using namespace musik::core::library; using namespace musik::core::net; using namespace cursespp; -static inline std::string resolveErrorMessage(const ILibrary* library) { +using MasterLibraryPtr = LibraryNotConnectedLayout::MasterLibraryPtr; + +static inline std::string resolveErrorMessage(MasterLibraryPtr library) { static const std::map kStateToErrorString = { { WebSocketClient::ConnectionError::ClosedByServer, "library_error_closed_by_server" }, { WebSocketClient::ConnectionError::ConnectionFailed, "library_error_connection_failed" }, { WebSocketClient::ConnectionError::InvalidPassword, "library_error_invalid_password" }, }; - if (library->GetType() == ILibrary::Type::Remote) { - const RemoteLibrary* remoteLibrary = static_cast(library); + auto remoteLibrary = dynamic_cast(library->Wrapped().get()); + if (remoteLibrary) { auto error = remoteLibrary->WebSocketClient().LastConnectionError(); auto it = kStateToErrorString.find(error); if (it != kStateToErrorString.end()) { @@ -74,9 +76,10 @@ static inline std::string resolveErrorMessage(const ILibrary* library) { return _TSTR("library_error_unknown"); } -static inline std::string resolveMessageText(const ILibrary* library) { - if (library->GetType() == ILibrary::Type::Remote) { - auto host = dynamic_cast(library)->WebSocketClient().Uri(); +static inline std::string resolveMessageText(MasterLibraryPtr library) { + auto remoteLibrary = dynamic_cast(library->Wrapped().get()); + if (remoteLibrary) { + auto host = remoteLibrary->WebSocketClient().Uri(); if (host.find("ws://") == 0) { host = host.substr(5); } if (host.size()) { return u8fmt(_TSTR("library_not_connected_with_hostname"), host.c_str()); @@ -85,7 +88,7 @@ static inline std::string resolveMessageText(const ILibrary* library) { return _TSTR("library_not_connected"); } -LibraryNotConnectedLayout::LibraryNotConnectedLayout(ILibraryPtr library) +LibraryNotConnectedLayout::LibraryNotConnectedLayout(MasterLibraryPtr library) : LayoutBase() , library(library) { this->library->ConnectionStateChanged.connect(this, &LibraryNotConnectedLayout::OnLibraryStateChanged); @@ -122,10 +125,9 @@ void LibraryNotConnectedLayout::OnLibraryStateChanged(ILibrary::ConnectionState } void LibraryNotConnectedLayout::UpdateErrorText() { - auto library = this->library.get(); - auto error = u8fmt(_TSTR("library_error_format"), resolveErrorMessage(library).c_str()); + auto error = u8fmt(_TSTR("library_error_format"), resolveErrorMessage(this->library).c_str()); this->errorText->SetText(error); - this->messageText->SetText(resolveMessageText(library)); + this->messageText->SetText(resolveMessageText(this->library)); } void LibraryNotConnectedLayout::SetShortcutsWindow(cursespp::ShortcutsWindow* shortcuts) { diff --git a/src/musikcube/app/layout/LibraryNotConnectedLayout.h b/src/musikcube/app/layout/LibraryNotConnectedLayout.h index 6063befcb..57bd55bd0 100644 --- a/src/musikcube/app/layout/LibraryNotConnectedLayout.h +++ b/src/musikcube/app/layout/LibraryNotConnectedLayout.h @@ -35,7 +35,7 @@ #pragma once #include -#include +#include #include #include #include @@ -48,7 +48,9 @@ namespace musik { namespace cube { public sigslot::has_slots<> { public: - LibraryNotConnectedLayout(musik::core::ILibraryPtr library); + using MasterLibraryPtr = std::shared_ptr; + + LibraryNotConnectedLayout(MasterLibraryPtr library); virtual void OnLayout() override; virtual bool KeyPress(const std::string& kn) override; @@ -61,7 +63,7 @@ namespace musik { namespace cube { private: void UpdateErrorText(); - musik::core::ILibraryPtr library; + MasterLibraryPtr library; std::shared_ptr messageText; std::shared_ptr errorText; std::shared_ptr helpText; diff --git a/src/musikcube/app/layout/MainLayout.cpp b/src/musikcube/app/layout/MainLayout.cpp index 56d42c438..1b99a8079 100755 --- a/src/musikcube/app/layout/MainLayout.cpp +++ b/src/musikcube/app/layout/MainLayout.cpp @@ -66,6 +66,8 @@ using namespace musik::core::library; using namespace musik::core::runtime; using namespace cursespp; +using MasterLibraryPtr = MainLayout::MasterLibraryPtr; + static UpdateCheck updateCheck; static inline void updateSyncingText(TextLabel* label, int updates) { @@ -86,18 +88,21 @@ static inline void updateSyncingText(TextLabel* label, int updates) { } } -static inline void updateRemoteLibraryConnectedText(TextLabel* label, const ILibrary* library) { - auto host = static_cast(library)->WebSocketClient().Uri(); - if (host.find("ws://") == 0) { host = host.substr(5); } - auto value = u8fmt(_TSTR("library_remote_connected_banner"), host.c_str()); - label->SetText(value, cursespp::text::AlignCenter); +static inline void updateRemoteLibraryConnectedText(TextLabel* label, MasterLibraryPtr library) { + RemoteLibrary* remoteLibrary = dynamic_cast(library->Wrapped().get()); + if (remoteLibrary) { + std::string host = remoteLibrary->WebSocketClient().Uri(); + if (host.find("ws://") == 0) { host = host.substr(5); } + auto value = u8fmt(_TSTR("library_remote_connected_banner"), host.c_str()); + label->SetText(value, cursespp::text::AlignCenter); + } } MainLayout::MainLayout( cursespp::App& app, musik::cube::ConsoleLogger* logger, musik::core::audio::PlaybackService& playback, - ILibraryPtr library) + MasterLibraryPtr library) : shortcutsFocused(false) , syncUpdateCount(0) , library(library) @@ -153,7 +158,7 @@ void MainLayout::UpdateTopBannerText() { updateSyncingText(this->topBanner.get(), this->syncUpdateCount); } else if (libraryType == ILibrary::Type::Remote) { - updateRemoteLibraryConnectedText(this->topBanner.get(), this->library.get()); + updateRemoteLibraryConnectedText(this->topBanner.get(), this->library); } } diff --git a/src/musikcube/app/layout/MainLayout.h b/src/musikcube/app/layout/MainLayout.h index 88b577da1..72956883a 100755 --- a/src/musikcube/app/layout/MainLayout.h +++ b/src/musikcube/app/layout/MainLayout.h @@ -41,10 +41,8 @@ #include #include -#include #include - -#include +#include #include @@ -54,11 +52,13 @@ namespace musik { namespace cube { class MainLayout : public cursespp::AppLayout { public: + using MasterLibraryPtr = std::shared_ptr; + MainLayout( cursespp::App& app, ConsoleLogger* logger, musik::core::audio::PlaybackService& playback, - musik::core::ILibraryPtr library); + MasterLibraryPtr library); virtual ~MainLayout(); @@ -95,7 +95,7 @@ namespace musik { std::shared_ptr hotkeysLayout; std::shared_ptr lyricsLayout; musik::core::audio::PlaybackService& playback; - musik::core::ILibraryPtr library; + MasterLibraryPtr library; bool shortcutsFocused; int syncUpdateCount; };