Some initial plumbing to test query serialization/deserialization so we

can make requests over websockets.
This commit is contained in:
casey langen 2020-09-30 23:08:03 -07:00
parent b181ed50f6
commit 4ee0b92323
34 changed files with 595 additions and 61 deletions

View File

@ -59,7 +59,7 @@
#include <core/sdk/IStreamingEncoder.h>
#include <core/sdk/IDevice.h>
#include <core/sdk/IOutput.h>
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <core/library/ILibrary.h>
#include <core/library/IIndexer.h>
#include <core/library/track/TrackList.h>
@ -1266,7 +1266,7 @@ mcsdk_export void mcsdk_svc_indexer_remove_callbacks(mcsdk_svc_indexer in, mcsdk
* ILibrary
*/
class mcsdk_db_wrapped_query: public LocalQueryBase {
class mcsdk_db_wrapped_query: public QueryBase {
public:
mcsdk_db_wrapped_query(
mcsdk_svc_library library,

View File

@ -500,6 +500,7 @@
<ClCompile Include="library\LocalMetadataProxy.cpp" />
<ClCompile Include="library\metadata\MetadataMap.cpp" />
<ClCompile Include="library\metadata\MetadataMapList.cpp" />
<ClCompile Include="library\QueryRegistry.cpp" />
<ClCompile Include="library\query\local\AlbumListQuery.cpp" />
<ClCompile Include="library\query\local\AllCategoriesQuery.cpp" />
<ClCompile Include="library\query\local\AppendPlaylistQuery.cpp" />
@ -517,6 +518,7 @@
<ClCompile Include="library\query\local\SetTrackRatingQuery.cpp" />
<ClCompile Include="library\query\local\TrackMetadataQuery.cpp" />
<ClCompile Include="library\query\local\util\CategoryQueryUtil.cpp" />
<ClCompile Include="library\RemoteLibrary.cpp" />
<ClCompile Include="library\track\IndexerTrack.cpp" />
<ClCompile Include="library\track\LibraryTrack.cpp" />
<ClCompile Include="library\track\Track.cpp" />
@ -577,8 +579,11 @@
<ClInclude Include="library\LibraryFactory.h" />
<ClInclude Include="library\LocalLibraryConstants.h" />
<ClInclude Include="library\LocalMetadataProxy.h" />
<ClInclude Include="library\LocalQueryBase.h" />
<ClInclude Include="library\metadata\MetadataMap.h" />
<ClInclude Include="library\metadata\MetadataMapList.h" />
<ClInclude Include="library\QueryBase.h" />
<ClInclude Include="library\QueryRegistry.h" />
<ClInclude Include="library\query\local\AlbumListQuery.h" />
<ClInclude Include="library\query\local\AllCategoriesQuery.h" />
<ClInclude Include="library\query\local\AppendPlaylistQuery.h" />
@ -595,11 +600,11 @@
<ClInclude Include="library\query\local\SearchTrackListQuery.h" />
<ClInclude Include="library\query\local\SetTrackRatingQuery.h" />
<ClInclude Include="library\query\local\TrackListQueryBase.h" />
<ClInclude Include="Library\query\local\LocalQueryBase.h" />
<ClInclude Include="library\query\local\TrackMetadataQuery.h" />
<ClInclude Include="library\query\local\util\CategoryQueryUtil.h" />
<ClInclude Include="library\query\local\util\SdkWrappers.h" />
<ClInclude Include="library\query\local\util\TrackSort.h" />
<ClInclude Include="library\RemoteLibrary.h" />
<ClInclude Include="library\track\IndexerTrack.h" />
<ClInclude Include="library\track\LibraryTrack.h" />
<ClInclude Include="library\track\Track.h" />

View File

@ -241,6 +241,12 @@
<ClCompile Include="c_interface_wrappers.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="library\RemoteLibrary.cpp">
<Filter>src\library</Filter>
</ClCompile>
<ClCompile Include="library\QueryRegistry.cpp">
<Filter>src\library</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.hpp">
@ -399,9 +405,6 @@
<ClInclude Include="library\query\local\CategoryListQuery.h">
<Filter>src\library\query\local</Filter>
</ClInclude>
<ClInclude Include="Library\query\local\LocalQueryBase.h">
<Filter>src\library\query\local</Filter>
</ClInclude>
<ClInclude Include="plugin\Plugins.h">
<Filter>src\plugin</Filter>
</ClInclude>
@ -594,5 +597,17 @@
<ClInclude Include="sdk\ReplayGain.h">
<Filter>src\sdk\metadata</Filter>
</ClInclude>
<ClInclude Include="library\RemoteLibrary.h">
<Filter>src\library</Filter>
</ClInclude>
<ClInclude Include="library\QueryRegistry.h">
<Filter>src\library</Filter>
</ClInclude>
<ClInclude Include="library\LocalQueryBase.h">
<Filter>src\library</Filter>
</ClInclude>
<ClInclude Include="library\QueryBase.h">
<Filter>src\library</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -54,11 +54,18 @@ namespace musik { namespace core { namespace db {
} Status;
virtual ~IQuery() { }
virtual int GetStatus() = 0;
virtual int GetId() = 0;
virtual int GetOptions() = 0;
virtual std::string Name() = 0;
};
class ISerializableQuery: public IQuery {
public:
virtual ~ISerializableQuery() { }
virtual std::string SerializeQuery() = 0;
virtual std::string SerializeResult() = 0;
virtual void DeserializeResult(const std::string& data) = 0;
};
} } }

View File

@ -35,6 +35,7 @@
#include "pch.hpp"
#include <core/library/LibraryFactory.h>
#include <core/library/LocalLibrary.h>
#include <core/library/RemoteLibrary.h>
#include <core/db/Connection.h>
#include <core/support/Common.h>
#include <core/support/Preferences.h>
@ -56,20 +57,21 @@ LibraryFactory::LibraryFactory() {
for (size_t i = 0; i < libraries.size(); i++) {
std::string name = libraries.at(i);
int id = prefs->GetInt(name);
this->AddLibrary(id, LocalLibrary, name);
this->AddLibrary(id, LibraryType::Local, name);
}
if (this->libraries.empty()) {
this->CreateLibrary("Local Library", LocalLibrary);
this->CreateLibrary("Local Library", LibraryType::Local);
}
}
LibraryFactory::~LibraryFactory() {
}
ILibraryPtr LibraryFactory::AddLibrary(int id, int type, const std::string& name)
{
ILibraryPtr library = library::LocalLibrary::Create(name, id);
ILibraryPtr LibraryFactory::AddLibrary(int id, LibraryType type, const std::string& name) {
ILibraryPtr library = (type == LibraryType::Local)
? library::LocalLibrary::Create(name, id)
: library::RemoteLibrary::Create(name, id);
if (library) {
this->libraries.push_back(library);
@ -88,7 +90,7 @@ void LibraryFactory::Shutdown() {
Instance().libraries.clear();
}
ILibraryPtr LibraryFactory::CreateLibrary(const std::string& name, int type) {
ILibraryPtr LibraryFactory::CreateLibrary(const std::string& name, LibraryType type) {
auto prefs = Preferences::ForComponent(prefs::components::Libraries);
std::vector<std::string> libraries;
prefs->GetKeys(libraries);
@ -113,7 +115,7 @@ ILibraryPtr LibraryFactory::CreateLibrary(const std::string& name, int type) {
++nextId; /* unique */
prefs->SetInt(name, nextId);
return this->AddLibrary(nextId, LocalLibrary, name);
return this->AddLibrary(nextId, type, name);
}
LibraryFactory::LibraryVector& LibraryFactory::Libraries() {

View File

@ -48,8 +48,9 @@ namespace musik { namespace core {
typedef std::map<int, ILibraryPtr> LibraryMap;
typedef sigslot::signal0<> LibrariesUpdatedEvent;
enum LibraryType {
LocalLibrary = 1
enum class LibraryType: int {
Local = 1,
Remote = 2
};
~LibraryFactory();
@ -58,7 +59,7 @@ namespace musik { namespace core {
static LibraryVector& Libraries();
static ILibraryPtr Default();
ILibraryPtr CreateLibrary(const std::string& name, int type);
ILibraryPtr CreateLibrary(const std::string& name, LibraryType type);
void Shutdown();
ILibraryPtr GetLibrary(int identifier);
@ -67,7 +68,7 @@ namespace musik { namespace core {
private:
LibraryFactory();
ILibraryPtr AddLibrary(int id, int type, const std::string& name);
ILibraryPtr AddLibrary(int id, LibraryType type, const std::string& name);
LibraryVector libraries;
LibraryMap libraryMap;

View File

@ -36,7 +36,7 @@
#include <core/library/LocalLibrary.h>
#include <core/config.h>
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <core/support/Common.h>
#include <core/support/Preferences.h>
#include <core/library/Indexer.h>

View File

@ -40,7 +40,7 @@
#include <core/library/ILibrary.h>
#include <core/library/IIndexer.h>
#include <core/library/IQuery.h>
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <thread>
#include <mutex>
@ -57,7 +57,7 @@ namespace musik { namespace core { namespace library {
public std::enable_shared_from_this<LocalLibrary>
{
public:
using LocalQuery = musik::core::db::LocalQueryBase;
using LocalQuery = musik::core::db::QueryBase;
using LocalQueryPtr = std::shared_ptr<LocalQuery>;
static ILibraryPtr Create(std::string name, int id);

View File

@ -173,7 +173,7 @@ class ExternalIdListToTrackListQuery : public TrackListQueryBase {
std::shared_ptr<TrackList> result;
};
class RemoveFromPlaylistQuery : public LocalQueryBase {
class RemoveFromPlaylistQuery : public QueryBase {
public:
RemoveFromPlaylistQuery(
ILibraryPtr library,

View File

@ -45,16 +45,16 @@
namespace musik { namespace core { namespace db {
class LocalQueryBase : public IQuery, public sigslot::has_slots<> {
class QueryBase: public ISerializableQuery, public sigslot::has_slots<> {
public:
LocalQueryBase()
QueryBase()
: status(0)
, options(0)
, queryId(nextId())
, cancel(false) {
}
virtual ~LocalQueryBase() {
virtual ~QueryBase() {
}
bool Run(musik::core::db::Connection &db) {
@ -76,6 +76,8 @@ namespace musik { namespace core { namespace db {
return false;
}
/* IQuery */
virtual int GetStatus() {
std::unique_lock<std::mutex> lock(this->stateMutex);
return this->status;
@ -100,6 +102,20 @@ namespace musik { namespace core { namespace db {
virtual std::string Name() = 0;
/* ISerializableQuery */
virtual std::string SerializeQuery() {
throw std::runtime_error("not implemented");
}
virtual std::string SerializeResult() {
throw std::runtime_error("not implemented");
}
virtual void DeserializeResult(const std::string& data) {
throw std::runtime_error("not implemented");
}
protected:
void SetStatus(int status) {
std::unique_lock<std::mutex> lock(this->stateMutex);

View File

@ -0,0 +1,57 @@
//////////////////////////////////////////////////////////////////////////////
//
// 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 "QueryRegistry.h"
#include <core/library/query/local/LyricsQuery.h>
using namespace musik::core::db;
using namespace musik::core::db::local;
namespace musik { namespace core { namespace library {
namespace QueryRegistry {
std::shared_ptr<ISerializableQuery> CreateLocalQueryFor(
const std::string& name, const std::string& data)
{
if (name == LyricsQuery::kQueryName) {
return LyricsQuery::DeserializeQuery(data);
}
return std::shared_ptr<ISerializableQuery>();
}
}
} } }

View File

@ -0,0 +1,48 @@
//////////////////////////////////////////////////////////////////////////////
//
// 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 <core/library/IQuery.h>
#include <string>
#include <memory>
namespace musik { namespace core { namespace library {
namespace QueryRegistry {
std::shared_ptr<musik::core::db::ISerializableQuery> CreateLocalQueryFor(
const std::string& name, const std::string& data);
}
} } }

View File

@ -0,0 +1,233 @@
//////////////////////////////////////////////////////////////////////////////
//
// 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 <core/library/RemoteLibrary.h>
#include <core/config.h>
#include <core/support/Common.h>
#include <core/support/Preferences.h>
#include <core/library/Indexer.h>
#include <core/library/IQuery.h>
#include <core/library/QueryRegistry.h>
#include <core/runtime/Message.h>
#include <core/debug.h>
#include <core/library/LibraryFactory.h> /* CAL TODO: remove this */
static const std::string TAG = "RemoteLibrary";
using namespace musik::core;
using namespace musik::core::db;
using namespace musik::core::library;
using namespace musik::core::runtime;
#define MESSAGE_QUERY_COMPLETED 5000
class RemoteLibrary::QueryCompletedMessage: public Message {
public:
using QueryContextPtr = RemoteLibrary::QueryContextPtr;
QueryCompletedMessage(IMessageTarget* target, QueryContextPtr context)
: Message(target, MESSAGE_QUERY_COMPLETED, 0, 0) {
this->context = context;
}
virtual ~QueryCompletedMessage() {
}
QueryContextPtr GetContext() { return this->context; }
private:
QueryContextPtr context;
};
ILibraryPtr RemoteLibrary::Create(std::string name, int id) {
ILibraryPtr lib(new RemoteLibrary(name, id));
return lib;
}
RemoteLibrary::RemoteLibrary(std::string name,int id)
: name(name)
, id(id)
, exit(false)
, messageQueue(nullptr) {
this->identifier = std::to_string(id);
this->thread = new std::thread(std::bind(&RemoteLibrary::ThreadProc, this));
}
RemoteLibrary::~RemoteLibrary() {
this->Close();
}
int RemoteLibrary::Id() {
return this->id;
}
const std::string& RemoteLibrary::Name() {
return this->name;
}
void RemoteLibrary::Close() {
std::thread* thread = nullptr;
{
std::unique_lock<std::recursive_mutex> lock(this->mutex);
if (this->thread) {
thread = this->thread;
this->thread = nullptr;
this->queryQueue.clear();
this->exit = true;
}
}
if (thread) {
this->queueCondition.notify_all();
thread->join();
delete thread;
}
}
int RemoteLibrary::Enqueue(QueryPtr query, unsigned int options, Callback callback) {
auto serializableQuery = std::dynamic_pointer_cast<ISerializableQuery>(query);
if (serializableQuery) {
std::unique_lock<std::recursive_mutex> lock(this->mutex);
if (this->exit) { /* closed */
return -1;
}
auto context = std::make_shared<QueryContext>();
context->query = serializableQuery;
context->callback = callback;
if (options & ILibrary::QuerySynchronous) {
this->RunQuery(context, false); /* false = do not notify via QueryCompleted */
}
else {
queryQueue.push_back(context);
queueCondition.notify_all();
}
return query->GetId();
}
return -1;
}
RemoteLibrary::QueryContextPtr RemoteLibrary::GetNextQuery() {
std::unique_lock<std::recursive_mutex> lock(this->mutex);
while (!this->queryQueue.size() && !this->exit) {
this->queueCondition.wait(lock);
}
if (this->exit) {
return QueryContextPtr();
}
else {
auto front = queryQueue.front();
queryQueue.pop_front();
return front;
}
}
void RemoteLibrary::ThreadProc() {
while (!this->exit) {
auto query = GetNextQuery();
if (query) {
this->RunQuery(query);
}
}
}
void RemoteLibrary::RunQuery(QueryContextPtr context, bool notify) {
if (context) {
auto queryBytes = context->query->SerializeQuery();
auto localQuery = QueryRegistry::CreateLocalQueryFor(context->query->Name(), queryBytes);
auto onComplete = [this, notify, context, localQuery]() {
if (notify) {
if (this->messageQueue) {
this->messageQueue->Post(std::make_shared<QueryCompletedMessage>(this, context));
}
else {
this->QueryCompleted(localQuery.get());
}
}
else if (context->callback) {
context->callback(context->query);
}
context->query.reset();
};
if (!localQuery) {
onComplete();
return;
}
/* CAL TODO: eventually make the request over a websocket. right now we just
do everything via loopback to the local library for testing. */
LibraryFactory::Default()->Enqueue(
localQuery,
0,
[context, onComplete, localQuery](auto result) {
if (localQuery->GetStatus() == IQuery::Finished) {
context->query->DeserializeResult(localQuery->SerializeResult());
}
onComplete();
});
}
}
void RemoteLibrary::SetMessageQueue(musik::core::runtime::IMessageQueue& queue) {
this->messageQueue = &queue;
}
void RemoteLibrary::ProcessMessage(musik::core::runtime::IMessage &message) {
if (message.Type() == MESSAGE_QUERY_COMPLETED) {
auto context = static_cast<QueryCompletedMessage*>(&message)->GetContext();
auto query = context->query;
this->QueryCompleted(context->query.get());
if (context->callback) {
context->callback(query);
}
}
}
musik::core::IIndexer* RemoteLibrary::Indexer() {
return nullptr;
}

View File

@ -0,0 +1,110 @@
//////////////////////////////////////////////////////////////////////////////
//
// 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 <core/config.h>
#include <core/db/Connection.h>
#include <core/library/ILibrary.h>
#include <core/library/IIndexer.h>
#include <core/library/IQuery.h>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <string>
namespace musik { namespace core { namespace library {
class RemoteLibrary :
public ILibrary,
public musik::core::runtime::IMessageTarget,
public std::enable_shared_from_this<RemoteLibrary>
{
public:
static ILibraryPtr Create(std::string name, int id);
RemoteLibrary(const RemoteLibrary&) = delete;
virtual ~RemoteLibrary();
/* ILibrary */
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 { return *messageQueue; }
virtual void Close() override;
/* IMessageTarget */
virtual void ProcessMessage(musik::core::runtime::IMessage &message) override;
private:
class QueryCompletedMessage;
struct QueryContext {
std::shared_ptr<musik::core::db::ISerializableQuery> query;
Callback callback;
};
using QueryContextPtr = std::shared_ptr<QueryContext>;
using QueryList = std::list<QueryContextPtr>;
RemoteLibrary(std::string name, int id); /* ctor */
void RunQuery(QueryContextPtr context, bool notify = true);
void ThreadProc();
QueryContextPtr GetNextQuery();
QueryList queryQueue;
musik::core::runtime::IMessageQueue* messageQueue;
std::string identifier;
int id;
std::string name;
std::thread* thread;
std::condition_variable_any queueCondition;
std::recursive_mutex mutex;
std::atomic<bool> exit;
};
} } }

View File

@ -35,7 +35,7 @@
#include "pch.hpp"
#include "MetadataMap.h"
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <core/library/LocalLibraryConstants.h>
#include <core/db/Connection.h>
#include <core/db/Statement.h>

View File

@ -34,14 +34,14 @@
#pragma once
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <core/library/query/local/util/CategoryQueryUtil.h>
#include <core/library/metadata/MetadataMapList.h>
#include <core/db/Connection.h>
namespace musik { namespace core { namespace db { namespace local {
class AlbumListQuery : public musik::core::db::LocalQueryBase {
class AlbumListQuery : public musik::core::db::QueryBase {
public:
AlbumListQuery(
const std::string& filter = "");

View File

@ -34,13 +34,13 @@
#pragma once
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <core/library/query/local/util/SdkWrappers.h>
#include <core/sdk/IValueList.h>
namespace musik { namespace core { namespace db { namespace local {
class AllCategoriesQuery : public musik::core::db::LocalQueryBase {
class AllCategoriesQuery : public musik::core::db::QueryBase {
public:
using Result = SdkValueList::Shared;

View File

@ -34,14 +34,14 @@
#pragma once
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <core/library/track/TrackList.h>
#include <stdint.h>
#include <vector>
namespace musik { namespace core { namespace db { namespace local {
class AppendPlaylistQuery : public musik::core::db::LocalQueryBase {
class AppendPlaylistQuery : public musik::core::db::QueryBase {
public:
AppendPlaylistQuery(
musik::core::ILibraryPtr library,

View File

@ -34,7 +34,7 @@
#pragma once
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <core/library/query/local/util/CategoryQueryUtil.h>
#include <core/library/query/local/util/SdkWrappers.h>
#include <core/db/Statement.h>
@ -45,7 +45,7 @@
namespace musik { namespace core { namespace db { namespace local {
class CategoryListQuery : public musik::core::db::LocalQueryBase {
class CategoryListQuery : public musik::core::db::QueryBase {
public:
using Result = SdkValueList::Shared;

View File

@ -36,7 +36,7 @@
#include <core/db/Connection.h>
#include <core/library/track/Track.h>
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <core/library/query/local/util/CategoryQueryUtil.h>
#include <core/library/query/local/util/TrackSort.h>
#include <core/db/Statement.h>

View File

@ -35,12 +35,12 @@
#pragma once
#include <core/library/ILibrary.h>
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <core/db/Connection.h>
namespace musik { namespace core { namespace db { namespace local {
class DeletePlaylistQuery : public musik::core::db::LocalQueryBase {
class DeletePlaylistQuery : public musik::core::db::QueryBase {
public:
DeletePlaylistQuery(
musik::core::ILibraryPtr library,

View File

@ -36,7 +36,7 @@
#include <core/db/Connection.h>
#include <core/library/track/Track.h>
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include "TrackListQueryBase.h"

View File

@ -34,11 +34,16 @@
#include "pch.hpp"
#include "LyricsQuery.h"
#include <json.hpp>
using namespace musik::core::db;
using namespace musik::core::db::local;
using namespace musik::core::sdk;
const std::string LyricsQuery::kQueryName = "LyricsQuery";
/* IQuery */
LyricsQuery::LyricsQuery(const std::string& trackExternalId) {
this->trackExternalId = trackExternalId;
}
@ -70,4 +75,30 @@ bool LyricsQuery::OnRun(musik::core::db::Connection &db) {
}
return true;
}
/* ISerializableQuery */
std::string LyricsQuery::SerializeQuery() {
nlohmann::json query;
query["name"] = this->Name();
query["options"] = {{ "trackExternalId", this->trackExternalId }};
return query.dump();
}
std::string LyricsQuery::SerializeResult() {
nlohmann::json query;
query["result"] = this->result;
return query.dump();
}
void LyricsQuery::DeserializeResult(const std::string& data) {
this->SetStatus(IQuery::Failed);
this->result = nlohmann::json::parse(data).value("result", "");
this->SetStatus(IQuery::Finished);
}
std::shared_ptr<LyricsQuery> LyricsQuery::DeserializeQuery(const std::string& data) {
nlohmann::json query = nlohmann::json::parse(data);
return std::make_shared<LyricsQuery>(query["options"].value("trackExternalId", ""));
}

View File

@ -34,19 +34,27 @@
#pragma once
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
namespace musik { namespace core { namespace db { namespace local {
class LyricsQuery : public musik::core::db::LocalQueryBase {
class LyricsQuery: public musik::core::db::QueryBase {
public:
static const std::string kQueryName;
LyricsQuery(const std::string& trackExternalId);
virtual ~LyricsQuery();
std::string Name() { return "LyricsQuery"; }
/* IQuery */
std::string Name() { return kQueryName; }
virtual std::string GetResult();
/* ISerializableQuery */
virtual std::string SerializeQuery();
virtual std::string SerializeResult();
virtual void DeserializeResult(const std::string& data);
static std::shared_ptr<LyricsQuery> DeserializeQuery(const std::string& data);
protected:
virtual bool OnRun(musik::core::db::Connection &db);

View File

@ -34,11 +34,11 @@
#pragma once
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
namespace musik { namespace core { namespace db { namespace local {
class MarkTrackPlayedQuery: public musik::core::db::LocalQueryBase {
class MarkTrackPlayedQuery: public musik::core::db::QueryBase {
public:
MarkTrackPlayedQuery(const int64_t trackId);
virtual ~MarkTrackPlayedQuery();

View File

@ -34,7 +34,7 @@
#pragma once
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <core/audio/PlaybackService.h>
#include "TrackListQueryBase.h"

View File

@ -34,12 +34,12 @@
#pragma once
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <core/audio/PlaybackService.h>
namespace musik { namespace core { namespace db { namespace local {
class PersistedPlayQueueQuery : public musik::core::db::LocalQueryBase {
class PersistedPlayQueueQuery : public musik::core::db::QueryBase {
public:
static PersistedPlayQueueQuery* Save(
musik::core::ILibraryPtr library,

View File

@ -34,7 +34,7 @@
#pragma once
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <core/library/track/TrackList.h>
#include <core/db/Connection.h>
#include <core/library/ILibrary.h>
@ -42,7 +42,7 @@
namespace musik { namespace core { namespace db { namespace local {
class SavePlaylistQuery : public musik::core::db::LocalQueryBase {
class SavePlaylistQuery : public musik::core::db::QueryBase {
public:
static std::shared_ptr<SavePlaylistQuery> Save(
musik::core::ILibraryPtr library,

View File

@ -34,11 +34,11 @@
#pragma once
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
namespace musik { namespace core { namespace db { namespace local {
class SetTrackRatingQuery: public musik::core::db::LocalQueryBase {
class SetTrackRatingQuery: public musik::core::db::QueryBase {
public:
SetTrackRatingQuery(int64_t trackId, int rating);
virtual ~SetTrackRatingQuery();

View File

@ -34,14 +34,14 @@
#pragma once
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <core/db/Connection.h>
#include <core/library/track/Track.h>
#include <core/library/track/TrackList.h>
namespace musik { namespace core { namespace db { namespace local {
class TrackListQueryBase : public musik::core::db::LocalQueryBase {
class TrackListQueryBase : public musik::core::db::QueryBase {
public:
typedef std::shared_ptr<musik::core::TrackList> Result;
typedef std::shared_ptr<std::set<size_t> > Headers;

View File

@ -32,13 +32,13 @@
//
//////////////////////////////////////////////////////////////////////////////
#include "LocalQueryBase.h"
#include <core/library/QueryBase.h>
#include <core/library/track/Track.h>
namespace musik { namespace core { namespace db { namespace local {
class TrackMetadataQuery : public LocalQueryBase {
class TrackMetadataQuery : public QueryBase {
public:
enum Type { Full, IdsOnly };

View File

@ -35,7 +35,7 @@
#include "pch.hpp"
#include "TrackList.h"
#include <core/library/query/local/LocalQueryBase.h>
#include <core/library/QueryBase.h>
#include <core/library/track/LibraryTrack.h>
#include <core/library/LocalLibraryConstants.h>
#include <core/library/track/Track.h>

View File

@ -38,6 +38,7 @@
#include <core/support/Auddio.h>
#include <core/support/Common.h>
#include <core/library/query/local/LyricsQuery.h>
#include <core/library/RemoteLibrary.h>
#include <cursespp/App.h>
#include <cursespp/Screen.h>
#include <cursespp/ToastOverlay.h>
@ -71,6 +72,9 @@ LyricsLayout::LyricsLayout(PlaybackService& playback, ILibraryPtr library)
this->AddWindow(this->infoText);
this->LoadLyricsForCurrentTrack();
this->remoteLibrary = musik::core::library::RemoteLibrary::Create("remote", 0xdeadbeef);
this->remoteLibrary->SetMessageQueue(Window::MessageQueue());
}
void LyricsLayout::OnLayout() {
@ -137,7 +141,7 @@ void LyricsLayout::LoadLyricsForCurrentTrack() {
this->SetState(State::Loading);
auto trackExternalId = track->GetString("external_id");
auto lyricsDbQuery = std::make_shared<LyricsQuery>(trackExternalId);
this->library->Enqueue(lyricsDbQuery, 0, [this, lyricsDbQuery, track](auto q) {
this->remoteLibrary->Enqueue(lyricsDbQuery, 0, [this, lyricsDbQuery, track](auto q) {
auto localLyrics = lyricsDbQuery->GetResult();
if (localLyrics.size()) {
this->OnLyricsLoaded(track, localLyrics);

View File

@ -28,9 +28,6 @@ namespace musik { namespace cube {
private:
enum class State: int { NotPlaying, Loading, Loaded, Failed };
void OnAdapterChanged(cursespp::SimpleScrollAdapter* adapter);
void OnSelectionChanged(cursespp::ListWindow* window, size_t index, size_t prev);
void OnPlaybackEvent(int playbackEvent);
void OnTrackChanged(size_t index, musik::core::TrackPtr track);
void OnLyricsLoaded(musik::core::TrackPtr track, const std::string& lyrics);
@ -39,7 +36,7 @@ namespace musik { namespace cube {
void UpdateAdapter(const std::string& lyrics);
State state { State::NotPlaying };
musik::core::ILibraryPtr library;
musik::core::ILibraryPtr library, remoteLibrary;
musik::core::audio::PlaybackService& playback;
std::shared_ptr<cursespp::SimpleScrollAdapter> adapter;
std::shared_ptr<cursespp::ListWindow> listView;