mirror of
https://github.com/HenkKalkwater/harbour-sailfin.git
synced 2024-12-22 22:15:17 +00:00
Added basis for WebSocket connection
This commit is contained in:
parent
5576e53656
commit
97429ff6ec
|
@ -12,7 +12,7 @@
|
|||
# The name of your application
|
||||
TARGET = harbour-sailfin
|
||||
|
||||
QT += multimedia
|
||||
QT += multimedia websockets
|
||||
|
||||
CONFIG += sailfishapp c++11
|
||||
|
||||
|
@ -31,6 +31,7 @@ SOURCES += \
|
|||
src/jellyfinapimodel.cpp \
|
||||
src/jellyfindeviceprofile.cpp \
|
||||
src/jellyfinmediasource.cpp \
|
||||
src/jellyfinwebsocket.cpp \
|
||||
src/serverdiscoverymodel.cpp
|
||||
|
||||
DISTFILES += \
|
||||
|
@ -90,4 +91,5 @@ HEADERS += \
|
|||
src/jellyfinapimodel.h \
|
||||
src/jellyfindeviceprofile.h \
|
||||
src/jellyfinmediasource.h \
|
||||
src/jellyfinwebsocket.h \
|
||||
src/serverdiscoverymodel.h
|
||||
|
|
|
@ -22,6 +22,7 @@ PkgConfigBR:
|
|||
- Qt5Core
|
||||
- Qt5Qml
|
||||
- Qt5Quick
|
||||
- Qt5WebSockets
|
||||
|
||||
# Build dependencies without a pkgconfig setup can be listed here
|
||||
# PkgBR:
|
||||
|
@ -30,6 +31,7 @@ PkgConfigBR:
|
|||
# Runtime dependencies which are not automatically detected
|
||||
Requires:
|
||||
- sailfishsilica-qt5 >= 0.10.9
|
||||
- qt5-qtdeclarative-import-xmllistmodel
|
||||
|
||||
# All installed files
|
||||
Files:
|
||||
|
|
|
@ -21,7 +21,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
namespace Jellyfin {
|
||||
ApiClient::ApiClient(QObject *parent)
|
||||
: QObject(parent) {
|
||||
: QObject(parent),
|
||||
m_webSocket(new WebSocket(this)) {
|
||||
m_deviceName = QHostInfo::localHostName();
|
||||
m_deviceId = QUuid::createUuid().toString(); // TODO: make this not random?
|
||||
m_credManager = CredentialsManager::newInstance(this);
|
||||
|
@ -268,4 +269,10 @@ void ApiClient::defaultNetworkErrorHandler(QNetworkReply::NetworkError error) {
|
|||
}
|
||||
rep->deleteLater();
|
||||
}
|
||||
|
||||
void ApiClient::setAuthenticated(bool authenticated) {
|
||||
this->m_authenticated = authenticated;
|
||||
if (authenticated) m_webSocket->open();
|
||||
emit authenticatedChanged(authenticated);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,9 +37,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
#include "credentialmanager.h"
|
||||
#include "jellyfindeviceprofile.h"
|
||||
#include "jellyfinwebsocket.h"
|
||||
|
||||
namespace Jellyfin {
|
||||
class MediaSource;
|
||||
class WebSocket;
|
||||
/**
|
||||
* @brief An Api client for Jellyfin. Handles requests and authentication.
|
||||
*
|
||||
|
@ -67,6 +69,7 @@ class MediaSource;
|
|||
*/
|
||||
class ApiClient : public QObject {
|
||||
friend class MediaSource;
|
||||
friend class WebSocket;
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ApiClient(QObject *parent = nullptr);
|
||||
|
@ -194,6 +197,7 @@ private:
|
|||
/*
|
||||
* State information
|
||||
*/
|
||||
WebSocket *m_webSocket;
|
||||
CredentialsManager * m_credManager;
|
||||
QString m_token;
|
||||
QString m_deviceName;
|
||||
|
@ -212,10 +216,8 @@ private:
|
|||
* Setters
|
||||
*/
|
||||
|
||||
void setAuthenticated(bool authenticated) {
|
||||
this->m_authenticated = authenticated;
|
||||
emit authenticatedChanged(authenticated);
|
||||
}
|
||||
void setAuthenticated(bool authenticated);
|
||||
|
||||
void setUserId(QString userId) {
|
||||
this->m_userId = userId;
|
||||
emit userIdChanged(userId);
|
||||
|
|
108
src/jellyfinwebsocket.cpp
Normal file
108
src/jellyfinwebsocket.cpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
Sailfin: a Jellyfin client written using Qt
|
||||
Copyright (C) 2020 Chris Josten
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "jellyfinwebsocket.h"
|
||||
|
||||
namespace Jellyfin {
|
||||
WebSocket::WebSocket(ApiClient *client)
|
||||
: QObject (client), m_apiClient(client){
|
||||
connect(&m_webSocket, &QWebSocket::connected, this, &WebSocket::onConnected);
|
||||
connect(&m_webSocket, static_cast<void (QWebSocket::*)(QAbstractSocket::SocketError)>(&QWebSocket::error),
|
||||
this, [this](QAbstractSocket::SocketError error) {
|
||||
Q_UNUSED(error)
|
||||
qDebug() << "Connection error: " << m_webSocket.errorString();
|
||||
});
|
||||
}
|
||||
|
||||
void WebSocket::open() {
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("api_key", m_apiClient->token());
|
||||
query.addQueryItem("deviceId", m_apiClient->m_deviceId);
|
||||
QUrl connectionUrl(m_apiClient->baseUrl());
|
||||
connectionUrl.setScheme(connectionUrl.scheme() == "http" ? "ws" : "wss");
|
||||
connectionUrl.setPath("/socket");
|
||||
connectionUrl.setQuery(query);
|
||||
m_webSocket.open(connectionUrl);
|
||||
qDebug() << "Opening WebSocket connection to " << m_webSocket.requestUrl();
|
||||
}
|
||||
|
||||
void WebSocket::onConnected() {
|
||||
connect(&m_webSocket, &QWebSocket::textMessageReceived, this, &WebSocket::textMessageReceived);
|
||||
}
|
||||
|
||||
void WebSocket::textMessageReceived(const QString &message) {
|
||||
QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8());
|
||||
if (doc.isNull() || !doc.isObject()) {
|
||||
qWarning() << "Malformed message received over WebSocket: parse error or root not an object.";
|
||||
return;
|
||||
}
|
||||
QJsonObject messageRoot = doc.object();
|
||||
if (!messageRoot.contains("MessageType") || !messageRoot.contains("Data")) {
|
||||
qWarning() << "Malformed message received over WebSocket: no MessageType and Data set.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the type so we can use it in our enums.
|
||||
QString messageTypeStr = messageRoot["MessageType"].toString();
|
||||
bool ok;
|
||||
MessageType messageType = static_cast<MessageType>(QMetaEnum::fromType<WebSocket::MessageType>().keyToValue(messageTypeStr.toLatin1(), &ok));
|
||||
if (!ok) {
|
||||
qWarning() << "Unknown message arrived: " << messageTypeStr;
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonValue data = messageRoot["Data"];
|
||||
qDebug() << "Received message: " << messageTypeStr;
|
||||
|
||||
switch (messageType) {
|
||||
case ForceKeepAlive:
|
||||
setupKeepAlive(data.toInt(-1));
|
||||
break;
|
||||
case KeepAlive:
|
||||
//TODO: do something?
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void WebSocket::sendKeepAlive() {
|
||||
sendMessage(KeepAlive);
|
||||
}
|
||||
|
||||
void WebSocket::setupKeepAlive(int data) {
|
||||
// Data is timeout in seconds, we want to send a keepalive at half the timeout
|
||||
m_keepAliveTimer.setInterval(data * 500);
|
||||
m_keepAliveTimer.setSingleShot(false);
|
||||
connect(&m_keepAliveTimer, &QTimer::timeout, this, &WebSocket::sendKeepAlive);
|
||||
m_keepAliveTimer.start();
|
||||
sendKeepAlive();
|
||||
}
|
||||
|
||||
QString WebSocket::generateMessageId() {
|
||||
return QUuid::createUuid().toString();
|
||||
}
|
||||
|
||||
void WebSocket::sendMessage(MessageType type, QJsonValue data) {
|
||||
QJsonObject root;
|
||||
root["MessageType"] = QVariant::fromValue(type).toString();
|
||||
root["Data"] = data;
|
||||
QString message = QJsonDocument(root).toJson(QJsonDocument::Compact);
|
||||
m_webSocket.sendTextMessage(message);
|
||||
qDebug() << "Sent message: " << message;
|
||||
}
|
||||
}
|
76
src/jellyfinwebsocket.h
Normal file
76
src/jellyfinwebsocket.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
Sailfin: a Jellyfin client written using Qt
|
||||
Copyright (C) 2020 Chris Josten
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef JELLYFIN_WEBSOCKET_H
|
||||
#define JELLYFIN_WEBSOCKET_H
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QDebug>
|
||||
#include <QObject>
|
||||
#include <QtGlobal>
|
||||
#include <QTimer>
|
||||
#include <QUuid>
|
||||
|
||||
#include <QtWebSockets/QWebSocket>
|
||||
|
||||
#include "jellyfinapiclient.h"
|
||||
|
||||
namespace Jellyfin {
|
||||
class ApiClient;
|
||||
class WebSocket : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief WebSocket creates a webSocket for a Jellyfin server to handle real time updates.
|
||||
* @param client The client to create the socket for.
|
||||
*
|
||||
* The socket will automatically set the ApiClient to its parent.
|
||||
*/
|
||||
explicit WebSocket(ApiClient *client);
|
||||
enum MessageType {
|
||||
ForceKeepAlive,
|
||||
KeepAlive
|
||||
};
|
||||
Q_ENUM(MessageType)
|
||||
public slots:
|
||||
void open();
|
||||
private slots:
|
||||
void textMessageReceived(const QString &message);
|
||||
void onConnected();
|
||||
|
||||
void sendKeepAlive();
|
||||
signals:
|
||||
void commandReceived(QString arts, QVariantMap args);
|
||||
|
||||
protected:
|
||||
ApiClient *m_apiClient;
|
||||
QWebSocket m_webSocket;
|
||||
|
||||
QTimer m_keepAliveTimer;
|
||||
|
||||
|
||||
void setupKeepAlive(int data);
|
||||
void sendMessage(MessageType type, QJsonValue data = QJsonValue());
|
||||
QString generateMessageId();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // JELLYFIN_WEBSOCKET_H
|
Loading…
Reference in a new issue