Move everything around in the source tree - static libraries and external binaries now go in "ext/". Add a generic worker pool.
This commit is contained in:
parent
85f2f087cb
commit
9041117867
|
@ -366,8 +366,9 @@ add_subdirectory(3rdparty/universalchardet)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
add_subdirectory(dist)
|
add_subdirectory(dist)
|
||||||
add_subdirectory(tools/ultimate_lyrics_parser)
|
add_subdirectory(tools/ultimate_lyrics_parser)
|
||||||
add_subdirectory(tagreader/common)
|
add_subdirectory(ext/libclementine-common)
|
||||||
add_subdirectory(tagreader/tagreader)
|
add_subdirectory(ext/libclementine-tagreader)
|
||||||
|
add_subdirectory(ext/clementine-tagreader)
|
||||||
|
|
||||||
option(WITH_DEBIAN OFF)
|
option(WITH_DEBIAN OFF)
|
||||||
if(WITH_DEBIAN)
|
if(WITH_DEBIAN)
|
||||||
|
@ -383,11 +384,11 @@ if(HAVE_BREAKPAD)
|
||||||
endif(HAVE_BREAKPAD)
|
endif(HAVE_BREAKPAD)
|
||||||
|
|
||||||
if(HAVE_SPOTIFY)
|
if(HAVE_SPOTIFY)
|
||||||
add_subdirectory(spotifyblob/common)
|
add_subdirectory(ext/libclementine-spotifyblob)
|
||||||
endif(HAVE_SPOTIFY)
|
endif(HAVE_SPOTIFY)
|
||||||
|
|
||||||
if(HAVE_SPOTIFY_BLOB)
|
if(HAVE_SPOTIFY_BLOB)
|
||||||
add_subdirectory(spotifyblob/blob)
|
add_subdirectory(ext/clementine-spotifyblob)
|
||||||
endif(HAVE_SPOTIFY_BLOB)
|
endif(HAVE_SPOTIFY_BLOB)
|
||||||
|
|
||||||
# This goes after everything else because KDE fucks everything else up with its
|
# This goes after everything else because KDE fucks everything else up with its
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
include_directories(${SPOTIFY_INCLUDE_DIRS})
|
include_directories(${SPOTIFY_INCLUDE_DIRS})
|
||||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../common)
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../common)
|
include_directories(${CMAKE_BINARY_DIR}/ext/libclementine-spotifyblob)
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/ext/libclementine-spotifyblob)
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/ext/libclementine-common)
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/src)
|
include_directories(${CMAKE_SOURCE_DIR}/src)
|
||||||
|
|
||||||
link_directories(${SPOTIFY_LIBRARY_DIRS})
|
link_directories(${SPOTIFY_LIBRARY_DIRS})
|
||||||
|
@ -14,8 +16,6 @@ set(SOURCES
|
||||||
mediapipeline.cpp
|
mediapipeline.cpp
|
||||||
spotifyclient.cpp
|
spotifyclient.cpp
|
||||||
spotify_utilities.cpp
|
spotify_utilities.cpp
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/src/core/logging.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
|
@ -45,6 +45,7 @@ target_link_libraries(clementine-spotifyblob
|
||||||
${GSTREAMER_BASE_LIBRARIES}
|
${GSTREAMER_BASE_LIBRARIES}
|
||||||
${GSTREAMER_APP_LIBRARIES}
|
${GSTREAMER_APP_LIBRARIES}
|
||||||
clementine-spotifyblob-messages
|
clementine-spotifyblob-messages
|
||||||
|
libclementine-common
|
||||||
)
|
)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
|
@ -1,11 +1,10 @@
|
||||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||||
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../common)
|
include_directories(${CMAKE_SOURCE_DIR}/ext/libclementine-common)
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../common)
|
include_directories(${CMAKE_BINARY_DIR}/ext/libclementine-tagreader)
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/src)
|
include_directories(${CMAKE_SOURCE_DIR}/src)
|
||||||
|
|
||||||
link_directories(${SPOTIFY_LIBRARY_DIRS})
|
|
||||||
|
|
||||||
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
|
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
|
@ -28,7 +27,8 @@ target_link_libraries(clementine-tagreader
|
||||||
${TAGLIB_LIBRARIES}
|
${TAGLIB_LIBRARIES}
|
||||||
${QT_QTCORE_LIBRARY}
|
${QT_QTCORE_LIBRARY}
|
||||||
${QT_QTNETWORK_LIBRARY}
|
${QT_QTNETWORK_LIBRARY}
|
||||||
clementine-tagreader-common
|
libclementine-common
|
||||||
|
libclementine-tagreader
|
||||||
)
|
)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
|
@ -18,8 +18,8 @@
|
||||||
#ifndef TAGREADERWORKER_H
|
#ifndef TAGREADERWORKER_H
|
||||||
#define TAGREADERWORKER_H
|
#define TAGREADERWORKER_H
|
||||||
|
|
||||||
#include "messagehandler.h"
|
|
||||||
#include "tagreadermessages.pb.h"
|
#include "tagreadermessages.pb.h"
|
||||||
|
#include "core/messagehandler.h"
|
||||||
|
|
||||||
#include <taglib/xiphcomment.h>
|
#include <taglib/xiphcomment.h>
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||||
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/src)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
core/closure.cpp
|
||||||
|
core/encoding.cpp
|
||||||
|
core/logging.cpp
|
||||||
|
core/messagehandler.cpp
|
||||||
|
core/workerpool.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HEADERS
|
||||||
|
core/closure.h
|
||||||
|
core/messagehandler.h
|
||||||
|
core/workerpool.h
|
||||||
|
)
|
||||||
|
|
||||||
|
qt4_wrap_cpp(MOC ${HEADERS})
|
||||||
|
|
||||||
|
add_library(libclementine-common STATIC
|
||||||
|
${SOURCES}
|
||||||
|
${MOC}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Use protobuf-lite if it's available
|
||||||
|
if(PROTOBUF_LITE_LIBRARY AND USE_PROTOBUF_LITE)
|
||||||
|
set(protobuf ${PROTOBUF_LITE_LIBRARY})
|
||||||
|
else(PROTOBUF_LITE_LIBRARY AND USE_PROTOBUF_LITE)
|
||||||
|
set(protobuf ${PROTOBUF_LIBRARY})
|
||||||
|
endif(PROTOBUF_LITE_LIBRARY AND USE_PROTOBUF_LITE)
|
||||||
|
|
||||||
|
target_link_libraries(libclementine-common
|
||||||
|
${protobuf}
|
||||||
|
${CMAKE_THREAD_LIBS_INIT}
|
||||||
|
chardet
|
||||||
|
)
|
||||||
|
|
|
@ -67,6 +67,8 @@ protected:
|
||||||
template <typename MessageType>
|
template <typename MessageType>
|
||||||
class MessageReply : public _MessageReplyBase {
|
class MessageReply : public _MessageReplyBase {
|
||||||
public:
|
public:
|
||||||
|
MessageReply(int id, QObject* parent);
|
||||||
|
|
||||||
const MessageType& message() const { return message_; }
|
const MessageType& message() const { return message_; }
|
||||||
|
|
||||||
void SetReply(const MessageType& message);
|
void SetReply(const MessageType& message);
|
||||||
|
@ -88,7 +90,7 @@ public:
|
||||||
protected slots:
|
protected slots:
|
||||||
void WriteMessage(const QByteArray& data);
|
void WriteMessage(const QByteArray& data);
|
||||||
void DeviceReadyRead();
|
void DeviceReadyRead();
|
||||||
virtual bool SocketClosed() {}
|
virtual void SocketClosed() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool MessageArrived(const QByteArray& data) = 0;
|
virtual bool MessageArrived(const QByteArray& data) = 0;
|
||||||
|
@ -145,6 +147,7 @@ protected:
|
||||||
|
|
||||||
// _MessageHandlerBase
|
// _MessageHandlerBase
|
||||||
bool MessageArrived(const QByteArray& data);
|
bool MessageArrived(const QByteArray& data);
|
||||||
|
void SocketClosed();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMutex mutex_;
|
QMutex mutex_;
|
||||||
|
@ -245,6 +248,12 @@ void AbstractMessageHandler<MessageType>::SocketClosed() {
|
||||||
pending_replies_.clear();
|
pending_replies_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename MessageType>
|
||||||
|
MessageReply<MessageType>::MessageReply(int id, QObject* parent)
|
||||||
|
: _MessageReplyBase(id, parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
template<typename MessageType>
|
template<typename MessageType>
|
||||||
void MessageReply<MessageType>::SetReply(const MessageType& message) {
|
void MessageReply<MessageType>::SetReply(const MessageType& message) {
|
||||||
Q_ASSERT(!finished_);
|
Q_ASSERT(!finished_);
|
|
@ -0,0 +1,25 @@
|
||||||
|
/* This file is part of Clementine.
|
||||||
|
Copyright 2011, David Sansome <me@davidsansome.com>
|
||||||
|
|
||||||
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Clementine is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "workerpool.h"
|
||||||
|
|
||||||
|
_WorkerPoolBase::_WorkerPoolBase(QObject* parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,276 @@
|
||||||
|
/* This file is part of Clementine.
|
||||||
|
Copyright 2011, David Sansome <me@davidsansome.com>
|
||||||
|
|
||||||
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Clementine is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WORKERPOOL_H
|
||||||
|
#define WORKERPOOL_H
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QLocalServer>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
#include "core/closure.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Base class containing signals and slots - required because moc doesn't do
|
||||||
|
// templated objects.
|
||||||
|
class _WorkerPoolBase : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
_WorkerPoolBase(QObject* parent = 0);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
// Emitted when a worker failed to start. This usually happens when the
|
||||||
|
// worker wasn't found, or couldn't be executed.
|
||||||
|
void WorkerFailedToStart();
|
||||||
|
|
||||||
|
// A worker connected and a handler was created for it. The next call to
|
||||||
|
// NextHandler() won't return NULL.
|
||||||
|
void WorkerConnected();
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
virtual void NewConnection() {}
|
||||||
|
virtual void ProcessError(QProcess::ProcessError) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Manages a pool of one or more external processes. A local socket server is
|
||||||
|
// started for each process, and the address is passed to the process as
|
||||||
|
// argv[1]. The process is expected to connect back to the socket server, and
|
||||||
|
// when it does a HandlerType is created for it.
|
||||||
|
template <typename HandlerType>
|
||||||
|
class WorkerPool : public _WorkerPoolBase {
|
||||||
|
public:
|
||||||
|
WorkerPool(QObject* parent = 0);
|
||||||
|
|
||||||
|
// Sets the name of the worker executable. This is looked for first in the
|
||||||
|
// current directory, and then in $PATH. You must call this before calling
|
||||||
|
// Start().
|
||||||
|
void SetExecutableName(const QString& executable_name);
|
||||||
|
|
||||||
|
// Sets the number of worker process to use. Defaults to
|
||||||
|
// 1 <= (processors / 2) <= 2.
|
||||||
|
void SetWorkerCount(int count);
|
||||||
|
|
||||||
|
// Sets the prefix to use for the local server (on unix this is a named pipe
|
||||||
|
// in /tmp). Defaults to QApplication::applicationName(). A random number
|
||||||
|
// is appended to this name when creating each server.
|
||||||
|
void SetLocalServerName(const QString& local_server_name);
|
||||||
|
|
||||||
|
// Starts all workers.
|
||||||
|
void Start();
|
||||||
|
|
||||||
|
// Returns a handler in a round-robin fashion. May return NULL if no handlers
|
||||||
|
// are running yet, in which case you must queue the request yourself and
|
||||||
|
// re-send it when the WorkerConnected() signal is emitted.
|
||||||
|
HandlerType* NextHandler();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void NewConnection();
|
||||||
|
void ProcessError(QProcess::ProcessError error);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Worker {
|
||||||
|
Worker() : local_server_(NULL), process_(NULL), handler_(NULL) {}
|
||||||
|
|
||||||
|
QLocalServer* local_server_;
|
||||||
|
QProcess* process_;
|
||||||
|
HandlerType* handler_;
|
||||||
|
};
|
||||||
|
|
||||||
|
void StartOneWorker(Worker* worker);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Worker* FindWorker(T Worker::*member, T value) {
|
||||||
|
foreach (Worker& worker, workers_) {
|
||||||
|
if (worker.*member == value) {
|
||||||
|
return &worker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteQObjectPointerLater(QObject** p) {
|
||||||
|
if (*p) {
|
||||||
|
(*p)->deleteLater();
|
||||||
|
*p = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString local_server_name_;
|
||||||
|
QString executable_name_;
|
||||||
|
QString executable_path_;
|
||||||
|
|
||||||
|
int worker_count_;
|
||||||
|
int next_worker_;
|
||||||
|
QList<Worker> workers_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename HandlerType>
|
||||||
|
WorkerPool<HandlerType>::WorkerPool(QObject* parent)
|
||||||
|
: _WorkerPoolBase(parent),
|
||||||
|
next_worker_(0)
|
||||||
|
{
|
||||||
|
worker_count_ = qBound(1, QThread::idealThreadCount() / 2, 2);
|
||||||
|
local_server_name_ = qApp->applicationName().toLower();
|
||||||
|
|
||||||
|
if (local_server_name_.isEmpty())
|
||||||
|
local_server_name_ = "workerpool";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename HandlerType>
|
||||||
|
void WorkerPool<HandlerType>::SetWorkerCount(int count) {
|
||||||
|
Q_ASSERT(workers_.isEmpty());
|
||||||
|
worker_count_ = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename HandlerType>
|
||||||
|
void WorkerPool<HandlerType>::SetLocalServerName(const QString& local_server_name) {
|
||||||
|
Q_ASSERT(workers_.isEmpty());
|
||||||
|
local_server_name_ = local_server_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename HandlerType>
|
||||||
|
void WorkerPool<HandlerType>::SetExecutableName(const QString& executable_name) {
|
||||||
|
Q_ASSERT(workers_.isEmpty());
|
||||||
|
executable_name_ = executable_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename HandlerType>
|
||||||
|
void WorkerPool<HandlerType>::Start() {
|
||||||
|
Q_ASSERT(workers_.isEmpty());
|
||||||
|
|
||||||
|
// Find the executable if we can, default to searching $PATH
|
||||||
|
executable_path_ = executable_name_;
|
||||||
|
|
||||||
|
QStringList search_path;
|
||||||
|
search_path << qApp->applicationDirPath();
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
search_path << qApp->applicationDirPath() + "/../PlugIns";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
foreach (const QString& path_prefix, search_path) {
|
||||||
|
const QString executable_path = path_prefix + "/" + executable_name_;
|
||||||
|
if (QFile::exists(executable_path)) {
|
||||||
|
executable_path_ = executable_path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start all the workers
|
||||||
|
for (int i=0 ; i<worker_count_ ; ++i) {
|
||||||
|
Worker worker;
|
||||||
|
StartOneWorker(&worker);
|
||||||
|
|
||||||
|
workers_ << worker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename HandlerType>
|
||||||
|
void WorkerPool<HandlerType>::StartOneWorker(Worker* worker) {
|
||||||
|
DeleteQObjectPointerLater(&worker->local_server_);
|
||||||
|
DeleteQObjectPointerLater(&worker->process_);
|
||||||
|
DeleteQObjectPointerLater(&worker->handler_);
|
||||||
|
|
||||||
|
worker->local_server_ = new QLocalServer(this);
|
||||||
|
worker->process_ = new QProcess(this);
|
||||||
|
|
||||||
|
connect(worker->local_server_, SIGNAL(newConnection()), SLOT(NewConnection()));
|
||||||
|
connect(worker->process_, SIGNAL(error(QProcess::ProcessError)),
|
||||||
|
SLOT(ProcessError(QProcess::ProcessError)));
|
||||||
|
|
||||||
|
// Create a server, find an unused name and start listening
|
||||||
|
forever {
|
||||||
|
const int unique_number = qrand() ^ reinterpret_cast<int>(this);
|
||||||
|
const QString name = QString("%1_%2").arg(local_server_name_).arg(unique_number);
|
||||||
|
|
||||||
|
if (worker->local_server_->listen(name)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the process
|
||||||
|
worker->process_->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||||
|
worker->process_->start(executable_path_,
|
||||||
|
QStringList() << worker->socket_server_->fullServerName());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename HandlerType>
|
||||||
|
void WorkerPool<HandlerType>::NewConnection() {
|
||||||
|
QLocalServer* server = qobject_cast<QLocalServer*>(sender());
|
||||||
|
|
||||||
|
// Find the worker with this server.
|
||||||
|
Worker* worker = FindWorker(&Worker::local_server_, server);
|
||||||
|
if (!worker)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Accept the connection.
|
||||||
|
QLocalSocket* socket = server->nextPendingConnection();
|
||||||
|
|
||||||
|
// We only ever accept one connection per worker, so destroy the server now.
|
||||||
|
server->deleteLater();
|
||||||
|
worker->local_server_ = NULL;
|
||||||
|
|
||||||
|
// Create the handler.
|
||||||
|
worker->handler_ = new HandlerType(socket, this);
|
||||||
|
|
||||||
|
emit WorkerConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename HandlerType>
|
||||||
|
void WorkerPool<HandlerType>::ProcessError(QProcess::ProcessError error) {
|
||||||
|
QProcess* process = qobject_cast<QProcess*>(sender());
|
||||||
|
|
||||||
|
// Find the worker with this process.
|
||||||
|
Worker* worker = FindWorker(&Worker::process_, process);
|
||||||
|
if (!worker)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (error) {
|
||||||
|
case QProcess::FailedToStart:
|
||||||
|
// Failed to start errors are bad - it usually means the worker isn't
|
||||||
|
// installed. Don't restart the process, but tell our owner, who will
|
||||||
|
// probably want to do something fatal.
|
||||||
|
emit WorkerFailedToStart();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// On any other error we just restart the process.
|
||||||
|
StartOneWorker(worker);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename HandlerType>
|
||||||
|
HandlerType* WorkerPool<HandlerType>::NextHandler() {
|
||||||
|
for (int i=0 ; i<workers_.count() ; ++i) {
|
||||||
|
const int worker_index = (next_worker_ + i) % workers_.count();
|
||||||
|
|
||||||
|
if (workers_[worker_index].handler_) {
|
||||||
|
next_worker_ = (worker_index + 1) % workers_.count();
|
||||||
|
return workers_[worker_index].handler_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // WORKERPOOL_H
|
|
@ -1,6 +1,6 @@
|
||||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/src)
|
include_directories(${CMAKE_SOURCE_DIR}/ext/libclementine-common)
|
||||||
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/blobversion.h.in
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/blobversion.h.in
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/blobversion.h)
|
${CMAKE_CURRENT_BINARY_DIR}/blobversion.h)
|
||||||
|
@ -26,15 +26,7 @@ add_library(clementine-spotifyblob-messages STATIC
|
||||||
${PROTO_SOURCES}
|
${PROTO_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Use protobuf-lite if it's available
|
|
||||||
if(PROTOBUF_LITE_LIBRARY AND USE_PROTOBUF_LITE)
|
|
||||||
set(protobuf ${PROTOBUF_LITE_LIBRARY})
|
|
||||||
else(PROTOBUF_LITE_LIBRARY AND USE_PROTOBUF_LITE)
|
|
||||||
set(protobuf ${PROTOBUF_LIBRARY})
|
|
||||||
endif(PROTOBUF_LITE_LIBRARY AND USE_PROTOBUF_LITE)
|
|
||||||
|
|
||||||
target_link_libraries(clementine-spotifyblob-messages
|
target_link_libraries(clementine-spotifyblob-messages
|
||||||
${protobuf}
|
libclementine-common
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||||
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
set(MESSAGES
|
||||||
|
tagreadermessages.proto
|
||||||
|
)
|
||||||
|
|
||||||
|
protobuf_generate_cpp(PROTO_SOURCES PROTO_HEADERS ${MESSAGES})
|
||||||
|
|
||||||
|
add_library(libclementine-tagreader STATIC
|
||||||
|
${PROTO_SOURCES}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(libclementine-tagreader
|
||||||
|
libclementine-common
|
||||||
|
)
|
||||||
|
|
|
@ -43,6 +43,10 @@ if(HAVE_BREAKPAD)
|
||||||
include_directories(../3rdparty/google-breakpad)
|
include_directories(../3rdparty/google-breakpad)
|
||||||
endif(HAVE_BREAKPAD)
|
endif(HAVE_BREAKPAD)
|
||||||
|
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/ext/libclementine-common)
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/ext/libclementine-tagreader)
|
||||||
|
include_directories(${CMAKE_BINARY_DIR}/ext/libclementine-tagreader)
|
||||||
|
|
||||||
cmake_policy(SET CMP0011 NEW)
|
cmake_policy(SET CMP0011 NEW)
|
||||||
include(../cmake/ParseArguments.cmake)
|
include(../cmake/ParseArguments.cmake)
|
||||||
include(../cmake/Translations.cmake)
|
include(../cmake/Translations.cmake)
|
||||||
|
@ -59,7 +63,6 @@ set(SOURCES
|
||||||
|
|
||||||
core/backgroundstreams.cpp
|
core/backgroundstreams.cpp
|
||||||
core/backgroundthread.cpp
|
core/backgroundthread.cpp
|
||||||
core/closure.cpp
|
|
||||||
core/commandlineoptions.cpp
|
core/commandlineoptions.cpp
|
||||||
core/crashreporting.cpp
|
core/crashreporting.cpp
|
||||||
core/database.cpp
|
core/database.cpp
|
||||||
|
@ -83,6 +86,7 @@ set(SOURCES
|
||||||
core/song.cpp
|
core/song.cpp
|
||||||
core/songloader.cpp
|
core/songloader.cpp
|
||||||
core/stylesheetloader.cpp
|
core/stylesheetloader.cpp
|
||||||
|
core/tagreaderclient.cpp
|
||||||
core/taskmanager.cpp
|
core/taskmanager.cpp
|
||||||
core/urlhandler.cpp
|
core/urlhandler.cpp
|
||||||
core/utilities.cpp
|
core/utilities.cpp
|
||||||
|
@ -325,7 +329,6 @@ set(HEADERS
|
||||||
|
|
||||||
core/backgroundstreams.h
|
core/backgroundstreams.h
|
||||||
core/backgroundthread.h
|
core/backgroundthread.h
|
||||||
core/closure.h
|
|
||||||
core/crashreporting.h
|
core/crashreporting.h
|
||||||
core/database.h
|
core/database.h
|
||||||
core/deletefiles.h
|
core/deletefiles.h
|
||||||
|
@ -338,6 +341,7 @@ set(HEADERS
|
||||||
core/organise.h
|
core/organise.h
|
||||||
core/player.h
|
core/player.h
|
||||||
core/songloader.h
|
core/songloader.h
|
||||||
|
core/tagreaderclient.h
|
||||||
core/taskmanager.h
|
core/taskmanager.h
|
||||||
core/urlhandler.h
|
core/urlhandler.h
|
||||||
|
|
||||||
|
@ -953,6 +957,8 @@ add_dependencies(clementine_lib pot)
|
||||||
|
|
||||||
|
|
||||||
target_link_libraries(clementine_lib
|
target_link_libraries(clementine_lib
|
||||||
|
libclementine-common
|
||||||
|
libclementine-tagreader
|
||||||
echoprint
|
echoprint
|
||||||
sha2
|
sha2
|
||||||
${ECHONEST_LIBRARIES}
|
${ECHONEST_LIBRARIES}
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "commandlineoptions.h"
|
#include "commandlineoptions.h"
|
||||||
#include "logging.h"
|
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "logging.h"
|
|
||||||
#include "multisortfilterproxy.h"
|
#include "multisortfilterproxy.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
|
||||||
#include <QDate>
|
#include <QDate>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
|
@ -15,12 +15,12 @@
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "encoding.h"
|
|
||||||
#include "logging.h"
|
|
||||||
#include "mpris_common.h"
|
#include "mpris_common.h"
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
#include "timeconstants.h"
|
#include "timeconstants.h"
|
||||||
#include "tagreader/common/messagehandler.h"
|
#include "core/encoding.h"
|
||||||
|
#include "core/logging.h"
|
||||||
|
#include "core/messagehandler.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
|
@ -17,21 +17,22 @@
|
||||||
|
|
||||||
#include "tagreaderclient.h"
|
#include "tagreaderclient.h"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QFile>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QTcpServer>
|
||||||
|
|
||||||
|
|
||||||
|
const char* TagReaderClient::kWorkerExecutableName = "clementine-tagreader";
|
||||||
|
|
||||||
TagReaderClient::TagReaderClient(QObject* parent)
|
TagReaderClient::TagReaderClient(QObject* parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
process_(NULL),
|
worker_pool_(new WorkerPool<HandlerType>(this))
|
||||||
handler_(NULL)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void TagReaderClient::Start() {
|
void TagReaderClient::Start() {
|
||||||
delete process_;
|
worker_pool_->Start();
|
||||||
delete handler_;
|
|
||||||
|
|
||||||
process_ = new QProcess(this);
|
|
||||||
process_->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TagReaderReply* TagReaderClient::ReadFile(const QString& filename) {
|
TagReaderReply* TagReaderClient::ReadFile(const QString& filename) {
|
||||||
|
@ -40,7 +41,7 @@ TagReaderReply* TagReaderClient::ReadFile(const QString& filename) {
|
||||||
|
|
||||||
req->set_filename(DataCommaSizeFromQString(filename));
|
req->set_filename(DataCommaSizeFromQString(filename));
|
||||||
|
|
||||||
return SendMessageWithReply(&message);
|
return handler_->SendMessageWithReply(&message);
|
||||||
}
|
}
|
||||||
|
|
||||||
TagReaderReply* TagReaderClient::SaveFile(const QString& filename, const Song& metadata) {
|
TagReaderReply* TagReaderClient::SaveFile(const QString& filename, const Song& metadata) {
|
||||||
|
@ -50,7 +51,7 @@ TagReaderReply* TagReaderClient::SaveFile(const QString& filename, const Song& m
|
||||||
req->set_filename(DataCommaSizeFromQString(filename));
|
req->set_filename(DataCommaSizeFromQString(filename));
|
||||||
metadata.ToProtobuf(req->mutable_metadata());
|
metadata.ToProtobuf(req->mutable_metadata());
|
||||||
|
|
||||||
return SendMessageWithReply(&message);
|
return handler_->SendMessageWithReply(&message);
|
||||||
}
|
}
|
||||||
|
|
||||||
TagReaderReply* TagReaderClient::IsMediaFile(const QString& filename) {
|
TagReaderReply* TagReaderClient::IsMediaFile(const QString& filename) {
|
||||||
|
@ -59,7 +60,7 @@ TagReaderReply* TagReaderClient::IsMediaFile(const QString& filename) {
|
||||||
|
|
||||||
req->set_filename(DataCommaSizeFromQString(filename));
|
req->set_filename(DataCommaSizeFromQString(filename));
|
||||||
|
|
||||||
return SendMessageWithReply(&message);
|
return handler_->SendMessageWithReply(&message);
|
||||||
}
|
}
|
||||||
|
|
||||||
TagReaderReply* TagReaderClient::LoadEmbeddedArt(const QString& filename) {
|
TagReaderReply* TagReaderClient::LoadEmbeddedArt(const QString& filename) {
|
||||||
|
@ -68,5 +69,5 @@ TagReaderReply* TagReaderClient::LoadEmbeddedArt(const QString& filename) {
|
||||||
|
|
||||||
req->set_filename(DataCommaSizeFromQString(filename));
|
req->set_filename(DataCommaSizeFromQString(filename));
|
||||||
|
|
||||||
return SendMessageWithReply(&message);
|
return handler_->SendMessageWithReply(&message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,14 @@
|
||||||
#ifndef TAGREADERCLIENT_H
|
#ifndef TAGREADERCLIENT_H
|
||||||
#define TAGREADERCLIENT_H
|
#define TAGREADERCLIENT_H
|
||||||
|
|
||||||
#include "messagehandler.h"
|
|
||||||
#include "song.h"
|
#include "song.h"
|
||||||
#include "tagreadermessages.pb.h"
|
#include "tagreadermessages.pb.h"
|
||||||
|
#include "core/messagehandler.h"
|
||||||
|
#include "core/workerpool.h"
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
class QLocalServer;
|
||||||
class QProcess;
|
class QProcess;
|
||||||
|
|
||||||
class TagReaderClient : public QObject {
|
class TagReaderClient : public QObject {
|
||||||
|
@ -33,6 +37,8 @@ public:
|
||||||
typedef AbstractMessageHandler<pb::tagreader::Message> HandlerType;
|
typedef AbstractMessageHandler<pb::tagreader::Message> HandlerType;
|
||||||
typedef typename HandlerType::ReplyType ReplyType;
|
typedef typename HandlerType::ReplyType ReplyType;
|
||||||
|
|
||||||
|
static const char* kWorkerExecutableName;
|
||||||
|
|
||||||
void Start();
|
void Start();
|
||||||
|
|
||||||
ReplyType* ReadFile(const QString& filename);
|
ReplyType* ReadFile(const QString& filename);
|
||||||
|
@ -41,8 +47,11 @@ public:
|
||||||
ReplyType* LoadEmbeddedArt(const QString& filename);
|
ReplyType* LoadEmbeddedArt(const QString& filename);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QProcess* process_;
|
void SendOrQueue(const pb::tagreader::Message& message);
|
||||||
HandlerType* handler_;
|
|
||||||
|
private:
|
||||||
|
WorkerPool<HandlerType>* worker_pool_;
|
||||||
|
QList<pb::tagreader::Message> message_queue_;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef TagReaderClient::ReplyType TagReaderReply;
|
typedef TagReaderClient::ReplyType TagReaderReply;
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "core/player.h"
|
#include "core/player.h"
|
||||||
#include "core/potranslator.h"
|
#include "core/potranslator.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
|
#include "core/tagreaderclient.h"
|
||||||
#include "core/taskmanager.h"
|
#include "core/taskmanager.h"
|
||||||
#include "core/ubuntuunityhack.h"
|
#include "core/ubuntuunityhack.h"
|
||||||
#include "core/utilities.h"
|
#include "core/utilities.h"
|
||||||
|
@ -407,6 +408,9 @@ int main(int argc, char *argv[]) {
|
||||||
GlobalSearchService global_search_service(&global_search);
|
GlobalSearchService global_search_service(&global_search);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Tag reader client
|
||||||
|
TagReaderClient tag_reader_client;
|
||||||
|
|
||||||
// Window
|
// Window
|
||||||
MainWindow w(
|
MainWindow w(
|
||||||
database.get(),
|
database.get(),
|
||||||
|
@ -418,7 +422,8 @@ int main(int argc, char *argv[]) {
|
||||||
&osd,
|
&osd,
|
||||||
&art_loader,
|
&art_loader,
|
||||||
&cover_providers,
|
&cover_providers,
|
||||||
&global_search);
|
&global_search,
|
||||||
|
&tag_reader_client);
|
||||||
#ifdef HAVE_DBUS
|
#ifdef HAVE_DBUS
|
||||||
QObject::connect(&mpris, SIGNAL(RaiseMainWindow()), &w, SLOT(Raise()));
|
QObject::connect(&mpris, SIGNAL(RaiseMainWindow()), &w, SLOT(Raise()));
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -161,6 +161,7 @@ MainWindow::MainWindow(
|
||||||
ArtLoader* art_loader,
|
ArtLoader* art_loader,
|
||||||
CoverProviders* cover_providers,
|
CoverProviders* cover_providers,
|
||||||
GlobalSearch* global_search,
|
GlobalSearch* global_search,
|
||||||
|
TagReader* tag_reader_client,
|
||||||
QWidget* parent)
|
QWidget* parent)
|
||||||
: QMainWindow(parent),
|
: QMainWindow(parent),
|
||||||
ui_(new Ui_MainWindow),
|
ui_(new Ui_MainWindow),
|
||||||
|
@ -177,6 +178,7 @@ MainWindow::MainWindow(
|
||||||
library_(NULL),
|
library_(NULL),
|
||||||
global_shortcuts_(new GlobalShortcuts(this)),
|
global_shortcuts_(new GlobalShortcuts(this)),
|
||||||
global_search_(global_search),
|
global_search_(global_search),
|
||||||
|
tag_reader_client_(tag_reader_client),
|
||||||
remote_(NULL),
|
remote_(NULL),
|
||||||
devices_(NULL),
|
devices_(NULL),
|
||||||
library_view_(new LibraryViewContainer(this)),
|
library_view_(new LibraryViewContainer(this)),
|
||||||
|
|
|
@ -68,6 +68,7 @@ class SongInfoBase;
|
||||||
class SongInfoView;
|
class SongInfoView;
|
||||||
class SystemTrayIcon;
|
class SystemTrayIcon;
|
||||||
class TagFetcher;
|
class TagFetcher;
|
||||||
|
class TagReaderClient;
|
||||||
class TaskManager;
|
class TaskManager;
|
||||||
class TrackSelectionDialog;
|
class TrackSelectionDialog;
|
||||||
class TranscodeDialog;
|
class TranscodeDialog;
|
||||||
|
@ -92,6 +93,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||||
ArtLoader* art_loader,
|
ArtLoader* art_loader,
|
||||||
CoverProviders* cover_providers,
|
CoverProviders* cover_providers,
|
||||||
GlobalSearch* global_search,
|
GlobalSearch* global_search,
|
||||||
|
TagReaderClient* tag_reader_client,
|
||||||
QWidget *parent = 0);
|
QWidget *parent = 0);
|
||||||
~MainWindow();
|
~MainWindow();
|
||||||
|
|
||||||
|
@ -279,6 +281,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||||
Library* library_;
|
Library* library_;
|
||||||
GlobalShortcuts* global_shortcuts_;
|
GlobalShortcuts* global_shortcuts_;
|
||||||
GlobalSearch* global_search_;
|
GlobalSearch* global_search_;
|
||||||
|
TagReaderClient* tag_reader_client_;
|
||||||
Remote* remote_;
|
Remote* remote_;
|
||||||
|
|
||||||
DeviceManager* devices_;
|
DeviceManager* devices_;
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/src)
|
|
||||||
|
|
||||||
set(COMMON_SOURCES
|
|
||||||
messagehandler.cpp
|
|
||||||
|
|
||||||
${CMAKE_SOURCE_DIR}/src/core/encoding.cpp
|
|
||||||
${CMAKE_SOURCE_DIR}/src/core/logging.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(COMMON_HEADERS
|
|
||||||
messagehandler.h
|
|
||||||
)
|
|
||||||
|
|
||||||
set(COMMON_MESSAGES
|
|
||||||
tagreadermessages.proto
|
|
||||||
)
|
|
||||||
|
|
||||||
qt4_wrap_cpp(COMMON_MOC ${COMMON_HEADERS})
|
|
||||||
protobuf_generate_cpp(PROTO_SOURCES PROTO_HEADERS ${COMMON_MESSAGES})
|
|
||||||
|
|
||||||
add_library(clementine-tagreader-common STATIC
|
|
||||||
${COMMON_SOURCES}
|
|
||||||
${COMMON_MOC}
|
|
||||||
${PROTO_SOURCES}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Use protobuf-lite if it's available
|
|
||||||
if(PROTOBUF_LITE_LIBRARY AND USE_PROTOBUF_LITE)
|
|
||||||
set(protobuf ${PROTOBUF_LITE_LIBRARY})
|
|
||||||
else(PROTOBUF_LITE_LIBRARY AND USE_PROTOBUF_LITE)
|
|
||||||
set(protobuf ${PROTOBUF_LIBRARY})
|
|
||||||
endif(PROTOBUF_LITE_LIBRARY AND USE_PROTOBUF_LITE)
|
|
||||||
|
|
||||||
target_link_libraries(clementine-tagreader-common
|
|
||||||
${protobuf}
|
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
|
||||||
chardet
|
|
||||||
)
|
|
||||||
|
|
Loading…
Reference in New Issue