New networkpackage format and serialization using qjson and qvariantmap (and templates fun)
This commit is contained in:
parent
975892dcd0
commit
b1e4e2d836
15 changed files with 171 additions and 107 deletions
|
@ -26,6 +26,7 @@ target_link_libraries(kded_kdeconnect
|
|||
${KDE4_KDECORE_LIBS}
|
||||
${KDE4_KDEUI_LIBS}
|
||||
kdnssd
|
||||
qjson
|
||||
${QT_QTNETWORK_LIBRARY}
|
||||
${QJSON_LIBRARIES}
|
||||
${QJSON_LIBRARY}
|
||||
|
|
|
@ -58,18 +58,23 @@ void AvahiAnnouncer::readPendingNotifications()
|
|||
//log.write(datagram);
|
||||
qDebug() << "AvahiAnnouncer incomming udp datagram: " << datagram;
|
||||
|
||||
NetworkPackage np = NetworkPackage::fromString(datagram);
|
||||
NetworkPackage np;
|
||||
NetworkPackage::unserialize(datagram,&np);
|
||||
|
||||
QString id = np.deviceId();
|
||||
QString name = np.body();
|
||||
if (np.type() == "kdeconnect.identity") {
|
||||
|
||||
qDebug() << "AvahiAnnouncer creating link to device" << id;
|
||||
QString id = np.get<QString>("deviceId");
|
||||
QString name = np.get<QString>("deviceName");
|
||||
|
||||
DeviceLink* dl = new UdpDeviceLink(id, this, sender, 10600);
|
||||
links.append(dl);
|
||||
qDebug() << "AvahiAnnouncer creating link to device" << id;
|
||||
|
||||
emit onNewDeviceLink(id, name, dl);
|
||||
DeviceLink* dl = new UdpDeviceLink(id, this, sender, 10600);
|
||||
links.append(dl);
|
||||
|
||||
emit onNewDeviceLink(id, name, dl);
|
||||
} else {
|
||||
qDebug() << "Not an identification package (wuh?)";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
61
daemon/default_args.h
Normal file
61
daemon/default_args.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* Copyright 2013 Albert Vaca <albertvaka@gmail.com>
|
||||
*
|
||||
* This program 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 2 of
|
||||
* the License or (at your option) version 3 or any later version
|
||||
* accepted by the membership of KDE e.V. (or its successor approved
|
||||
* by the membership of KDE e.V.), which shall act as a proxy
|
||||
* defined in Section 14 of version 3 of the license.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DEFAULTARG_H
|
||||
#define DEFAULTARG_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
template<class T>
|
||||
struct default_arg {
|
||||
static T get(); //Not defined for any other value
|
||||
};
|
||||
|
||||
//bool -> false
|
||||
template<>
|
||||
struct default_arg<bool> {
|
||||
static bool get() { return false; }
|
||||
};
|
||||
|
||||
//int -> -1
|
||||
template<>
|
||||
struct default_arg<int> {
|
||||
static int get() { return -1; }
|
||||
};
|
||||
|
||||
//Pointer types -> NULL (partial specialization)
|
||||
/*template<class T*>
|
||||
struct default_arg<T*> {
|
||||
static T* get() { NULL; }
|
||||
};
|
||||
*/
|
||||
//QStrings -> empty string
|
||||
template<>
|
||||
struct default_arg<QString> {
|
||||
static QString get() { return QString(); }
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct default_arg<T*> {
|
||||
static T* get() { return NULL;}
|
||||
};
|
||||
|
||||
|
||||
#endif // DEFAULTARG_H
|
|
@ -78,15 +78,16 @@ void Device::removeLink(DeviceLink* link)
|
|||
m_deviceLinks.remove(m_deviceLinks.indexOf(link));
|
||||
}
|
||||
|
||||
void Device::sendPackage(const NetworkPackage& np)
|
||||
bool Device::sendPackage(const NetworkPackage& np)
|
||||
{
|
||||
m_deviceLinks.first()->sendPackage(np);
|
||||
if (m_deviceLinks.empty()) return false;
|
||||
return m_deviceLinks.first()->sendPackage(np);
|
||||
}
|
||||
|
||||
void Device::privateReceivedPackage(const NetworkPackage& np)
|
||||
{
|
||||
if (np.type() == "IDENTITY" && !m_knownIdentiy) {
|
||||
m_deviceName = np.body();
|
||||
if (np.type() == "kdeconnect.identity" && !m_knownIdentiy) {
|
||||
m_deviceName = np.get<QString>("deviceName");
|
||||
} else if (m_paired) {
|
||||
qDebug() << "package received from paired device";
|
||||
emit receivedPackage(np);
|
||||
|
@ -97,10 +98,9 @@ void Device::privateReceivedPackage(const NetworkPackage& np)
|
|||
|
||||
void Device::sendPing()
|
||||
{
|
||||
qDebug() << "sendPing";
|
||||
NetworkPackage np;
|
||||
np.setType("PING");
|
||||
sendPackage(np);
|
||||
NetworkPackage np("kdeconnect.ping");
|
||||
bool success = sendPackage(np);
|
||||
qDebug() << "sendPing:" << success;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
void addLink(DeviceLink*);
|
||||
void removeLink(DeviceLink*);
|
||||
|
||||
void sendPackage(const NetworkPackage& np);
|
||||
bool sendPackage(const NetworkPackage& np);
|
||||
|
||||
Q_SIGNALS:
|
||||
void receivedPackage(const NetworkPackage& np);
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
const QString& deviceId() { return mDeviceId; }
|
||||
Announcer* announcer() { return mAnnouncer; }
|
||||
|
||||
virtual void sendPackage(const NetworkPackage& np) = 0;
|
||||
virtual bool sendPackage(const NetworkPackage& np) = 0;
|
||||
|
||||
signals:
|
||||
void receivedPackage(const NetworkPackage& np);
|
||||
|
|
|
@ -30,8 +30,9 @@ class EchoDeviceLink : public DeviceLink
|
|||
public:
|
||||
EchoDeviceLink(const QString& d, FakeAnnouncer* a);
|
||||
|
||||
void sendPackage(const NetworkPackage& np) {
|
||||
bool sendPackage(const NetworkPackage& np) {
|
||||
emit receivedPackage(np);
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -28,9 +28,9 @@ UdpDeviceLink::UdpDeviceLink(const QString& d, AvahiAnnouncer* a, QHostAddress i
|
|||
mIp = ip;
|
||||
mPort = port;
|
||||
|
||||
mUdpSocket = new QUdpSocket();
|
||||
mUdpSocket->bind(port);
|
||||
connect(mUdpSocket, SIGNAL(readyRead()), this, SLOT(readPendingNotifications()));
|
||||
mSocket = new QUdpSocket();
|
||||
mSocket->bind(port);
|
||||
connect(mSocket, SIGNAL(readyRead()), this, SLOT(readPendingNotifications()));
|
||||
|
||||
}
|
||||
|
||||
|
@ -39,18 +39,19 @@ void UdpDeviceLink::readPendingNotifications()
|
|||
|
||||
qDebug() << "UdpDeviceLink readPendingNotifications";
|
||||
|
||||
while (mUdpSocket->hasPendingDatagrams()) {
|
||||
while (mSocket->hasPendingDatagrams()) {
|
||||
|
||||
QByteArray datagram;
|
||||
datagram.resize(mUdpSocket->pendingDatagramSize());
|
||||
datagram.resize(mSocket->pendingDatagramSize());
|
||||
QHostAddress sender;
|
||||
quint16 senderPort;
|
||||
mUdpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
|
||||
mSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
|
||||
|
||||
//log.write(datagram);
|
||||
qDebug() << datagram;
|
||||
|
||||
NetworkPackage np = NetworkPackage::fromString(datagram);
|
||||
NetworkPackage np;
|
||||
NetworkPackage::unserialize(datagram,&np);
|
||||
|
||||
emit receivedPackage(np);
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "devicelink.h"
|
||||
#include <qudpsocket.h>
|
||||
#include <qtcpsocket.h>
|
||||
|
||||
class AvahiAnnouncer;
|
||||
|
||||
|
@ -36,15 +37,16 @@ class UdpDeviceLink : public DeviceLink
|
|||
public:
|
||||
UdpDeviceLink(const QString& d, AvahiAnnouncer* a, QHostAddress ip, quint16 port);
|
||||
|
||||
void sendPackage(const NetworkPackage& np) {
|
||||
mUdpSocket->writeDatagram(np.toString(), mIp, mPort);
|
||||
bool sendPackage(const NetworkPackage& np) {
|
||||
mSocket->writeDatagram(np.serialize(),mIp,mPort);
|
||||
return true;
|
||||
}
|
||||
|
||||
private Q_SLOTS:
|
||||
void readPendingNotifications();
|
||||
|
||||
private:
|
||||
QUdpSocket* mUdpSocket;
|
||||
QUdpSocket* mSocket;
|
||||
|
||||
QHostAddress mIp;
|
||||
quint16 mPort;
|
||||
|
|
|
@ -24,64 +24,47 @@
|
|||
#include <QDebug>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <qjson/serializer.h>
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
#include <qjson/qobjecthelper.h>
|
||||
|
||||
|
||||
static QString decodeNextString(std::stringstream& ss) {
|
||||
int length;
|
||||
ss >> length;
|
||||
char c[length];
|
||||
ss.get(); //Skip ws
|
||||
ss.read(c,length);
|
||||
return QString::fromAscii(c,length);
|
||||
}
|
||||
|
||||
NetworkPackage NetworkPackage::fromString(QByteArray s)
|
||||
NetworkPackage::NetworkPackage(QString type)
|
||||
{
|
||||
//FIXME: Find a better way of serialization
|
||||
std::string stds(std::string(s.data()));
|
||||
std::cout << stds << std::endl;
|
||||
|
||||
std::stringstream ss(stds);
|
||||
|
||||
NetworkPackage pp;
|
||||
|
||||
long id;
|
||||
ss >> id;
|
||||
pp.mId = id;
|
||||
|
||||
//qDebug() << "Decoding package with id:" << id;
|
||||
|
||||
pp.mDeviceId = decodeNextString(ss);
|
||||
|
||||
ss >> pp.mTime;
|
||||
|
||||
std::string type;
|
||||
ss >> type;
|
||||
pp.mType = QString::fromStdString(type);
|
||||
|
||||
pp.mBody = decodeNextString(ss);
|
||||
|
||||
ss >> pp.mIsCancel;
|
||||
|
||||
qDebug() << "Decoded package with id:" << id;
|
||||
|
||||
return pp;
|
||||
|
||||
mId = time(NULL);
|
||||
mType = type;
|
||||
}
|
||||
|
||||
|
||||
QByteArray NetworkPackage::toString() const
|
||||
QByteArray NetworkPackage::serialize() const
|
||||
{
|
||||
//Object -> QVariant
|
||||
//QVariantMap variant;
|
||||
//variant["id"] = mId;
|
||||
//variant["type"] = mType;
|
||||
//variant["body"] = mBody;
|
||||
QVariantMap variant = QJson::QObjectHelper::qobject2qvariant(this);
|
||||
|
||||
QByteArray s;
|
||||
|
||||
//TODO
|
||||
s += "HOLA";
|
||||
|
||||
return s;
|
||||
//QVariant -> json
|
||||
bool ok;
|
||||
QJson::Serializer serializer;
|
||||
QByteArray json = serializer.serialize(variant,&ok);
|
||||
if (!ok) qDebug() << "D'oh!";
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
void NetworkPackage::unserialize(QByteArray a, NetworkPackage* np)
|
||||
{
|
||||
//Json -> QVariant
|
||||
QJson::Parser parser;
|
||||
QVariantMap variant = parser.parse(a).toMap();
|
||||
|
||||
//QVariant -> Object
|
||||
//NetworkPackage np;
|
||||
//QJSon json(a);
|
||||
//np.mId = json["id"];
|
||||
//np.mType = json["type"];
|
||||
//np.mBody = json["body"];
|
||||
QJson::QObjectHelper::qvariant2qobject(variant,np);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,44 +21,51 @@
|
|||
#ifndef NETWORKPACKAGE_H
|
||||
#define NETWORKPACKAGE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <qjson/parser.h>
|
||||
#include "default_args.h"
|
||||
|
||||
class NetworkPackage
|
||||
class NetworkPackage : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( long id READ id WRITE setId )
|
||||
Q_PROPERTY( QString type READ type WRITE setType )
|
||||
Q_PROPERTY( QVariantMap body READ body WRITE setBody )
|
||||
Q_PROPERTY( int version READ version WRITE setVersion )
|
||||
|
||||
public:
|
||||
|
||||
NetworkPackage() {
|
||||
mId = 3;
|
||||
//TODO
|
||||
}
|
||||
NetworkPackage() {};
|
||||
NetworkPackage(QString type);
|
||||
|
||||
static NetworkPackage fromString(QByteArray);
|
||||
QByteArray toString() const;
|
||||
static void unserialize(QByteArray, NetworkPackage*);
|
||||
QByteArray serialize() const;
|
||||
|
||||
long id() const { return mId; }
|
||||
const QString& deviceId() const { return mDeviceId; }
|
||||
const QString& type() const { return mType; }
|
||||
const QString& body() const { return mBody; }
|
||||
bool isCancel() const { return mIsCancel; }
|
||||
QVariantMap& body() { return mBody; }
|
||||
int version() const { return mVersion; }
|
||||
|
||||
void setId(long id) { mId = id; }
|
||||
void setDeviceId(const QString& id) { mDeviceId = id; }
|
||||
void setType(const QString& t) { mType = t; }
|
||||
void setBody(const QString& b) { mBody = b; }
|
||||
void setCancel(bool b) { mIsCancel = b; }
|
||||
//Get and set info from body. Note that id, type and version can not be accessed through these.
|
||||
template<typename T> T get(const QString& property, const T& defaultValue = default_arg<T>::get()) const {
|
||||
return mBody.value(property,defaultValue).template value<T>(); //Important note: Awesome template syntax is awesome
|
||||
}
|
||||
template<typename T> void set(const QString& property, const T& value) const { return mBody[property].setValue(value); }
|
||||
|
||||
private:
|
||||
void setId(long id) { mId = id; }
|
||||
void setType(const QString& t) { mType = t; }
|
||||
void setBody(const QVariantMap& b) { mBody = b; }
|
||||
void setVersion(int v) { mVersion = v; }
|
||||
|
||||
long mId;
|
||||
long mTime;
|
||||
QString mDeviceId;
|
||||
QString mType;
|
||||
QString mBody;
|
||||
QVariant mExtra;
|
||||
bool mIsCancel;
|
||||
QVariantMap mBody; //json in the Android side
|
||||
int mVersion;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // NETWORKPACKAGE_H
|
||||
|
|
|
@ -64,7 +64,7 @@ KNotification* NotificationPackageReceiver::createNotification(const NetworkPack
|
|||
notification->setPixmap(KIcon(icon).pixmap(48, 48));
|
||||
notification->setComponentData(KComponentData("kdeconnect", "kdeconnect"));
|
||||
notification->setTitle(title);
|
||||
notification->setText(np.body());
|
||||
notification->setText(np.get<QString>(QString("content")));
|
||||
|
||||
return notification;
|
||||
|
||||
|
@ -72,19 +72,18 @@ KNotification* NotificationPackageReceiver::createNotification(const NetworkPack
|
|||
|
||||
bool NotificationPackageReceiver::receivePackage(const NetworkPackage& np) {
|
||||
|
||||
if (np.isCancel()) {
|
||||
//if (np.get("isCancel")) {
|
||||
|
||||
//It would be awesome to remove the old notification from the system tray here, but there is no way to do it :(
|
||||
//Now I realize why at the end of the day I have hundreds of notifications from facebook messages that I HAVE ALREADY READ,
|
||||
//...it's just because the telepathy client has no way to remove them! even when it knows that I have read those messages lol
|
||||
//Here we have our awesome KDE notifications system, unusable and meant to fuck the user.
|
||||
|
||||
} else {
|
||||
//} else {
|
||||
|
||||
KNotification* n = createNotification(np);
|
||||
n->sendEvent();
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
return true;
|
||||
|
||||
|
|
|
@ -30,11 +30,11 @@ PauseMusicPackageReceiver::PauseMusicPackageReceiver()
|
|||
bool PauseMusicPackageReceiver::receivePackage ( const NetworkPackage& np )
|
||||
{
|
||||
|
||||
if (np.type() != "RINGING") return false; //TODO: Consider pauseOnlyAfterAnswering
|
||||
if (np.get<QString>("eventType","") != "ring") return false; //TODO: Consider pauseOnlyAfterAnswering
|
||||
|
||||
//TODO: Use KDE DBUS API
|
||||
if (np.isCancel()) {
|
||||
system("qdbus org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.PlayPause");
|
||||
if (np.get<QString>("eventDetails") == "hang") {
|
||||
system("qdbus org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Play");
|
||||
} else {
|
||||
system("qdbus org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Pause");
|
||||
}
|
||||
|
|
|
@ -50,8 +50,10 @@ public:
|
|||
|
||||
DeviceDbusInterface* getDevice(const QModelIndex& index);
|
||||
|
||||
private Q_SLOTS:
|
||||
public Q_SLOTS:
|
||||
void deviceStatusChanged(const QString& id);
|
||||
|
||||
private Q_SLOTS:
|
||||
void deviceAdded(const QString& id);
|
||||
|
||||
private:
|
||||
|
|
|
@ -75,7 +75,9 @@ void KdeConnectKcm::deviceSelected(const QModelIndex& current)
|
|||
void KdeConnectKcm::trustedStateChanged(bool b)
|
||||
{
|
||||
if (!selectedIndex.isValid()) return;
|
||||
pairedDevicesList->getDevice(selectedIndex)->setPair(b);
|
||||
DeviceDbusInterface* device = pairedDevicesList->getDevice(selectedIndex);
|
||||
device->setPair(b);
|
||||
pairedDevicesList->deviceStatusChanged(device->id());
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue