New networkpackage format and serialization using qjson and qvariantmap (and templates fun)

This commit is contained in:
Albert Vaca 2013-07-04 01:09:49 +02:00
parent 975892dcd0
commit b1e4e2d836
15 changed files with 171 additions and 107 deletions

View file

@ -26,6 +26,7 @@ target_link_libraries(kded_kdeconnect
${KDE4_KDECORE_LIBS}
${KDE4_KDEUI_LIBS}
kdnssd
qjson
${QT_QTNETWORK_LIBRARY}
${QJSON_LIBRARIES}
${QJSON_LIBRARY}

View file

@ -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
View 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

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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;
}
};

View file

@ -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);

View file

@ -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;

View file

@ -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);
}

View file

@ -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

View file

@ -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;

View file

@ -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");
}

View file

@ -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:

View file

@ -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());
}