Added message to retrive the library (table songs).

This commit is contained in:
Andreas 2013-08-01 18:13:14 +02:00
parent 662b635d96
commit 3a309e9b25
10 changed files with 229 additions and 89 deletions

View File

@ -21,6 +21,7 @@ enum MsgType {
LOVE = 12;
BAN = 13;
STOP_AFTER = 17;
GET_LIBRARY = 18;
// Messages send by both
DISCONNECT = 2;
@ -49,6 +50,7 @@ enum MsgType {
LYRICS = 49;
SONG_FILE_CHUNK = 50;
DOWNLOAD_QUEUE_EMPTY = 51;
LIBRARY_CHUNK = 52;
}
// Valid Engine states
@ -255,6 +257,13 @@ message ResponseSongFileChunk {
optional int32 size = 8;
}
message ResponseLibraryChunk {
optional int32 chunk_number = 1;
optional int32 chunk_count = 2;
optional bytes data = 3;
optional int32 size = 4;
}
message ResponseSongOffer {
optional bool accepted = 1; // true = client wants to download item
}
@ -290,4 +299,5 @@ message Message {
optional ResponseLyrics response_lyrics = 30;
optional ResponseSongFileChunk response_song_file_chunk = 32;
optional ResponseSongOffer response_song_offer = 33;
optional ResponseLibraryChunk response_library_chunk = 34;
}

View File

@ -328,7 +328,7 @@ Database::Database(Application* app, QObject* parent, const QString& database_na
Utilities::GetConfigPath(Utilities::Path_Root));
attached_databases_["jamendo"] = AttachedDatabase(
directory_ + "/jamendo.db", ":/schema/jamendo.sql");
directory_ + "/jamendo.db", ":/schema/jamendo.sql", false);
QMutexLocker l(&mutex_);
Connect();
@ -410,6 +410,9 @@ QSqlDatabase Database::Connect() {
// We might have to initialise the schema in some attached databases now, if
// they were deleted and don't match up with the main schema version.
foreach (const QString& key, attached_databases_.keys()) {
if (attached_databases_[key].is_temporary_ &&
attached_databases_[key].schema_.isEmpty())
continue;
// Find out if there are any tables in this database
QSqlQuery q(QString("SELECT ROWID FROM %1.sqlite_master"
" WHERE type='table'").arg(key), db);
@ -479,6 +482,27 @@ void Database::RecreateAttachedDb(const QString& database_name) {
}
}
void Database::AttachDatabase(const QString& database_name,
const AttachedDatabase& database) {
attached_databases_[database_name] = database;
}
void Database::DetachDatabase(const QString& database_name) {
QMutexLocker l(&mutex_);
{
QSqlDatabase db(Connect());
QSqlQuery q("DETACH DATABASE :alias", db);
q.bindValue(":alias", database_name);
if (!q.exec()) {
qLog(Warning) << "Failed to detach database" << database_name;
return;
}
}
attached_databases_.remove(database_name);
}
void Database::UpdateDatabaseSchema(int version, QSqlDatabase &db) {
QString filename;
if (version == 0)

View File

@ -46,6 +46,16 @@ class Database : public QObject {
Database(Application* app, QObject* parent = 0,
const QString& database_name = QString());
struct AttachedDatabase {
AttachedDatabase() {}
AttachedDatabase(const QString& filename, const QString& schema, bool is_temporary)
: filename_(filename), schema_(schema), is_temporary_(is_temporary) {}
QString filename_;
QString schema_;
bool is_temporary_;
};
static const int kSchemaVersion;
static const char* kDatabaseFilename;
static const char* kMagicAllSongsTables;
@ -63,6 +73,9 @@ class Database : public QObject {
int startup_schema_version() const { return startup_schema_version_; }
int current_schema_version() const { return kSchemaVersion; }
void AttachDatabase(const QString& database_name, const AttachedDatabase& database);
void DetachDatabase(const QString& database_name);
signals:
void Error(const QString& message);
@ -87,15 +100,6 @@ class Database : public QObject {
void BackupFile(const QString& filename);
bool OpenDatabase(const QString& filename, sqlite3** connection) const;
struct AttachedDatabase {
AttachedDatabase() {}
AttachedDatabase(const QString& filename, const QString& schema)
: filename_(filename), schema_(schema) {}
QString filename_;
QString schema_;
};
Application* app_;
// Alias -> filename

View File

@ -212,6 +212,17 @@ QString MakeTempDir(const QString template_name) {
return path;
}
QString GetTempFileName() {
QString file;
{
QTemporaryFile tempfile;
tempfile.open();
file = tempfile.fileName();
}
return file;
}
void RemoveRecursive(const QString& path) {
QDir dir(path);
foreach (const QString& child, dir.entryList(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Hidden))

View File

@ -49,6 +49,7 @@ namespace Utilities {
quint64 FileSystemFreeSpace(const QString& path);
QString MakeTempDir(const QString template_name = QString());
QString GetTempFileName();
void RemoveRecursive(const QString& path);
bool CopyRecursive(const QString& source, const QString& destination);
bool Copy(QIODevice* source, QIODevice* destination);

View File

@ -99,64 +99,87 @@ void IncomingDataParser::Parse(const pb::remote::Message& msg) {
// Now check what's to do
switch (msg.type()) {
case pb::remote::CONNECT: ClientConnect(msg);
break;
case pb::remote::DISCONNECT: close_connection_ = true;
break;
case pb::remote::REQUEST_PLAYLISTS: SendPlaylists(msg);
break;
case pb::remote::REQUEST_PLAYLIST_SONGS: GetPlaylistSongs(msg);
break;
case pb::remote::SET_VOLUME: emit SetVolume(msg.request_set_volume().volume());
break;
case pb::remote::PLAY: emit Play();
break;
case pb::remote::PLAYPAUSE: emit PlayPause();
break;
case pb::remote::PAUSE: emit Pause();
break;
case pb::remote::STOP: emit Stop();
break;
case pb::remote::STOP_AFTER: emit StopAfterCurrent();
break;
case pb::remote::NEXT: emit Next();
break;
case pb::remote::PREVIOUS: emit Previous();
break;
case pb::remote::CHANGE_SONG: ChangeSong(msg);
break;
case pb::remote::SHUFFLE_PLAYLIST: emit ShuffleCurrent();
break;
case pb::remote::REPEAT: SetRepeatMode(msg.repeat());
break;
case pb::remote::SHUFFLE: SetShuffleMode(msg.shuffle());
break;
case pb::remote::CONNECT:
ClientConnect(msg);
break;
case pb::remote::DISCONNECT:
close_connection_ = true;
break;
case pb::remote::REQUEST_PLAYLISTS:
SendPlaylists(msg);
break;
case pb::remote::REQUEST_PLAYLIST_SONGS:
GetPlaylistSongs(msg);
break;
case pb::remote::SET_VOLUME:
emit SetVolume(msg.request_set_volume().volume());
break;
case pb::remote::PLAY:
emit Play();
break;
case pb::remote::PLAYPAUSE:
emit PlayPause();
break;
case pb::remote::PAUSE:
emit Pause();
break;
case pb::remote::STOP:
emit Stop();
break;
case pb::remote::STOP_AFTER:
emit StopAfterCurrent();
break;
case pb::remote::NEXT:
emit Next();
break;
case pb::remote::PREVIOUS:
emit Previous();
break;
case pb::remote::CHANGE_SONG:
ChangeSong(msg);
break;
case pb::remote::SHUFFLE_PLAYLIST:
emit ShuffleCurrent();
break;
case pb::remote::REPEAT:
SetRepeatMode(msg.repeat());
break;
case pb::remote::SHUFFLE:
SetShuffleMode(msg.shuffle());
break;
case pb::remote::SET_TRACK_POSITION:
emit SeekTo(msg.request_set_track_position().position());
break;
case pb::remote::INSERT_URLS: InsertUrls(msg);
break;
case pb::remote::REMOVE_SONGS:RemoveSongs(msg);
break;
emit SeekTo(msg.request_set_track_position().position());
break;
case pb::remote::INSERT_URLS:
InsertUrls(msg);
break;
case pb::remote::REMOVE_SONGS:
RemoveSongs(msg);
break;
case pb::remote::OPEN_PLAYLIST:
OpenPlaylist(msg);
break;
OpenPlaylist(msg);
break;
case pb::remote::CLOSE_PLAYLIST:
ClosePlaylist(msg);
break;
case pb::remote::LOVE: emit Love();
break;
case pb::remote::BAN: emit Ban();
break;
case pb::remote::GET_LYRICS: emit GetLyrics();
break;
ClosePlaylist(msg);
break;
case pb::remote::LOVE:
emit Love();
break;
case pb::remote::BAN:
emit Ban();
break;
case pb::remote::GET_LYRICS:
emit GetLyrics();
break;
case pb::remote::DOWNLOAD_SONGS:
emit SendSongs(msg.request_download_songs(), client);
break;
emit SendSongs(msg.request_download_songs(), client);
break;
case pb::remote::SONG_OFFER_RESPONSE:
emit ResponseSongOffer(client,
msg.response_song_offer().accepted());
break;
emit ResponseSongOffer(client, msg.response_song_offer().accepted());
break;
case pb::remote::GET_LIBRARY:
emit SendLibrary(client);
break;
default: break;
}
}
@ -180,37 +203,37 @@ void IncomingDataParser::ChangeSong(const pb::remote::Message& msg) {
void IncomingDataParser::SetRepeatMode(const pb::remote::Repeat& repeat) {
switch (repeat.repeat_mode()) {
case pb::remote::Repeat_Off:
emit SetRepeatMode(PlaylistSequence::Repeat_Off);
break;
case pb::remote::Repeat_Track:
emit SetRepeatMode(PlaylistSequence::Repeat_Track);
break;
case pb::remote::Repeat_Album:
emit SetRepeatMode(PlaylistSequence::Repeat_Album);
break;
case pb::remote::Repeat_Playlist:
emit SetRepeatMode(PlaylistSequence::Repeat_Playlist);
break;
default: break;
case pb::remote::Repeat_Off:
emit SetRepeatMode(PlaylistSequence::Repeat_Off);
break;
case pb::remote::Repeat_Track:
emit SetRepeatMode(PlaylistSequence::Repeat_Track);
break;
case pb::remote::Repeat_Album:
emit SetRepeatMode(PlaylistSequence::Repeat_Album);
break;
case pb::remote::Repeat_Playlist:
emit SetRepeatMode(PlaylistSequence::Repeat_Playlist);
break;
default: break;
}
}
void IncomingDataParser::SetShuffleMode(const pb::remote::Shuffle& shuffle) {
switch (shuffle.shuffle_mode()) {
case pb::remote::Shuffle_Off:
emit SetShuffleMode(PlaylistSequence::Shuffle_Off);
break;
case pb::remote::Shuffle_All:
emit SetShuffleMode(PlaylistSequence::Shuffle_All);
break;
case pb::remote::Shuffle_InsideAlbum:
emit SetShuffleMode(PlaylistSequence::Shuffle_InsideAlbum);
break;
case pb::remote::Shuffle_Albums:
emit SetShuffleMode(PlaylistSequence::Shuffle_Albums);
break;
default: break;
case pb::remote::Shuffle_Off:
emit SetShuffleMode(PlaylistSequence::Shuffle_Off);
break;
case pb::remote::Shuffle_All:
emit SetShuffleMode(PlaylistSequence::Shuffle_All);
break;
case pb::remote::Shuffle_InsideAlbum:
emit SetShuffleMode(PlaylistSequence::Shuffle_InsideAlbum);
break;
case pb::remote::Shuffle_Albums:
emit SetShuffleMode(PlaylistSequence::Shuffle_Albums);
break;
default: break;
}
}

View File

@ -47,6 +47,7 @@ signals:
void SeekTo(int seconds);
void SendSongs(const pb::remote::RequestDownloadSongs& request, RemoteClient* client);
void ResponseSongOffer(RemoteClient* client, bool accepted);
void SendLibrary(RemoteClient* client);
private:
Application* app_;

View File

@ -170,6 +170,11 @@ void NetworkRemote::AcceptConnection() {
SIGNAL(ResponseSongOffer(RemoteClient*, bool)),
outgoing_data_creator_.get(),
SLOT(ResponseSongOffer(RemoteClient*, bool)));
connect(incoming_data_parser_.get(),
SIGNAL(SendLibrary(RemoteClient*)),
outgoing_data_creator_.get(),
SLOT(SendLibrary(RemoteClient*)));
}
QTcpServer* server = qobject_cast<QTcpServer*>(sender());

View File

@ -22,8 +22,13 @@
#include "networkremote.h"
#include "core/logging.h"
#include "core/timeconstants.h"
#include "core/utilities.h"
#include "library/librarybackend.h"
#include <QSqlDatabase>
#include <QSqlQuery>
#include "core/database.h"
const quint32 OutgoingDataCreator::kFileChunkSize = 100000; // in Bytes
OutgoingDataCreator::OutgoingDataCreator(Application* app)
@ -707,3 +712,58 @@ void OutgoingDataCreator::SendPlaylist(RemoteClient *client, int playlist_id) {
}
}
}
void OutgoingDataCreator::SendLibrary(RemoteClient *client) {
// Get a temporary file name
QString temp_file_name = Utilities::GetTempFileName();
// Attach this file to the database
Database::AttachedDatabase adb(temp_file_name, "", true);
app_->database()->AttachDatabase("songs_export", adb);
QSqlDatabase db(app_->database()->Connect());
// Copy the content of the song table to this temporary database
QSqlQuery q(QString("create table songs_export.songs as SELECT * FROM songs;"), db);
q.exec();
if (app_->database()->CheckErrors(q)) return;
// Detach the database
app_->database()->DetachDatabase("songs_export");
// Open the file
QFile file(temp_file_name);
file.open(QIODevice::ReadOnly);
QByteArray data;
pb::remote::Message msg;
pb::remote::ResponseLibraryChunk* chunk = msg.mutable_response_library_chunk();
msg.set_type(pb::remote::LIBRARY_CHUNK);
// Calculate the number of chunks
int chunk_count = qRound((file.size() / kFileChunkSize) + 0.5);
int chunk_number = 1;
while (!file.atEnd()) {
// Read file chunk
data = file.read(kFileChunkSize);
// Set chunk data
chunk->set_chunk_count(chunk_count);
chunk->set_chunk_number(chunk_number);
chunk->set_size(file.size());
chunk->set_data(data.data(), data.size());
// Send data directly to the client
client->SendData(&msg);
// Clear working data
chunk->Clear();
data.clear();
chunk_number++;
}
// Remove temporary file
file.remove();
}

View File

@ -72,6 +72,7 @@ public slots:
void SendLyrics(int id, const SongInfoFetcher::Result& result);
void SendSongs(const pb::remote::RequestDownloadSongs& request, RemoteClient* client);
void ResponseSongOffer(RemoteClient* client, bool accepted);
void SendLibrary(RemoteClient* client);
private:
Application* app_;