From c12a02487b265fa48bc1269bd4a8bcfc14ba23a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96nnerby?= Date: Tue, 19 Aug 2008 11:28:38 +0000 Subject: [PATCH] - 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. --- src/core/Common.cpp | 4 +- src/core/Common.h | 4 +- src/core/Library/Base.cpp | 6 ++ src/core/Library/Remote.cpp | 31 +++++- src/core/Library/Remote.h | 1 + src/core/Query/Base.cpp | 13 ++- src/core/Query/Base.h | 13 ++- src/core/Query/ListBase.cpp | 52 +++++++++ src/core/Query/ListBase.h | 7 +- src/core/Query/ListSelection.cpp | 59 ++--------- src/core/Query/ListSelection.h | 6 +- src/core/Query/SortTracks.cpp | 72 ++++++++++++- src/core/Query/SortTracks.h | 18 ++-- src/core/Query/TrackMetadata.cpp | 174 ++++++++++++++++++++++++++++++- src/core/Query/TrackMetadata.h | 17 ++- src/core/Track.cpp | 4 +- src/core/server/Connection.cpp | 13 ++- src/core/tracklist/Standard.cpp | 24 +++-- src/core/xml/Parser.cpp | 7 ++ src/core/xml/Writer.cpp | 8 ++ 20 files changed, 431 insertions(+), 102 deletions(-) diff --git a/src/core/Common.cpp b/src/core/Common.cpp index 525e67223..5fbf2f429 100644 --- a/src/core/Common.cpp +++ b/src/core/Common.cpp @@ -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; diff --git a/src/core/Common.h b/src/core/Common.h index d895901a7..ddedb420c 100644 --- a/src/core/Common.h +++ b/src/core/Common.h @@ -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); diff --git a/src/core/Library/Base.cpp b/src/core/Library/Base.cpp index 1d8fd73ca..3e0d25234 100644 --- a/src/core/Library/Base.cpp +++ b/src/core/Library/Base.cpp @@ -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. diff --git a/src/core/Library/Remote.cpp b/src/core/Library/Remote.cpp index dd6d96921..61698f567 100644 --- a/src/core/Library/Remote.cpp +++ b/src/core/Library/Remote.cpp @@ -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(node.Attributes()["id"]); + unsigned int uniqueId = boost::lexical_cast(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(query->queryId); + queryNode.Attributes()["uid"] = boost::lexical_cast(query->uniqueId); if(query->options){ queryNode.Attributes()["options"] = boost::lexical_cast(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(); +} diff --git a/src/core/Library/Remote.h b/src/core/Library/Remote.h index 870a0e216..16da5e699 100644 --- a/src/core/Library/Remote.h +++ b/src/core/Library/Remote.h @@ -70,6 +70,7 @@ class Remote : public Library::Base{ protected: void CancelCurrentQuery( ); + virtual void Exit(); private: // Methods: diff --git a/src/core/Query/Base.cpp b/src/core/Query/Base.cpp index bfec2dff2..2571ce4d0 100644 --- a/src/core/Query/Base.cpp +++ b/src/core/Query/Base.cpp @@ -38,18 +38,22 @@ #include #include +#include +#include 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; +} + diff --git a/src/core/Query/Base.h b/src/core/Query/Base.h index 1de2da70c..dfc7af1ea 100644 --- a/src/core/Query/Base.h +++ b/src/core/Query/Base.h @@ -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 #include -#include -#include ////////////////////////////////////////////////////////////////////////////// @@ -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(); }; diff --git a/src/core/Query/ListBase.cpp b/src/core/Query/ListBase.cpp index ecc077305..7ab635ae2 100644 --- a/src/core/Query/ListBase.cpp +++ b/src/core/Query/ListBase.cpp @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include 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 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; +} + +/// genre,artist,album +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; +} diff --git a/src/core/Query/ListBase.h b/src/core/Query/ListBase.h index 1e421ff01..35e50e392 100644 --- a/src/core/Query/ListBase.h +++ b/src/core/Query/ListBase.h @@ -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; diff --git a/src/core/Query/ListSelection.cpp b/src/core/Query/ListSelection.cpp index 1f3551295..892505fa2 100644 --- a/src/core/Query/ListSelection.cpp +++ b/src/core/Query/ListSelection.cpp @@ -37,6 +37,8 @@ #include "pch.hpp" #include #include +#include +#include #include #include @@ -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 << ""; // Get metakey nodes // Expected tag is likle this: // 2,5,3 while( musik::core::xml::ParserNode selectionNode = node.ChildNode("selection") ){ - std::cout << ""; // 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(*value)); - std::cout << "," << *value; } - std::cout << "" << std::endl; } - std::cout << "" << 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 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){ /// /// 1,3,5,7 /// 6,7,8 /// -/// genre,artist,album +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; } diff --git a/src/core/Query/ListSelection.h b/src/core/Query/ListSelection.h index fc0e7bff5..176468757 100644 --- a/src/core/Query/ListSelection.h +++ b/src/core/Query/ListSelection.h @@ -39,11 +39,7 @@ ////////////////////////////////////////////////////////////// // Forward declarations ////////////////////////////////////////////////////////////// -namespace musik{ namespace core{ - namespace Library{ - class Base; - } -} } + ////////////////////////////////////////////////////////////// #include diff --git a/src/core/Query/SortTracks.cpp b/src/core/Query/SortTracks.cpp index 00af7aeab..3af949e59 100644 --- a/src/core/Query/SortTracks.cpp +++ b/src/core/Query/SortTracks.cpp @@ -38,6 +38,9 @@ #include #include #include +#include +#include +#include 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 +/// +/// 1,3,5,7 +/// +///\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 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(*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(*trackId)); + } + } + + this->SendQueryStandardNodes(queryNode); + + return true; + +} + diff --git a/src/core/Query/SortTracks.h b/src/core/Query/SortTracks.h index 0706bfb0a..c6922374f 100644 --- a/src/core/Query/SortTracks.h +++ b/src/core/Query/SortTracks.h @@ -46,14 +46,7 @@ #include #include -////////////////////////////////////////////////////////////// -// 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 tracksToSort; + typedef std::vector IntVector; + IntVector tracksToSort; std::list 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: }; diff --git a/src/core/Query/TrackMetadata.cpp b/src/core/Query/TrackMetadata.cpp index 4ae2cb1fe..8f9e91a7e 100644 --- a/src/core/Query/TrackMetadata.cpp +++ b/src/core/Query/TrackMetadata.cpp @@ -36,8 +36,10 @@ #include "pch.hpp" +#include #include #include +#include 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 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(*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( (*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( (*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(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; +} + diff --git a/src/core/Query/TrackMetadata.h b/src/core/Query/TrackMetadata.h index 5f1389a58..d5a64b8f0 100644 --- a/src/core/Query/TrackMetadata.h +++ b/src/core/Query/TrackMetadata.h @@ -72,10 +72,11 @@ class TrackMetadata : public Query::Base { TrackMetadataEvent OnTracksEvent; private: - std::set requestedFields; + typedef std::set StringSet; + StringSet requestedFields; std::vector fieldOrder; - std::set metaFields; - std::set 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); + }; ////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 89a33572f..b767c8c24 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -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(fileSize).c_str()); this->SetValue("filetime",boost::lexical_cast(fileTime).c_str()); diff --git a/src/core/server/Connection.cpp b/src/core/server/Connection.cpp index 5b8b3af86..0be267da9 100644 --- a/src/core/server/Connection.cpp +++ b/src/core/server/Connection.cpp @@ -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(queryNode.Attributes()["id"]); + try{ + query->queryId = boost::lexical_cast(queryNode.Attributes()["id"]); + query->uniqueId = boost::lexical_cast(queryNode.Attributes()["uid"]); + }catch(...){} if(query->RecieveQuery(queryNode)){ + unsigned int options(0); + try{ + options = boost::lexical_cast(queryNode.Attributes()["options"]); + }catch(...){} + // TODO: check for AddQuery options in tag - this->AddQuery( *query,boost::lexical_cast(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(sendQuery->queryId); + queryNode.Attributes()["uid"] = boost::lexical_cast(sendQuery->uniqueId); sendQuery->SendResults(queryNode,this); } diff --git a/src/core/tracklist/Standard.cpp b/src/core/tracklist/Standard.cpp index 3bb4ccc3e..ef6e94cef 100644 --- a/src/core/tracklist/Standard.cpp +++ b/src/core/tracklist/Standard.cpp @@ -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);ihintedRows;++i){ - if(this->QueryForTrack(i)){ - ++trackCount; + if(this->QueryForTrack(position)){ + + int trackCount(1); + + for(int i(position+1);ihintedRows;++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){ diff --git a/src/core/xml/Parser.cpp b/src/core/xml/Parser.cpp index 3c4121079..1c855f414 100644 --- a/src/core/xml/Parser.cpp +++ b/src/core/xml/Parser.cpp @@ -38,6 +38,8 @@ #include #include +#include + 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; + } ////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/xml/Writer.cpp b/src/core/xml/Writer.cpp index 6fab0e418..bdb29910b 100644 --- a/src/core/xml/Writer.cpp +++ b/src/core/xml/Writer.cpp @@ -37,6 +37,7 @@ #include #include #include +#include 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(); }