mirror of
https://github.com/clangen/musikcube.git
synced 2025-02-11 09:40:26 +00:00
- Query::ListSelection and Query::TrackMetadata are fully working with Library::Remote.
- Fixed a tracklist issue where the tracklist where sending 1 query for each track. - Threading issues fixed in Library::Remote and server::Connection.
This commit is contained in:
parent
621afdf5cc
commit
c12a02487b
@ -141,7 +141,7 @@ utfstring musik::core::GetPath(const utfstring &sFile){
|
||||
///\returns
|
||||
///Converted string
|
||||
//////////////////////////////////////////
|
||||
std::string musik::core::ConvertUTF8(std::wstring &sString){
|
||||
std::string musik::core::ConvertUTF8(const std::wstring &sString){
|
||||
std::string sUTF8;
|
||||
utf8::utf16to8(sString.begin(),sString.end(),std::back_inserter(sUTF8));
|
||||
return sUTF8;
|
||||
@ -157,7 +157,7 @@ std::string musik::core::ConvertUTF8(std::wstring &sString){
|
||||
///\returns
|
||||
///Converted string
|
||||
//////////////////////////////////////////
|
||||
std::wstring musik::core::ConvertUTF16(std::string &sString){
|
||||
std::wstring musik::core::ConvertUTF16(const std::string &sString){
|
||||
std::wstring sUTF16;
|
||||
utf8::utf8to16(sString.begin(),sString.end(),std::back_inserter(sUTF16));
|
||||
return sUTF16;
|
||||
|
@ -61,8 +61,8 @@ namespace musik{ namespace core{
|
||||
*****************************/
|
||||
utfstring GetPluginDirectory();
|
||||
|
||||
std::string ConvertUTF8(std::wstring &sString);
|
||||
std::wstring ConvertUTF16(std::string &sString);
|
||||
std::string ConvertUTF8(const std::wstring &sString);
|
||||
std::wstring ConvertUTF16(const std::string &sString);
|
||||
std::wstring ConvertUTF16(const char *string);
|
||||
|
||||
UINT64 Checksum(char *data,unsigned int bytes);
|
||||
|
@ -144,6 +144,7 @@ utfstring Library::Base::GetDBPath(){
|
||||
/// - Query::Options::CancelQueue : Cancel all other queries that are to be executed by the Library.
|
||||
/// - Query::Options::CancelSimilar : Cancel all similar queries. A similar query is a query that originates from the same Query::Base that is passed to the AddQuery.
|
||||
/// - Query::Options::UnCanceable : Under no circumstances is this Query allowed to be canceled.
|
||||
/// - Query::Options::UnCanceable : Under no circumstances is this Query allowed to be canceled.
|
||||
///
|
||||
///The query will be copied by the library and executed in the library thread.
|
||||
///
|
||||
@ -159,6 +160,11 @@ bool Library::Base::AddQuery( const Query::Base &query,unsigned int options ){
|
||||
// Start by making a copy
|
||||
Query::Ptr queryCopy( query.copy() );
|
||||
|
||||
//
|
||||
if(options&Query::CopyUniqueId){
|
||||
queryCopy->uniqueId = query.uniqueId;
|
||||
}
|
||||
|
||||
queryCopy->PreAddQuery(this);
|
||||
|
||||
// Since query is not added to queue yet, variables can now be changed without locking.
|
||||
|
@ -125,9 +125,12 @@ void Library::Remote::ReadThread(){
|
||||
boost::system::error_code error = boost::asio::error::host_not_found;
|
||||
while (error && endpointIterator!=end){
|
||||
this->socket.close();
|
||||
this->socket.connect(*endpointIterator++, error);
|
||||
this->socket.connect(*endpointIterator, error);
|
||||
if(error){
|
||||
endpointIterator++;
|
||||
}
|
||||
}
|
||||
if (error){
|
||||
if (error || endpointIterator==end){
|
||||
this->Exit();
|
||||
return;
|
||||
}
|
||||
@ -159,6 +162,7 @@ void Library::Remote::ReadThread(){
|
||||
if(node.Name()=="queryresults"){
|
||||
|
||||
unsigned int queryId = boost::lexical_cast<unsigned int>(node.Attributes()["id"]);
|
||||
unsigned int uniqueId = boost::lexical_cast<unsigned int>(node.Attributes()["uid"]);
|
||||
Query::Ptr currentQuery;
|
||||
// This is a query node
|
||||
// Find the query in the outgoingQueries list
|
||||
@ -166,15 +170,17 @@ void Library::Remote::ReadThread(){
|
||||
boost::mutex::scoped_lock lock(this->libraryMutex);
|
||||
// Reverse loop since it's most likely the query is in the end
|
||||
for(QueryList::reverse_iterator query=this->outgoingQueries.rbegin();query!=this->outgoingQueries.rend();++query){
|
||||
if( (*query)->queryId==queryId ){
|
||||
if( (*query)->uniqueId==uniqueId ){
|
||||
currentQuery = *query;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(currentQuery){
|
||||
if(currentQuery->RecieveResults(node,this)){
|
||||
boost::mutex::scoped_lock lock(this->libraryMutex);
|
||||
currentQuery->status |= Query::Base::Status::Ended;
|
||||
}else{
|
||||
boost::mutex::scoped_lock lock(this->libraryMutex);
|
||||
currentQuery->status |= Query::Base::Status::Canceled | Query::Base::Status::Ended;
|
||||
}
|
||||
}
|
||||
@ -214,7 +220,7 @@ void Library::Remote::WriteThread(){
|
||||
this->outgoingQueries.push_back(query);
|
||||
|
||||
// Set query as started
|
||||
// query->status |= Query::Base::Status::Started;
|
||||
query->status |= Query::Base::Status::Started;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -222,6 +228,7 @@ void Library::Remote::WriteThread(){
|
||||
xml::WriterNode queryNode(rootNode,"query");
|
||||
queryNode.Attributes()["type"] = query->Name();
|
||||
queryNode.Attributes()["id"] = boost::lexical_cast<std::string>(query->queryId);
|
||||
queryNode.Attributes()["uid"] = boost::lexical_cast<std::string>(query->uniqueId);
|
||||
|
||||
if(query->options){
|
||||
queryNode.Attributes()["options"] = boost::lexical_cast<std::string>(query->options);
|
||||
@ -233,6 +240,10 @@ void Library::Remote::WriteThread(){
|
||||
query->status |= Query::Base::Status::Canceled | Query::Base::Status::Ended;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Notify that the Query is finished.
|
||||
this->waitCondition.notify_all();
|
||||
|
||||
// Check if writer has quit
|
||||
if(writer.Exited()){
|
||||
this->Exit();
|
||||
@ -265,3 +276,15 @@ void Library::Remote::CancelCurrentQuery( ){
|
||||
}
|
||||
|
||||
|
||||
void Library::Remote::Exit(){
|
||||
{
|
||||
boost::mutex::scoped_lock lock(this->libraryMutex);
|
||||
if(!this->exit){
|
||||
if(this->socket.is_open()){
|
||||
this->socket.close();
|
||||
}
|
||||
}
|
||||
this->exit = true;
|
||||
}
|
||||
this->waitCondition.notify_all();
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ class Remote : public Library::Base{
|
||||
|
||||
protected:
|
||||
void CancelCurrentQuery( );
|
||||
virtual void Exit();
|
||||
|
||||
private:
|
||||
// Methods:
|
||||
|
@ -38,18 +38,22 @@
|
||||
|
||||
#include <core/Query/Base.h>
|
||||
#include <core/Library/Base.h>
|
||||
#include <core/xml/ParserNode.h>
|
||||
#include <core/xml/WriterNode.h>
|
||||
|
||||
using namespace musik::core;
|
||||
|
||||
Query::Base::Base(void)
|
||||
:status(0)
|
||||
,options(0)
|
||||
,uniqueId(0)
|
||||
{
|
||||
// This will guarantee that the query id is uniq for each query, but copies will not.
|
||||
// This is usefull when canceling similar queries
|
||||
static unsigned int uniqueQueryId(0);
|
||||
uniqueQueryId++;
|
||||
this->queryId = uniqueQueryId;
|
||||
this->queryId = uniqueQueryId;
|
||||
|
||||
}
|
||||
|
||||
Query::Base::~Base(void){
|
||||
@ -114,3 +118,10 @@ bool Query::Base::SendResults(musik::core::xml::WriterNode &queryNode,Library::B
|
||||
std::string Query::Base::Name(){
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
void Query::Base::PostCopy(){
|
||||
static unsigned int uniqueQueryId(0);
|
||||
uniqueQueryId++;
|
||||
this->uniqueId = uniqueQueryId;
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,10 @@ namespace musik{ namespace core{
|
||||
namespace server{
|
||||
class Connection;
|
||||
}
|
||||
namespace xml{
|
||||
class ParserNode;
|
||||
class WriterNode;
|
||||
}
|
||||
} }
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -57,8 +61,6 @@ namespace musik{ namespace core{
|
||||
#include <sigslot/sigslot.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <core/xml/ParserNode.h>
|
||||
#include <core/xml/WriterNode.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -74,7 +76,8 @@ enum Options:unsigned int{
|
||||
Prioritize = 4,
|
||||
CancelQueue = 8,
|
||||
CancelSimilar = 16,
|
||||
UnCanceable = 32
|
||||
UnCanceable = 32,
|
||||
CopyUniqueId = 64
|
||||
};
|
||||
|
||||
//////////////////////////////////////////
|
||||
@ -122,6 +125,7 @@ class Base : public sigslot::has_slots<> {
|
||||
///Used for comparing queries and find similar queries.
|
||||
//////////////////////////////////////////
|
||||
unsigned int queryId;
|
||||
unsigned int uniqueId;
|
||||
|
||||
//////////////////////////////////////////
|
||||
///\brief
|
||||
@ -205,6 +209,9 @@ class Base : public sigslot::has_slots<> {
|
||||
virtual bool SendQuery(musik::core::xml::WriterNode &queryNode);
|
||||
virtual bool RecieveResults(musik::core::xml::ParserNode &queryNode,Library::Base *library);
|
||||
virtual bool SendResults(musik::core::xml::WriterNode &queryNode,Library::Base *library);
|
||||
|
||||
public:
|
||||
void PostCopy();
|
||||
};
|
||||
|
||||
|
||||
|
@ -38,6 +38,8 @@
|
||||
#include <core/Query/ListBase.h>
|
||||
#include <core/Library/Base.h>
|
||||
#include <core/Common.h>
|
||||
#include <core/xml/ParserNode.h>
|
||||
#include <core/xml/WriterNode.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
using namespace musik::core;
|
||||
@ -384,4 +386,54 @@ void Query::ListBase::DummySlotTrackInfo(UINT64,UINT64,UINT64){
|
||||
}
|
||||
|
||||
|
||||
bool Query::ListBase::RecieveQueryStandardNodes(musik::core::xml::ParserNode &node){
|
||||
if(node.Name()=="listeners"){
|
||||
|
||||
// Wait for all content
|
||||
node.WaitForContent();
|
||||
|
||||
// Secondly, lets look for what to query for
|
||||
// Split comaseparated list
|
||||
typedef std::vector<std::string> StringVector;
|
||||
StringVector keys;
|
||||
boost::algorithm::split(keys,node.Content(),boost::algorithm::is_any_of(","));
|
||||
|
||||
for(StringVector::iterator key=keys.begin();key!=keys.end();++key){
|
||||
if(!key->empty()){
|
||||
// connect dummy to the signals
|
||||
this->OnMetadataEvent(key->c_str()).connect( (Query::ListBase*)this,&Query::ListBase::DummySlot);
|
||||
}
|
||||
}
|
||||
}else if(node.Name()=="listtracks"){
|
||||
this->OnTrackEvent().connect( (Query::ListBase*)this,&Query::ListBase::DummySlotTracks);
|
||||
}else if(node.Name()=="listtrackinfo"){
|
||||
this->OnTrackInfoEvent().connect( (Query::ListBase*)this,&Query::ListBase::DummySlotTrackInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <listeners>genre,artist,album</listeners>
|
||||
bool Query::ListBase::SendQueryStandardNodes(musik::core::xml::WriterNode &queryNode){
|
||||
// Then the listeners
|
||||
xml::WriterNode listenersNode(queryNode,"listeners");
|
||||
for(MetadataSignals::iterator listener=this->metadataEvent.begin();listener!=this->metadataEvent.end();++listener){
|
||||
if( listener->second.has_connections() ){
|
||||
if(!listenersNode.Content().empty()){
|
||||
listenersNode.Content().append(",");
|
||||
}
|
||||
listenersNode.Content().append(listener->first);
|
||||
}
|
||||
}
|
||||
// Then the track listener
|
||||
if( this->trackEvent.has_connections() ){
|
||||
xml::WriterNode listTracksNode(queryNode,"listtracks");
|
||||
listTracksNode.Content().append("true");
|
||||
}
|
||||
// Then the track listener
|
||||
if( this->trackInfoEvent.has_connections() ){
|
||||
xml::WriterNode listTrackInfoNode(queryNode,"listtrackinfo");
|
||||
listTrackInfoNode.Content().append("true");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -49,10 +49,6 @@
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Forward declarations
|
||||
//////////////////////////////////////////////////////////////
|
||||
/*namespace musik{ namespace core{
|
||||
class Track;
|
||||
} }
|
||||
*/
|
||||
|
||||
|
||||
namespace musik{ namespace core{
|
||||
@ -78,6 +74,9 @@ namespace musik{ namespace core{
|
||||
|
||||
bool ParseTracksSQL(std::string sql,Library::Base *library,db::Connection &db);
|
||||
|
||||
bool RecieveQueryStandardNodes(musik::core::xml::ParserNode &node);
|
||||
bool SendQueryStandardNodes(musik::core::xml::WriterNode &queryNode);
|
||||
|
||||
MetadataResults metadataResults;
|
||||
TrackVector trackResults;
|
||||
|
||||
|
@ -37,6 +37,8 @@
|
||||
#include "pch.hpp"
|
||||
#include <core/Query/ListSelection.h>
|
||||
#include <core/Library/Base.h>
|
||||
#include <core/xml/ParserNode.h>
|
||||
#include <core/xml/WriterNode.h>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
@ -459,7 +461,9 @@ bool Query::ListSelection::ParseQuery(Library::Base *library,db::Connection &db)
|
||||
///A shared_ptr to the Query::Base
|
||||
//////////////////////////////////////////
|
||||
Query::Ptr Query::ListSelection::copy() const{
|
||||
return Query::Ptr(new Query::ListSelection(*this));
|
||||
Query::Ptr queryCopy(new Query::ListSelection(*this));
|
||||
queryCopy->PostCopy();
|
||||
return queryCopy;
|
||||
}
|
||||
|
||||
void Query::ListSelection::SQLPrependWhereOrAnd(std::string &sql){
|
||||
@ -571,12 +575,10 @@ bool Query::ListSelection::RecieveQuery(musik::core::xml::ParserNode &queryNode)
|
||||
|
||||
while( musik::core::xml::ParserNode node = queryNode.ChildNode() ){
|
||||
if(node.Name()=="selections"){
|
||||
std::cout << "<selections>";
|
||||
// Get metakey nodes
|
||||
// Expected tag is likle this:
|
||||
// <selection key="genre">2,5,3</selection>
|
||||
while( musik::core::xml::ParserNode selectionNode = node.ChildNode("selection") ){
|
||||
std::cout << "<selection key=\"" << selectionNode.Attributes()["key"] << "\">";
|
||||
|
||||
// Wait for all content
|
||||
selectionNode.WaitForContent();
|
||||
@ -588,34 +590,12 @@ bool Query::ListSelection::RecieveQuery(musik::core::xml::ParserNode &queryNode)
|
||||
|
||||
for(StringVector::iterator value=values.begin();value!=values.end();++value){
|
||||
this->SelectMetadata(selectionNode.Attributes()["key"].c_str(),boost::lexical_cast<DBINT>(*value));
|
||||
std::cout << "," << *value;
|
||||
}
|
||||
std::cout << "</selection>" << std::endl;
|
||||
|
||||
}
|
||||
std::cout << "</selections>" << std::endl;
|
||||
|
||||
}else if(node.Name()=="listeners"){
|
||||
|
||||
// Wait for all content
|
||||
node.WaitForContent();
|
||||
|
||||
// Secondly, lets look for what to query for
|
||||
// Split comaseparated list
|
||||
typedef std::vector<std::string> StringVector;
|
||||
StringVector keys;
|
||||
boost::algorithm::split(keys,node.Content(),boost::algorithm::is_any_of(","));
|
||||
|
||||
for(StringVector::iterator key=keys.begin();key!=keys.end();++key){
|
||||
if(!key->empty()){
|
||||
// connect dummy to the signals
|
||||
this->OnMetadataEvent(key->c_str()).connect( (Query::ListBase*)this,&Query::ListBase::DummySlot);
|
||||
}
|
||||
}
|
||||
}else if(node.Name()=="listtracks"){
|
||||
this->OnTrackEvent().connect( (Query::ListBase*)this,&Query::ListBase::DummySlotTracks);
|
||||
}else if(node.Name()=="listtrackinfo"){
|
||||
this->OnTrackInfoEvent().connect( (Query::ListBase*)this,&Query::ListBase::DummySlotTrackInfo);
|
||||
}else{
|
||||
this->RecieveQueryStandardNodes(node);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -625,12 +605,11 @@ std::string Query::ListSelection::Name(){
|
||||
return "ListSelection";
|
||||
}
|
||||
|
||||
bool Query::ListSelection::SendQuery(musik::core::xml::WriterNode &queryNode){
|
||||
/// <selections>
|
||||
/// <selection key="genre">1,3,5,7</selection>
|
||||
/// <selection key="artist">6,7,8</selection>
|
||||
/// </selections>
|
||||
/// <listeners>genre,artist,album</listeners>
|
||||
bool Query::ListSelection::SendQuery(musik::core::xml::WriterNode &queryNode){
|
||||
xml::WriterNode selectionsNode(queryNode,"selections");
|
||||
|
||||
// Start with the selection nodes
|
||||
@ -651,26 +630,8 @@ bool Query::ListSelection::SendQuery(musik::core::xml::WriterNode &queryNode){
|
||||
|
||||
}
|
||||
|
||||
// Then the listeners
|
||||
xml::WriterNode listenersNode(queryNode,"listeners");
|
||||
for(MetadataSignals::iterator listener=this->metadataEvent.begin();listener!=this->metadataEvent.end();++listener){
|
||||
if( listener->second.has_connections() ){
|
||||
if(!listenersNode.Content().empty()){
|
||||
listenersNode.Content().append(",");
|
||||
}
|
||||
listenersNode.Content().append(listener->first);
|
||||
}
|
||||
}
|
||||
// Then the track listener
|
||||
if( this->trackEvent.has_connections() ){
|
||||
xml::WriterNode listTracksNode(queryNode,"listtracks");
|
||||
listTracksNode.Content().append("true");
|
||||
}
|
||||
// Then the track listener
|
||||
if( this->trackInfoEvent.has_connections() ){
|
||||
xml::WriterNode listTrackInfoNode(queryNode,"listtrackinfo");
|
||||
listTrackInfoNode.Content().append("true");
|
||||
}
|
||||
this->SendQueryStandardNodes(queryNode);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
@ -39,11 +39,7 @@
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Forward declarations
|
||||
//////////////////////////////////////////////////////////////
|
||||
namespace musik{ namespace core{
|
||||
namespace Library{
|
||||
class Base;
|
||||
}
|
||||
} }
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
@ -38,6 +38,9 @@
|
||||
#include <core/Query/SortTracks.h>
|
||||
#include <core/Library/Base.h>
|
||||
#include <core/config_format.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <core/xml/ParserNode.h>
|
||||
#include <core/xml/WriterNode.h>
|
||||
|
||||
using namespace musik::core;
|
||||
|
||||
@ -177,7 +180,9 @@ bool Query::SortTracks::ParseQuery(Library::Base *library,db::Connection &db){
|
||||
///A shared_ptr to the Query::Base
|
||||
//////////////////////////////////////////
|
||||
Query::Ptr Query::SortTracks::copy() const{
|
||||
return Query::Ptr(new Query::SortTracks(*this));
|
||||
Query::Ptr queryCopy(new Query::SortTracks(*this));
|
||||
queryCopy->PostCopy();
|
||||
return queryCopy;
|
||||
}
|
||||
|
||||
void Query::SortTracks::AddTrack(int trackId){
|
||||
@ -207,3 +212,68 @@ void Query::SortTracks::ClearTracks(){
|
||||
this->tracksToSort.clear();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
///\brief
|
||||
///Recieve the query from XML
|
||||
///
|
||||
///\param queryNode
|
||||
///Reference to query XML node
|
||||
///
|
||||
///The excpeted input format is like this:
|
||||
///\code
|
||||
///<query type="SortTracks">
|
||||
/// <tracks>1,3,5,7</tracks>
|
||||
///</query>
|
||||
///\endcode
|
||||
///
|
||||
///\returns
|
||||
///true when successfully recieved
|
||||
//////////////////////////////////////////
|
||||
bool Query::SortTracks::RecieveQuery(musik::core::xml::ParserNode &queryNode){
|
||||
|
||||
while( musik::core::xml::ParserNode node = queryNode.ChildNode() ){
|
||||
if(node.Name()=="tracks"){
|
||||
node.WaitForContent();
|
||||
|
||||
typedef std::vector<std::string> StringVector;
|
||||
StringVector values;
|
||||
|
||||
try{ // lexical_cast can throw
|
||||
boost::algorithm::split(values,node.Content(),boost::algorithm::is_any_of(","));
|
||||
for(StringVector::iterator value=values.begin();value!=values.end();++value){
|
||||
this->tracksToSort.push_back( boost::lexical_cast<DBINT>(*value) );
|
||||
}
|
||||
}
|
||||
catch(...){
|
||||
return false;
|
||||
}
|
||||
|
||||
}else{
|
||||
this->RecieveQueryStandardNodes(node);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Query::SortTracks::Name(){
|
||||
return "SortTracks";
|
||||
}
|
||||
|
||||
bool Query::SortTracks::SendQuery(musik::core::xml::WriterNode &queryNode){
|
||||
{
|
||||
xml::WriterNode tracksNode(queryNode,"tracks");
|
||||
|
||||
for(IntVector::iterator trackId=this->tracksToSort.begin();trackId!=this->tracksToSort.end();++trackId){
|
||||
if(!tracksNode.Content().empty()){
|
||||
tracksNode.Content().append(",");
|
||||
}
|
||||
tracksNode.Content().append(boost::lexical_cast<std::string>(*trackId));
|
||||
}
|
||||
}
|
||||
|
||||
this->SendQueryStandardNodes(queryNode);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
@ -46,14 +46,7 @@
|
||||
#include <core/Query/ListBase.h>
|
||||
#include <core/tracklist/IRandomAccess.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Forward declarations
|
||||
//////////////////////////////////////////////////////////////
|
||||
namespace musik{ namespace core{
|
||||
namespace Library{
|
||||
class Base;
|
||||
}
|
||||
} }
|
||||
|
||||
|
||||
|
||||
namespace musik{ namespace core{
|
||||
@ -74,17 +67,22 @@ namespace musik{ namespace core{
|
||||
|
||||
protected:
|
||||
|
||||
std::vector<int> tracksToSort;
|
||||
typedef std::vector<int> IntVector;
|
||||
IntVector tracksToSort;
|
||||
std::list<std::string> sortMetaKeys;
|
||||
|
||||
|
||||
friend class Library::Base;
|
||||
friend class Library::LocalDB;
|
||||
|
||||
virtual bool ParseQuery(Library::Base *library,db::Connection &db);
|
||||
|
||||
Ptr copy() const;
|
||||
|
||||
virtual std::string Name();
|
||||
virtual bool ParseQuery(Library::Base *library,db::Connection &db);
|
||||
virtual bool RecieveQuery(musik::core::xml::ParserNode &queryNode);
|
||||
virtual bool SendQuery(musik::core::xml::WriterNode &queryNode);
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
@ -36,8 +36,10 @@
|
||||
|
||||
#include "pch.hpp"
|
||||
|
||||
#include <core/Common.h>
|
||||
#include <core/Query/TrackMetadata.h>
|
||||
#include <core/Library/Base.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
using namespace musik::core;
|
||||
using namespace musik::core::Query;
|
||||
@ -243,7 +245,7 @@ bool TrackMetadata::RunCallbacks(Library::Base *library){
|
||||
|
||||
// First swap the results so that Query can continue to parse
|
||||
{
|
||||
boost::mutex::scoped_lock oLock(library->oResultMutex);
|
||||
boost::mutex::scoped_lock lock(library->oResultMutex);
|
||||
aResultCopy.swap(this->aResultTracks);
|
||||
|
||||
if( (this->status & Status::Ended)!=0){
|
||||
@ -288,7 +290,9 @@ void TrackMetadata::RequestAllMetakeys(){
|
||||
}
|
||||
|
||||
Query::Ptr TrackMetadata::copy() const{
|
||||
return Query::Ptr(new Query::TrackMetadata(*this));
|
||||
Query::Ptr queryCopy(new Query::TrackMetadata(*this));
|
||||
queryCopy->PostCopy();
|
||||
return queryCopy;
|
||||
}
|
||||
|
||||
void TrackMetadata::PreAddQuery(Library::Base *library){
|
||||
@ -297,4 +301,170 @@ void TrackMetadata::PreAddQuery(Library::Base *library){
|
||||
}
|
||||
}
|
||||
|
||||
std::string TrackMetadata::Name(){
|
||||
return "TrackMetadata";
|
||||
}
|
||||
|
||||
|
||||
bool TrackMetadata::RecieveQuery(musik::core::xml::ParserNode &queryNode){
|
||||
|
||||
while(musik::core::xml::ParserNode metakeysNode = queryNode.ChildNode()){
|
||||
if(metakeysNode.Name()=="metakeys"){
|
||||
if(metakeysNode.Attributes()["all"]=="true"){
|
||||
this->RequestAllMetakeys();
|
||||
}else{
|
||||
metakeysNode.WaitForContent();
|
||||
|
||||
StringSet values;
|
||||
|
||||
try{ // lexical_cast can throw
|
||||
boost::algorithm::split(values,metakeysNode.Content(),boost::algorithm::is_any_of(","));
|
||||
this->RequestMetakeys(values);
|
||||
}
|
||||
catch(...){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}else if(metakeysNode.Name()=="tracks"){
|
||||
metakeysNode.WaitForContent();
|
||||
|
||||
typedef std::vector<std::string> StringVector;
|
||||
StringVector values;
|
||||
try{ // lexical_cast can throw
|
||||
boost::algorithm::split(values,metakeysNode.Content(),boost::algorithm::is_any_of(","));
|
||||
for(StringVector::iterator value=values.begin();value!=values.end();++value){
|
||||
this->RequestTrack(TrackPtr(new Track( boost::lexical_cast<DBINT>(*value) )));
|
||||
}
|
||||
}
|
||||
catch(...){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool TrackMetadata::SendQuery(musik::core::xml::WriterNode &queryNode){
|
||||
{
|
||||
musik::core::xml::WriterNode metakeysNode(queryNode,"metakeys");
|
||||
if(this->requestAllFields){
|
||||
metakeysNode.Attributes()["all"] = "true";
|
||||
}else{
|
||||
for(StringSet::iterator metakey=this->requestedFields.begin();metakey!=this->requestedFields.end();++metakey){
|
||||
if(!metakeysNode.Content().empty()){
|
||||
metakeysNode.Content().append(",");
|
||||
}
|
||||
metakeysNode.Content().append(*metakey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
musik::core::xml::WriterNode tracksNode(queryNode,"tracks");
|
||||
|
||||
for(TrackVector::iterator track=this->aRequestTracks.begin();track!=this->aRequestTracks.end();++track){
|
||||
if(!tracksNode.Content().empty()){
|
||||
tracksNode.Content().append(",");
|
||||
}
|
||||
tracksNode.Content().append( boost::lexical_cast<std::string>( (*track)->id ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool TrackMetadata::SendResults(musik::core::xml::WriterNode &queryNode,Library::Base *library){
|
||||
|
||||
bool continueSending(true);
|
||||
|
||||
while(continueSending){
|
||||
TrackVector resultCopy;
|
||||
{
|
||||
boost::mutex::scoped_lock lock(library->oResultMutex);
|
||||
resultCopy.swap(this->aResultTracks);
|
||||
|
||||
if( (this->status & Status::Ended)!=0){
|
||||
continueSending = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Send the results
|
||||
if( !resultCopy.empty() ){
|
||||
try{
|
||||
for(TrackVector::iterator track=resultCopy.begin();track!=resultCopy.end();++track){
|
||||
musik::core::xml::WriterNode trackNode(queryNode,"t");
|
||||
trackNode.Attributes()["id"] = boost::lexical_cast<std::string>( (*track)->id );
|
||||
|
||||
TrackMeta::TagMapIteratorPair metaDatas( (*track)->GetAllValues() );
|
||||
for(TrackMeta::TagMapConstIterator metaData=metaDatas.first;metaData!=metaDatas.second;++metaData){
|
||||
musik::core::xml::WriterNode metaDataNode(trackNode,"md");
|
||||
metaDataNode.Attributes()["k"] = metaData->first;
|
||||
metaDataNode.Content().append( ConvertUTF8(metaData->second) );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch(...){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for more results
|
||||
if( continueSending && resultCopy.empty()){
|
||||
boost::thread::yield();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool TrackMetadata::RecieveResults(musik::core::xml::ParserNode &queryNode,Library::Base *library){
|
||||
|
||||
while(musik::core::xml::ParserNode trackNode=queryNode.ChildNode("t") ){
|
||||
try{
|
||||
DBINT trackId( boost::lexical_cast<DBINT>(trackNode.Attributes()["id"]) );
|
||||
|
||||
// Find the track in the aRequestTracks
|
||||
TrackVector::iterator track=this->aRequestTracks.begin();
|
||||
bool trackFound(false);
|
||||
while(track!=this->aRequestTracks.end() && !trackFound){
|
||||
if( (*track)->id==trackId ){
|
||||
// TrackPtr found
|
||||
trackFound = true;
|
||||
}else{
|
||||
++track;
|
||||
}
|
||||
}
|
||||
if(track!=this->aRequestTracks.end() && trackFound){
|
||||
TrackPtr currentTrack(*track);
|
||||
|
||||
// Remove the track from the aRequestTracks
|
||||
this->aRequestTracks.erase(track);
|
||||
|
||||
// Get the metadata
|
||||
while(musik::core::xml::ParserNode metadataNode=trackNode.ChildNode("md") ){
|
||||
metadataNode.WaitForContent();
|
||||
currentTrack->SetValue( metadataNode.Attributes()["k"].c_str(),ConvertUTF16(metadataNode.Content()).c_str());
|
||||
}
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock oLock(library->oResultMutex);
|
||||
this->aResultTracks.push_back(currentTrack);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(...){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -72,10 +72,11 @@ class TrackMetadata : public Query::Base {
|
||||
TrackMetadataEvent OnTracksEvent;
|
||||
|
||||
private:
|
||||
std::set<std::string> requestedFields;
|
||||
typedef std::set<std::string> StringSet;
|
||||
StringSet requestedFields;
|
||||
std::vector<std::string> fieldOrder;
|
||||
std::set<std::string> metaFields;
|
||||
std::set<std::string> categoryFields;
|
||||
StringSet metaFields;
|
||||
StringSet categoryFields;
|
||||
std::string sSQL;
|
||||
std::string sSQLTables;
|
||||
std::string sSQLWhere;
|
||||
@ -89,9 +90,17 @@ class TrackMetadata : public Query::Base {
|
||||
protected:
|
||||
friend class Library::Base;
|
||||
friend class Library::LocalDB;
|
||||
bool ParseQuery(Library::Base *library,db::Connection &db);
|
||||
Ptr copy() const;
|
||||
void PreAddQuery(Library::Base *library);
|
||||
|
||||
virtual bool ParseQuery(Library::Base *library,db::Connection &db);
|
||||
|
||||
virtual std::string Name();
|
||||
virtual bool RecieveQuery(musik::core::xml::ParserNode &queryNode);
|
||||
virtual bool SendQuery(musik::core::xml::WriterNode &queryNode);
|
||||
virtual bool SendResults(musik::core::xml::WriterNode &queryNode,Library::Base *library);
|
||||
virtual bool RecieveResults(musik::core::xml::ParserNode &queryNode,Library::Base *library);
|
||||
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -154,8 +154,8 @@ bool Track::CompareDBAndFileInfo(const boost::filesystem::utfpath &file,db::Conn
|
||||
this->SetValue("extension",file.leaf().substr(lastDot+1).c_str());
|
||||
}
|
||||
|
||||
DBINT fileSize = boost::filesystem::file_size(file);
|
||||
DBTIME fileTime = boost::filesystem::last_write_time(file);
|
||||
DBINT fileSize = (DBINT)boost::filesystem::file_size(file);
|
||||
DBTIME fileTime = (DBTIME)boost::filesystem::last_write_time(file);
|
||||
|
||||
this->SetValue("filesize",boost::lexical_cast<utfstring>(fileSize).c_str());
|
||||
this->SetValue("filetime",boost::lexical_cast<utfstring>(fileTime).c_str());
|
||||
|
@ -105,12 +105,20 @@ void Connection::ReadThread(){
|
||||
if(queryIt!=queryMap.end()){
|
||||
// Query type exists, lets create a copy
|
||||
musik::core::Query::Ptr query( queryIt->second->copy() );
|
||||
query->queryId = boost::lexical_cast<unsigned int>(queryNode.Attributes()["id"]);
|
||||
try{
|
||||
query->queryId = boost::lexical_cast<unsigned int>(queryNode.Attributes()["id"]);
|
||||
query->uniqueId = boost::lexical_cast<unsigned int>(queryNode.Attributes()["uid"]);
|
||||
}catch(...){}
|
||||
|
||||
if(query->RecieveQuery(queryNode)){
|
||||
|
||||
unsigned int options(0);
|
||||
try{
|
||||
options = boost::lexical_cast<unsigned int>(queryNode.Attributes()["options"]);
|
||||
}catch(...){}
|
||||
|
||||
// TODO: check for AddQuery options in tag
|
||||
this->AddQuery( *query,boost::lexical_cast<unsigned int>(queryNode.Attributes()["options"]) );
|
||||
this->AddQuery( *query,options|musik::core::Query::CopyUniqueId );
|
||||
|
||||
}
|
||||
|
||||
@ -213,6 +221,7 @@ void Connection::WriteThread(){
|
||||
musik::core::xml::WriterNode queryNode(musikNode,"queryresults");
|
||||
queryNode.Attributes()["type"] = sendQuery->Name();
|
||||
queryNode.Attributes()["id"] = boost::lexical_cast<std::string>(sendQuery->queryId);
|
||||
queryNode.Attributes()["uid"] = boost::lexical_cast<std::string>(sendQuery->uniqueId);
|
||||
|
||||
sendQuery->SendResults(queryNode,this);
|
||||
}
|
||||
|
@ -148,20 +148,22 @@ void Standard::OnTracksFromQuery(musik::core::TrackVector *newTracks,bool clear)
|
||||
}
|
||||
|
||||
void Standard::LoadTrack(int position){
|
||||
|
||||
int trackCount(0);
|
||||
|
||||
for(int i(position);i<position+this->hintedRows;++i){
|
||||
if(this->QueryForTrack(i)){
|
||||
++trackCount;
|
||||
if(this->QueryForTrack(position)){
|
||||
|
||||
int trackCount(1);
|
||||
|
||||
for(int i(position+1);i<position+this->hintedRows;++i){
|
||||
if(this->QueryForTrack(i)){
|
||||
++trackCount;
|
||||
}
|
||||
}
|
||||
|
||||
if(trackCount && this->library){
|
||||
this->library->AddQuery(this->trackQuery,musik::core::Query::Prioritize);
|
||||
this->trackQuery.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if(trackCount && this->library){
|
||||
this->library->AddQuery(this->trackQuery,musik::core::Query::Prioritize);
|
||||
this->trackQuery.Clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool Standard::QueryForTrack(int position){
|
||||
|
@ -38,6 +38,8 @@
|
||||
#include <core/xml/ParserNode.h>
|
||||
#include <expat/expat.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
using namespace musik::core::xml;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@ -157,6 +159,11 @@ void Parser::ReadFromSocket(){
|
||||
this->Exit();
|
||||
}
|
||||
|
||||
// Log
|
||||
// std::ofstream logFile("mc2_Parser.log",std::ios::app);
|
||||
// logFile.write(this->readBuffer.c_array(),this->readBufferLength);
|
||||
// logFile << std::endl;
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <core/xml/Writer.h>
|
||||
#include <core/xml/WriterNode.h>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <fstream>
|
||||
|
||||
using namespace musik::core::xml;
|
||||
|
||||
@ -175,9 +176,16 @@ void Writer::Send(){
|
||||
// Time to send the buffer
|
||||
if(!sendBuffer.empty()){
|
||||
boost::asio::write(*(this->socket),boost::asio::buffer(sendBuffer));
|
||||
// Log
|
||||
//std::ofstream logFile("mc2_Writer.log",std::ios::app);
|
||||
//logFile << sendBuffer << std::endl;
|
||||
|
||||
sendBuffer.clear();
|
||||
}
|
||||
}
|
||||
catch(boost::system::error_code &error){
|
||||
this->Exit();
|
||||
}
|
||||
catch(...){
|
||||
this->Exit();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user