Only start internal HTTP server when required, and stop 1 second after last Cantata stream is removed.
BUG: 369
This commit is contained in:
committed by
craig.p.drummond
parent
16b3ed8e25
commit
3a07ab4e6d
@@ -247,7 +247,7 @@ set(CANTATA_MOC_HDRS
|
||||
widgets/playqueueview.h widgets/groupedview.h widgets/actionitemdelegate.h widgets/coverwidget.h widgets/volumeslider.h
|
||||
widgets/genrecombo.h widgets/toolbar.h widgets/searchwidget.h widgets/messageoverlay.h widgets/servicestatuslabel.h
|
||||
network/networkaccessmanager.h
|
||||
http/httpserversettings.h http/httpsocket.h
|
||||
http/httpserver.h http/httpsocket.h
|
||||
context/togglelist.h context/ultimatelyrics.h context/ultimatelyricsprovider.h context/lyricsdialog.h
|
||||
context/contextwidget.h context/artistview.h context/albumview.h context/songview.h context/view.h context/contextengine.h
|
||||
context/wikipediaengine.h context/wikipediasettings.h context/othersettings.h context/lastfmengine.h context/metaengine.h
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
12. When adding files to playqueue, only add in batches of up to 2000 songs.
|
||||
This 'chunk size' may be altered by setting mpdListSize in Cantata's config
|
||||
file - see README for details.
|
||||
13. Add 'Remove dusplicates' functionality to play queue and play lists.
|
||||
13. Add 'Remove duplicates' functionality to play queue and play lists.
|
||||
14. Only start internal HTTP server when required, and stop 1 second after
|
||||
last Cantata stream is removed.
|
||||
|
||||
1.2.2
|
||||
-----
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "thread.h"
|
||||
#include <QFile>
|
||||
#include <QUrl>
|
||||
#include <QTimer>
|
||||
#if QT_VERSION >= 0x050000
|
||||
#include <QUrlQuery>
|
||||
#endif
|
||||
@@ -72,51 +73,72 @@ HttpServer * HttpServer::self()
|
||||
#endif
|
||||
}
|
||||
|
||||
void HttpServer::stop()
|
||||
HttpServer::HttpServer()
|
||||
: QObject(0)
|
||||
, thread(0)
|
||||
, socket(0)
|
||||
, closeTimer(0)
|
||||
{
|
||||
if (socket) {
|
||||
socket->terminate();
|
||||
socket=0;
|
||||
}
|
||||
|
||||
if (thread) {
|
||||
thread->stop();
|
||||
thread=0;
|
||||
}
|
||||
connect(MPDConnection::self(), SIGNAL(socketAddress(QString)), this, SLOT(mpdAddress(QString)));
|
||||
connect(MPDConnection::self(), SIGNAL(cantataStreams(QList<Song>,bool)), this, SLOT(cantataStreams(QList<Song>,bool)));
|
||||
connect(MPDConnection::self(), SIGNAL(cantataStreams(QStringList)), this, SLOT(cantataStreams(QStringList)));
|
||||
connect(MPDConnection::self(), SIGNAL(removedIds(QSet<qint32>)), this, SLOT(removedIds(QSet<qint32>)));
|
||||
}
|
||||
|
||||
bool HttpServer::readConfig()
|
||||
bool HttpServer::start()
|
||||
{
|
||||
QString iface=Settings::self()->httpInterface();
|
||||
if (closeTimer) {
|
||||
DBUG << "stop close timer";
|
||||
closeTimer->stop();
|
||||
}
|
||||
|
||||
if (socket && socket->isListening() && iface==socket->configuredInterface()) {
|
||||
if (socket) {
|
||||
DBUG << "already open";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (socket) {
|
||||
socket->terminate();
|
||||
socket=0;
|
||||
}
|
||||
|
||||
if (thread) {
|
||||
thread->stop();
|
||||
thread=0;
|
||||
}
|
||||
|
||||
DBUG << "open new socket";
|
||||
quint16 prevPort=Settings::self()->httpAllocatedPort();
|
||||
thread=new Thread("HttpServer");
|
||||
socket=new HttpSocket(iface, prevPort);
|
||||
bool newThread=0==thread;
|
||||
if (newThread) {
|
||||
thread=new Thread("HttpServer");
|
||||
}
|
||||
socket=new HttpSocket(Settings::self()->httpInterface(), prevPort);
|
||||
socket->mpdAddress(mpdAddr);
|
||||
connect(this, SIGNAL(terminateSocket()), socket, SLOT(terminate()), Qt::QueuedConnection);
|
||||
if (socket->serverPort()!=prevPort) {
|
||||
Settings::self()->saveHttpAllocatedPort(socket->serverPort());
|
||||
}
|
||||
socket->moveToThread(thread);
|
||||
thread->start();
|
||||
return socket->isListening();
|
||||
bool started=socket->isListening();
|
||||
if (newThread) {
|
||||
thread->start();
|
||||
}
|
||||
return started;
|
||||
}
|
||||
|
||||
bool HttpServer::isAlive() const
|
||||
void HttpServer::stop()
|
||||
{
|
||||
return socket && socket->isListening();
|
||||
if (socket) {
|
||||
DBUG;
|
||||
emit terminateSocket();
|
||||
socket=0;
|
||||
}
|
||||
}
|
||||
|
||||
void HttpServer::readConfig()
|
||||
{
|
||||
QString iface=Settings::self()->httpInterface();
|
||||
|
||||
if (socket && socket->isListening() && iface==socket->configuredInterface()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool wasStarted=0!=socket;
|
||||
stop();
|
||||
if (wasStarted) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
QString HttpServer::address() const
|
||||
@@ -127,13 +149,13 @@ QString HttpServer::address() const
|
||||
|
||||
bool HttpServer::isOurs(const QString &url) const
|
||||
{
|
||||
return isAlive() ? url.startsWith(address()+"/") : false;
|
||||
return 0!=socket ? url.startsWith(address()+"/") : false;
|
||||
}
|
||||
|
||||
QByteArray HttpServer::encodeUrl(const Song &s) const
|
||||
QByteArray HttpServer::encodeUrl(const Song &s)
|
||||
{
|
||||
DBUG << "song" << s.file << isAlive();
|
||||
if (!isAlive()) {
|
||||
if (!start()) {
|
||||
return QByteArray();
|
||||
}
|
||||
#if QT_VERSION < 0x050000
|
||||
@@ -186,7 +208,7 @@ QByteArray HttpServer::encodeUrl(const Song &s) const
|
||||
return url.toEncoded();
|
||||
}
|
||||
|
||||
QByteArray HttpServer::encodeUrl(const QString &file) const
|
||||
QByteArray HttpServer::encodeUrl(const QString &file)
|
||||
{
|
||||
Song s;
|
||||
#ifdef Q_OS_WIN
|
||||
@@ -284,3 +306,57 @@ Song HttpServer::decodeUrl(const QUrl &url) const
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void HttpServer::startCloseTimer()
|
||||
{
|
||||
if (!closeTimer) {
|
||||
closeTimer=new QTimer(this);
|
||||
closeTimer->setSingleShot(true);
|
||||
connect(closeTimer, SIGNAL(timeout()), this, SLOT(stop()));
|
||||
}
|
||||
DBUG;
|
||||
closeTimer->start(1000);
|
||||
}
|
||||
|
||||
void HttpServer::mpdAddress(const QString &a)
|
||||
{
|
||||
mpdAddr=a;
|
||||
}
|
||||
|
||||
void HttpServer::cantataStreams(const QStringList &files)
|
||||
{
|
||||
DBUG << files;
|
||||
foreach (const QString &f, files) {
|
||||
Song s=HttpServer::self()->decodeUrl(f);
|
||||
if (s.isCantataStream() || s.isCdda()) {
|
||||
start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HttpServer::cantataStreams(const QList<Song> &songs, bool isUpdate)
|
||||
{
|
||||
DBUG << isUpdate << songs.count();
|
||||
if (!isUpdate) {
|
||||
streamIds.clear();
|
||||
}
|
||||
|
||||
foreach (const Song &s, songs) {
|
||||
streamIds.insert(s.id);
|
||||
}
|
||||
|
||||
if (streamIds.isEmpty()) {
|
||||
startCloseTimer();
|
||||
} else {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
void HttpServer::removedIds(const QSet<qint32> &ids)
|
||||
{
|
||||
streamIds+=ids;
|
||||
if (streamIds.isEmpty()) {
|
||||
startCloseTimer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,39 +24,60 @@
|
||||
#ifndef _HTTP_SERVER_H
|
||||
#define _HTTP_SERVER_H
|
||||
|
||||
#include <qglobal.h>
|
||||
#include <QObject>
|
||||
#include <QByteArray>
|
||||
#include <QSet>
|
||||
#include "song.h"
|
||||
#include "config.h"
|
||||
|
||||
class HttpSocket;
|
||||
class Thread;
|
||||
class QUrl;
|
||||
class QTimer;
|
||||
|
||||
class HttpServer
|
||||
class HttpServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static void enableDebug();
|
||||
static bool debugEnabled();
|
||||
|
||||
static HttpServer * self();
|
||||
|
||||
HttpServer() : thread(0), socket(0) { }
|
||||
HttpServer();
|
||||
virtual ~HttpServer() { }
|
||||
|
||||
void stop();
|
||||
bool isAlive() const;
|
||||
bool readConfig();
|
||||
bool start();
|
||||
bool isAlive() const { return true; } // Started on-demamnd!
|
||||
void readConfig();
|
||||
QString address() const;
|
||||
bool isOurs(const QString &url) const;
|
||||
QByteArray encodeUrl(const Song &s) const;
|
||||
QByteArray encodeUrl(const QString &file) const;
|
||||
QByteArray encodeUrl(const Song &s);
|
||||
QByteArray encodeUrl(const QString &file);
|
||||
Song decodeUrl(const QUrl &url) const;
|
||||
Song decodeUrl(const QString &file) const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void stop();
|
||||
|
||||
private Q_SLOTS:
|
||||
void startCloseTimer();
|
||||
void mpdAddress(const QString &a);
|
||||
void cantataStreams(const QStringList &files);
|
||||
void cantataStreams(const QList<Song> &songs, bool isUpdate);
|
||||
void removedIds(const QSet<qint32> &ids);
|
||||
|
||||
Q_SIGNALS:
|
||||
void terminateSocket();
|
||||
|
||||
private:
|
||||
Thread *thread;
|
||||
HttpSocket *socket;
|
||||
|
||||
QString mpdAddr;
|
||||
QSet<qint32> streamIds; // Currently playing MPD stream IDs
|
||||
QTimer *closeTimer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "localize.h"
|
||||
#include "httpserver.h"
|
||||
#include <QComboBox>
|
||||
#include <QTimer>
|
||||
#include <QNetworkInterface>
|
||||
|
||||
static int isIfaceType(const QNetworkInterface &iface, const QString &prefix)
|
||||
@@ -64,7 +63,6 @@ HttpServerSettings::HttpServerSettings(QWidget *p)
|
||||
{
|
||||
setupUi(this);
|
||||
initInterfaces(httpInterface);
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
void HttpServerSettings::load()
|
||||
@@ -87,14 +85,4 @@ void HttpServerSettings::save()
|
||||
{
|
||||
Settings::self()->saveHttpInterface(httpInterface->itemData(httpInterface->currentIndex()).toString());
|
||||
HttpServer::self()->readConfig();
|
||||
QTimer::singleShot(250, this, SLOT(updateStatus()));
|
||||
}
|
||||
|
||||
void HttpServerSettings::updateStatus()
|
||||
{
|
||||
if (HttpServer::self()->isAlive()) {
|
||||
status->setText(HttpServer::self()->address());
|
||||
} else {
|
||||
status->setText(i18n("Inactive"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
class HttpServerSettings : public QWidget, private Ui::HttpServerSettings
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
HttpServerSettings(QWidget *p);
|
||||
virtual ~HttpServerSettings() { }
|
||||
@@ -36,9 +35,6 @@ public:
|
||||
void load();
|
||||
void save();
|
||||
bool haveMultipleInterfaces() const;
|
||||
|
||||
private Q_SLOTS:
|
||||
void updateStatus();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -32,22 +32,6 @@
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="httpInterface"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3b">
|
||||
<property name="text">
|
||||
<string>Current URL:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="status">
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
</font>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
||||
@@ -259,6 +259,8 @@ HttpSocket::HttpSocket(const QString &iface, quint16 port)
|
||||
ifaceAddress=QLatin1String("127.0.0.1");
|
||||
}
|
||||
|
||||
DBUG << isListening() << ifaceAddress << serverPort();
|
||||
|
||||
connect(MPDConnection::self(), SIGNAL(socketAddress(QString)), this, SLOT(mpdAddress(QString)));
|
||||
connect(MPDConnection::self(), SIGNAL(cantataStreams(QList<Song>,bool)), this, SLOT(cantataStreams(QList<Song>,bool)));
|
||||
connect(MPDConnection::self(), SIGNAL(cantataStreams(QStringList)), this, SLOT(cantataStreams(QStringList)));
|
||||
@@ -293,7 +295,12 @@ bool HttpSocket::openPort(const QHostAddress &a, quint16 p)
|
||||
|
||||
void HttpSocket::terminate()
|
||||
{
|
||||
if (terminated) {
|
||||
return;
|
||||
}
|
||||
DBUG;
|
||||
terminated=true;
|
||||
close();
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
|
||||
@@ -41,11 +41,14 @@ public:
|
||||
HttpSocket(const QString &iface, quint16 port);
|
||||
virtual ~HttpSocket() { }
|
||||
|
||||
void terminate();
|
||||
void incomingConnection(int socket);
|
||||
QString address() const { return ifaceAddress; }
|
||||
QString configuredInterface() { return cfgInterface; }
|
||||
|
||||
public Q_SLOTS:
|
||||
void terminate();
|
||||
void mpdAddress(const QString &a);
|
||||
|
||||
private:
|
||||
bool openPort(const QHostAddress &a, quint16 p);
|
||||
bool isCantataStream(const QString &file) const;
|
||||
@@ -54,7 +57,6 @@ private:
|
||||
private Q_SLOTS:
|
||||
void readClient();
|
||||
void discardClient();
|
||||
void mpdAddress(const QString &a);
|
||||
void cantataStreams(const QStringList &files);
|
||||
void cantataStreams(const QList<Song> &songs, bool isUpdate);
|
||||
void removedIds(const QSet<qint32> &ids);
|
||||
|
||||
Reference in New Issue
Block a user