mirror of
https://github.com/clangen/musikcube.git
synced 2025-01-01 17:58:29 +00:00
Continued on the Library::Remote. The Query::ListBase and Query::ListSelection is starting to work.
This commit is contained in:
parent
41769da567
commit
252f06e1b4
@ -502,7 +502,12 @@ bool Indexer::Startup(utfstring setLibraryPath){
|
||||
}
|
||||
|
||||
// start the thread
|
||||
this->oThread = new boost::thread(boost::bind(&Indexer::ThreadLoop,this));
|
||||
try{
|
||||
this->oThread = new boost::thread(boost::bind(&Indexer::ThreadLoop,this));
|
||||
}
|
||||
catch(...){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,7 @@ bool Library::Base::AddQuery( const Query::Base &query,unsigned int options ){
|
||||
if( options & Query::Options::CancelQueue ){
|
||||
oCheckQuery = this->incomingQueries.erase(oCheckQuery);
|
||||
}else if( options & Query::Options::CancelSimilar ){
|
||||
if( (*oCheckQuery)->iQueryId == queryCopy->iQueryId ){
|
||||
if( (*oCheckQuery)->queryId == queryCopy->queryId ){
|
||||
oCheckQuery = this->incomingQueries.erase(oCheckQuery);
|
||||
}else{
|
||||
++oCheckQuery;
|
||||
@ -222,7 +222,7 @@ bool Library::Base::AddQuery( const Query::Base &query,unsigned int options ){
|
||||
if( options & Query::Options::CancelQueue ){
|
||||
(*oCheckQuery)->status |= Query::Base::Status::Canceled;
|
||||
}else if( options & Query::Options::CancelSimilar ){
|
||||
if( (*oCheckQuery)->iQueryId == queryCopy->iQueryId ){
|
||||
if( (*oCheckQuery)->queryId == queryCopy->queryId ){
|
||||
(*oCheckQuery)->status |= Query::Base::Status::Canceled;
|
||||
}
|
||||
}
|
||||
@ -236,7 +236,7 @@ bool Library::Base::AddQuery( const Query::Base &query,unsigned int options ){
|
||||
if( options & Query::Options::CancelQueue ){
|
||||
bCancelCurrentQuery = true;
|
||||
}else if( options & Query::Options::CancelSimilar ){
|
||||
if( this->runningQuery->iQueryId == queryCopy->iQueryId ){
|
||||
if( this->runningQuery->queryId == queryCopy->queryId ){
|
||||
bCancelCurrentQuery = true;
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,12 @@ utfstring Library::LocalDB::GetInfo(){
|
||||
bool Library::LocalDB::Startup(){
|
||||
|
||||
// Start the library thread
|
||||
this->threads.create_thread(boost::bind(&Library::LocalDB::ThreadLoop,this));
|
||||
try{
|
||||
this->threads.create_thread(boost::bind(&Library::LocalDB::ThreadLoop,this));
|
||||
}
|
||||
catch(...){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -112,49 +112,79 @@ bool Library::Remote::Startup(){
|
||||
//////////////////////////////////////////
|
||||
void Library::Remote::ReadThread(){
|
||||
|
||||
this->address = "localhost";
|
||||
this->port = "10543";
|
||||
|
||||
boost::asio::ip::tcp::resolver resolver(this->ioService);
|
||||
boost::asio::ip::tcp::resolver::query resolverQuery(this->address,this->port);
|
||||
|
||||
boost::asio::ip::tcp::resolver::iterator endpointIterator = resolver.resolve(resolverQuery);
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
try{
|
||||
boost::asio::ip::tcp::resolver::iterator endpointIterator = resolver.resolve(resolverQuery);
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
|
||||
boost::system::error_code error = boost::asio::error::host_not_found;
|
||||
while (error && endpointIterator!=end){
|
||||
this->socket.close();
|
||||
this->socket.connect(*endpointIterator++, error);
|
||||
boost::system::error_code error = boost::asio::error::host_not_found;
|
||||
while (error && endpointIterator!=end){
|
||||
this->socket.close();
|
||||
this->socket.connect(*endpointIterator++, error);
|
||||
}
|
||||
if (error){
|
||||
this->Exit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (error){
|
||||
catch(boost::system::system_error &error){
|
||||
this->Exit();
|
||||
return;
|
||||
}
|
||||
catch(...){
|
||||
this->Exit();
|
||||
return;
|
||||
}
|
||||
|
||||
// Successfully connected to server
|
||||
// Start the WriteThread
|
||||
this->threads.create_thread(boost::bind(&Library::Remote::WriteThread,this));
|
||||
try{
|
||||
this->threads.create_thread(boost::bind(&Library::Remote::WriteThread,this));
|
||||
}
|
||||
catch(...){
|
||||
this->Exit();
|
||||
return;
|
||||
}
|
||||
|
||||
// Lets start recieving queries
|
||||
xml::Parser parser(&this->socket);
|
||||
if( xml::ParserNode rootNode=parser.ChildNode("musik")){
|
||||
while(xml::ParserNode node=rootNode.ChildNode()){
|
||||
if(node.Name()=="queryresults"){
|
||||
try{
|
||||
// Lets start recieving queries
|
||||
xml::Parser parser(&this->socket);
|
||||
if( xml::ParserNode rootNode=parser.ChildNode("musik")){
|
||||
while(xml::ParserNode node=rootNode.ChildNode()){
|
||||
if(node.Name()=="queryresults"){
|
||||
|
||||
unsigned int queryId = boost::lexical_cast<unsigned int>(node.Attributes()["id"]);
|
||||
Query::Ptr currentQuery;
|
||||
// This is a query node
|
||||
// Find the query in the outgoingQueries list
|
||||
{
|
||||
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)->iQueryId==queryId ){
|
||||
currentQuery = *query;
|
||||
unsigned int queryId = boost::lexical_cast<unsigned int>(node.Attributes()["id"]);
|
||||
Query::Ptr currentQuery;
|
||||
// This is a query node
|
||||
// Find the query in the outgoingQueries list
|
||||
{
|
||||
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 ){
|
||||
currentQuery = *query;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(currentQuery){
|
||||
if(currentQuery->RecieveResults(node,this)){
|
||||
currentQuery->status |= Query::Base::Status::Ended;
|
||||
}else{
|
||||
currentQuery->status |= Query::Base::Status::Canceled;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(...){
|
||||
|
||||
}
|
||||
this->Exit();
|
||||
}
|
||||
|
||||
@ -191,7 +221,11 @@ void Library::Remote::WriteThread(){
|
||||
// Lets send the query
|
||||
xml::WriterNode queryNode(rootNode,"query");
|
||||
queryNode.Attributes()["type"] = query->Name();
|
||||
queryNode.Attributes()["id"] = boost::lexical_cast<std::string>(query->iQueryId);
|
||||
queryNode.Attributes()["id"] = boost::lexical_cast<std::string>(query->queryId);
|
||||
|
||||
if(query->options){
|
||||
queryNode.Attributes()["options"] = boost::lexical_cast<std::string>(query->options);
|
||||
}
|
||||
|
||||
query->SendQuery(queryNode);
|
||||
|
||||
|
@ -41,12 +41,15 @@
|
||||
|
||||
using namespace musik::core;
|
||||
|
||||
Query::Base::Base(void) : status(0){
|
||||
Query::Base::Base(void)
|
||||
:status(0)
|
||||
,options(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 iUniqueQueryId(0);
|
||||
iUniqueQueryId++;
|
||||
iQueryId = iUniqueQueryId;
|
||||
static unsigned int uniqueQueryId(0);
|
||||
uniqueQueryId++;
|
||||
this->queryId = uniqueQueryId;
|
||||
}
|
||||
|
||||
Query::Base::~Base(void){
|
||||
@ -90,7 +93,7 @@ bool Query::Base::SendQuery(musik::core::xml::WriterNode &queryNode){
|
||||
///\returns
|
||||
///true when successfully recieved
|
||||
//////////////////////////////////////////
|
||||
bool Query::Base::RecieveResults(musik::core::xml::ParserNode &queryNode){
|
||||
bool Query::Base::RecieveResults(musik::core::xml::ParserNode &queryNode,Library::Base *library){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ class Base : public sigslot::has_slots<> {
|
||||
///
|
||||
///Used for comparing queries and find similar queries.
|
||||
//////////////////////////////////////////
|
||||
unsigned int iQueryId;
|
||||
unsigned int queryId;
|
||||
|
||||
//////////////////////////////////////////
|
||||
///\brief
|
||||
@ -203,7 +203,7 @@ class Base : public sigslot::has_slots<> {
|
||||
|
||||
virtual bool RecieveQuery(musik::core::xml::ParserNode &queryNode);
|
||||
virtual bool SendQuery(musik::core::xml::WriterNode &queryNode);
|
||||
virtual bool RecieveResults(musik::core::xml::ParserNode &queryNode);
|
||||
virtual bool RecieveResults(musik::core::xml::ParserNode &queryNode,Library::Base *library);
|
||||
virtual bool SendResults(musik::core::xml::WriterNode &queryNode,Library::Base *library);
|
||||
};
|
||||
|
||||
|
@ -269,6 +269,52 @@ bool Query::ListBase::SendResults(musik::core::xml::WriterNode &queryNode,Librar
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Query::ListBase::RecieveResults(musik::core::xml::ParserNode &queryNode,Library::Base *library){
|
||||
while( musik::core::xml::ParserNode node = queryNode.ChildNode() ){
|
||||
if( node.Name()=="metadata"){
|
||||
|
||||
std::string metakey(node.Attributes()["key"]);
|
||||
|
||||
MetadataValueVector tempMetadataValues;
|
||||
tempMetadataValues.reserve(10);
|
||||
int row(0);
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(library->oResultMutex);
|
||||
this->metadataResults[metakey];
|
||||
}
|
||||
|
||||
while( musik::core::xml::ParserNode metaDataNode = node.ChildNode("md") ){
|
||||
metaDataNode.WaitForContent();
|
||||
|
||||
tempMetadataValues.push_back(
|
||||
MetadataValuePtr(
|
||||
new MetadataValue(
|
||||
boost::lexical_cast<unsigned int>( metaDataNode.Attributes()["id"] ),
|
||||
ConvertUTF16(metaDataNode.Content()).c_str()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if( (++row)%10==0 ){
|
||||
boost::mutex::scoped_lock lock(library->oResultMutex);
|
||||
this->metadataResults[metakey].insert(this->metadataResults[metakey].end(),tempMetadataValues.begin(),tempMetadataValues.end());
|
||||
tempMetadataValues.clear();
|
||||
tempMetadataValues.reserve(10);
|
||||
}
|
||||
}
|
||||
if(!tempMetadataValues.empty()){
|
||||
boost::mutex::scoped_lock lock(library->oResultMutex);
|
||||
this->metadataResults[metakey].insert(this->metadataResults[metakey].end(),tempMetadataValues.begin(),tempMetadataValues.end());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Query::ListBase::DummySlot(MetadataValueVector*,bool){
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,7 @@ namespace musik{ namespace core{
|
||||
UINT64 trackInfoSize;
|
||||
|
||||
virtual bool SendResults(musik::core::xml::WriterNode &queryNode,Library::Base *library);
|
||||
virtual bool RecieveResults(musik::core::xml::ParserNode &queryNode,Library::Base *library);
|
||||
|
||||
public:
|
||||
MetadataSignal& OnMetadataEvent(const char* metatag);
|
||||
|
@ -620,4 +620,43 @@ 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>
|
||||
xml::WriterNode selectionsNode(queryNode,"selections");
|
||||
|
||||
// Start with the selection nodes
|
||||
for(SelectedMetadata::iterator selection=this->selectedMetadata.begin();selection!=this->selectedMetadata.end();++selection){
|
||||
xml::WriterNode selectionNode(selectionsNode,"selection");
|
||||
selectionNode.Attributes()["key"] = selection->first;
|
||||
|
||||
std::string selectionIDs;
|
||||
|
||||
for(SelectedMetadataIDs::iterator id=selection->second.begin();id!=selection->second.end();++id){
|
||||
if(!selectionIDs.empty()){
|
||||
selectionIDs.append(",");
|
||||
}
|
||||
selectionIDs.append(boost::lexical_cast<std::string>(*id));
|
||||
}
|
||||
|
||||
selectionNode.Content() = selectionIDs;
|
||||
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Forward declarations
|
||||
//////////////////////////////////////////////////////////////
|
||||
namespace musik{ namespace core{
|
||||
namespace Library{
|
||||
class Base;
|
||||
}
|
||||
} }
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <set>
|
||||
@ -47,79 +57,73 @@
|
||||
#include <core/Query/ListBase.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// Forward declarations
|
||||
//////////////////////////////////////////////////////////////
|
||||
namespace musik{ namespace core{
|
||||
namespace Library{
|
||||
class Base;
|
||||
}
|
||||
} }
|
||||
|
||||
namespace musik{ namespace core{ namespace Query{
|
||||
|
||||
//////////////////////////////////////////
|
||||
///\brief
|
||||
///ListSelection is the query used when listing tracks and metalists from a metalist (genres, artists, etc) selection.
|
||||
///
|
||||
///Write detailed description for ListSelection here.
|
||||
///
|
||||
///\see
|
||||
///Query::ListBase
|
||||
//////////////////////////////////////////
|
||||
class ListSelection : public Query::ListBase{
|
||||
public:
|
||||
ListSelection(void);
|
||||
~ListSelection(void);
|
||||
|
||||
void SelectMetadata(const char* metakey,DBINT metadataId);
|
||||
void RemoveMetadata(const char* metakey,DBINT metadataId);
|
||||
void ClearMetadata(const char* metakey=NULL);
|
||||
|
||||
void SelectionOrderSensitive(bool sensitive);
|
||||
protected:
|
||||
friend class Library::Base;
|
||||
friend class Library::LocalDB;
|
||||
friend class server::Connection;
|
||||
|
||||
virtual std::string Name();
|
||||
virtual bool ParseQuery(Library::Base *library,db::Connection &db);
|
||||
|
||||
Ptr copy() const;
|
||||
|
||||
virtual bool RecieveQuery(musik::core::xml::ParserNode &queryNode);
|
||||
virtual bool SendQuery(musik::core::xml::WriterNode &queryNode);
|
||||
|
||||
private:
|
||||
typedef std::set<DBINT> SelectedMetadataIDs;
|
||||
typedef std::map<std::string,SelectedMetadataIDs> SelectedMetadata;
|
||||
|
||||
namespace musik{ namespace core{
|
||||
namespace Query{
|
||||
|
||||
//////////////////////////////////////////
|
||||
///\brief
|
||||
///ListSelection is the query used when listing tracks and metalists from a metalist (genres, artists, etc) selection.
|
||||
///
|
||||
///Write detailed description for ListSelection here.
|
||||
///
|
||||
///\see
|
||||
///Query::ListBase
|
||||
///A map of selected metakeys
|
||||
//////////////////////////////////////////
|
||||
class ListSelection : public Query::ListBase{
|
||||
public:
|
||||
ListSelection(void);
|
||||
~ListSelection(void);
|
||||
SelectedMetadata selectedMetadata;
|
||||
|
||||
void SelectMetadata(const char* metakey,DBINT metadataId);
|
||||
void RemoveMetadata(const char* metakey,DBINT metadataId);
|
||||
void ClearMetadata(const char* metakey=NULL);
|
||||
//////////////////////////////////////////
|
||||
///\brief
|
||||
///Setting if selection is sensitive to order of selection
|
||||
//////////////////////////////////////////
|
||||
bool selectionOrderSensitive;
|
||||
|
||||
void SelectionOrderSensitive(bool sensitive);
|
||||
protected:
|
||||
friend class Library::Base;
|
||||
friend class Library::LocalDB;
|
||||
friend class server::Connection;
|
||||
|
||||
virtual std::string Name();
|
||||
virtual bool ParseQuery(Library::Base *library,db::Connection &db);
|
||||
|
||||
Ptr copy() const;
|
||||
|
||||
virtual bool RecieveQuery(musik::core::xml::ParserNode &queryNode);
|
||||
|
||||
private:
|
||||
typedef std::map<std::string,std::set<DBINT>> SelectedMetadata;
|
||||
//////////////////////////////////////////
|
||||
///\brief
|
||||
///A list of the metakeys selection order
|
||||
//////////////////////////////////////////
|
||||
std::vector<std::string> metakeySelectionOrder;
|
||||
|
||||
|
||||
//////////////////////////////////////////
|
||||
///\brief
|
||||
///A map of selected metakeys
|
||||
//////////////////////////////////////////
|
||||
SelectedMetadata selectedMetadata;
|
||||
inline void SQLPrependWhereOrAnd(std::string &sql);
|
||||
void SQLSelectQuery(const char *metakey,const char *sqlStart,const char *sqlEnd,std::set<std::string> &metakeysSelected,std::string &sqlSelectTrackWhere,Library::Base *library);
|
||||
void QueryForMetadata(const char *metakey,const char *sql,std::set<std::string> &metakeysQueried,Library::Base *library,db::Connection &db);
|
||||
|
||||
//////////////////////////////////////////
|
||||
///\brief
|
||||
///Setting if selection is sensitive to order of selection
|
||||
//////////////////////////////////////////
|
||||
bool selectionOrderSensitive;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////
|
||||
///\brief
|
||||
///A list of the metakeys selection order
|
||||
//////////////////////////////////////////
|
||||
std::vector<std::string> metakeySelectionOrder;
|
||||
|
||||
|
||||
inline void SQLPrependWhereOrAnd(std::string &sql);
|
||||
void SQLSelectQuery(const char *metakey,const char *sqlStart,const char *sqlEnd,std::set<std::string> &metakeysSelected,std::string &sqlSelectTrackWhere,Library::Base *library);
|
||||
void QueryForMetadata(const char *metakey,const char *sql,std::set<std::string> &metakeysQueried,Library::Base *library,db::Connection &db);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
} }
|
||||
//////////////////////////////////////////////////////////////
|
||||
} } }
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
@ -105,11 +105,12 @@ 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"]);
|
||||
|
||||
if(query->RecieveQuery(queryNode)){
|
||||
|
||||
// TODO: check for AddQuery options in tag
|
||||
this->AddQuery( *query );
|
||||
this->AddQuery( *query,boost::lexical_cast<unsigned int>(queryNode.Attributes()["options"]) );
|
||||
|
||||
}
|
||||
|
||||
@ -211,6 +212,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);
|
||||
|
||||
sendQuery->SendResults(queryNode,this);
|
||||
}
|
||||
|
@ -171,10 +171,15 @@ void Writer::Send(){
|
||||
}
|
||||
}
|
||||
|
||||
// Time to send the buffer
|
||||
if(!sendBuffer.empty()){
|
||||
boost::asio::write(*(this->socket),boost::asio::buffer(sendBuffer));
|
||||
sendBuffer.clear();
|
||||
try{
|
||||
// Time to send the buffer
|
||||
if(!sendBuffer.empty()){
|
||||
boost::asio::write(*(this->socket),boost::asio::buffer(sendBuffer));
|
||||
sendBuffer.clear();
|
||||
}
|
||||
}
|
||||
catch(...){
|
||||
this->Exit();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user