From 6ae8e3d78b5c4a75ca7d5ca88af730071047d148 Mon Sep 17 00:00:00 2001 From: Roman Plášil Date: Wed, 16 Aug 2017 13:56:13 +0800 Subject: Implement saving save to enable incremental sync even after shutdown --- jobs/syncjob.cpp | 32 ++++++++++++++------------------ jobs/syncjob.h | 19 ++++++++++++++----- 2 files changed, 28 insertions(+), 23 deletions(-) (limited to 'jobs') diff --git a/jobs/syncjob.cpp b/jobs/syncjob.cpp index 29ddc2e6..3adf6b0c 100644 --- a/jobs/syncjob.cpp +++ b/jobs/syncjob.cpp @@ -22,20 +22,13 @@ using namespace QMatrixClient; -class SyncJob::Private -{ - public: - QString nextBatch; - SyncData roomData; -}; - static size_t jobId = 0; SyncJob::SyncJob(const ConnectionData* connection, const QString& since, const QString& filter, int timeout, const QString& presence) : BaseJob(connection, HttpVerb::Get, QString("SyncJob-%1").arg(++jobId), "_matrix/client/r0/sync") - , d(new Private) + , d(new SyncData) { setLoggingCategory(SYNCJOB); QUrlQuery query; @@ -57,21 +50,26 @@ SyncJob::~SyncJob() delete d; } -QString SyncJob::nextBatch() const +QString SyncData::nextBatch() const { - return d->nextBatch; + return nextBatch_; } -SyncData&& SyncJob::takeRoomData() +SyncDataList&& SyncData::takeRoomData() { - return std::move(d->roomData); + return std::move(roomData); } BaseJob::Status SyncJob::parseJson(const QJsonDocument& data) { + d->parseJson(data); + return Success; +} + +void SyncData::parseJson(const QJsonDocument &data) { QElapsedTimer et; et.start(); QJsonObject json = data.object(); - d->nextBatch = json.value("next_batch").toString(); + nextBatch_ = json.value("next_batch").toString(); // TODO: presence // TODO: account_data QJsonObject rooms = json.value("rooms").toObject(); @@ -86,13 +84,11 @@ BaseJob::Status SyncJob::parseJson(const QJsonDocument& data) { const QJsonObject rs = rooms.value(roomState.jsonKey).toObject(); // We have a Qt container on the right and an STL one on the left - d->roomData.reserve(static_cast(rs.size())); + roomData.reserve(static_cast(rs.size())); for( auto rkey: rs.keys() ) - d->roomData.emplace_back(rkey, roomState.enumVal, rs[rkey].toObject()); + roomData.emplace_back(rkey, roomState.enumVal, rs[rkey].toObject()); } - qCDebug(PROFILER) << "*** SyncJob::parseJson():" << et.elapsed() << "ms"; - - return Success; + qCDebug(PROFILER) << "*** SyncData::parseJson():" << et.elapsed() << "ms"; } SyncRoomData::SyncRoomData(const QString& roomId_, JoinState joinState_, diff --git a/jobs/syncjob.h b/jobs/syncjob.h index 07824e23..9dc221b5 100644 --- a/jobs/syncjob.h +++ b/jobs/syncjob.h @@ -67,7 +67,18 @@ Q_DECLARE_TYPEINFO(QMatrixClient::SyncRoomData, Q_MOVABLE_TYPE); namespace QMatrixClient { // QVector cannot work with non-copiable objects, std::vector can. - using SyncData = std::vector; + using SyncDataList = std::vector; + + class SyncData { + public: + void parseJson(const QJsonDocument &data); + SyncDataList&& takeRoomData(); + QString nextBatch() const; + + private: + QString nextBatch_; + SyncDataList roomData; + }; class SyncJob: public BaseJob { @@ -77,14 +88,12 @@ namespace QMatrixClient int timeout = -1, const QString& presence = {}); virtual ~SyncJob(); - SyncData&& takeRoomData(); - QString nextBatch() const; + SyncData *data() const { return d; } protected: Status parseJson(const QJsonDocument& data) override; private: - class Private; - Private* d; + SyncData* d; }; } // namespace QMatrixClient -- cgit v1.2.3 From 9a26c52f8c3e71f803fd38128ecddfd6ce9748f6 Mon Sep 17 00:00:00 2001 From: Roman Plášil Date: Sat, 2 Sep 2017 00:58:58 +0800 Subject: Use status return type for parseJson --- connection.cpp | 7 +++---- jobs/syncjob.cpp | 3 ++- jobs/syncjob.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'jobs') diff --git a/connection.cpp b/connection.cpp index 97594e7d..fe0cb251 100644 --- a/connection.cpp +++ b/connection.cpp @@ -32,10 +32,9 @@ #include "jobs/mediathumbnailjob.h" #include -#include -#include -#include -#include +#include +#include +#include using namespace QMatrixClient; diff --git a/jobs/syncjob.cpp b/jobs/syncjob.cpp index 3adf6b0c..1e71e215 100644 --- a/jobs/syncjob.cpp +++ b/jobs/syncjob.cpp @@ -66,7 +66,7 @@ BaseJob::Status SyncJob::parseJson(const QJsonDocument& data) return Success; } -void SyncData::parseJson(const QJsonDocument &data) { +BaseJob::Status SyncData::parseJson(const QJsonDocument &data) { QElapsedTimer et; et.start(); QJsonObject json = data.object(); nextBatch_ = json.value("next_batch").toString(); @@ -89,6 +89,7 @@ void SyncData::parseJson(const QJsonDocument &data) { roomData.emplace_back(rkey, roomState.enumVal, rs[rkey].toObject()); } qCDebug(PROFILER) << "*** SyncData::parseJson():" << et.elapsed() << "ms"; + return Success; } SyncRoomData::SyncRoomData(const QString& roomId_, JoinState joinState_, diff --git a/jobs/syncjob.h b/jobs/syncjob.h index 9dc221b5..16ac5895 100644 --- a/jobs/syncjob.h +++ b/jobs/syncjob.h @@ -71,7 +71,7 @@ namespace QMatrixClient class SyncData { public: - void parseJson(const QJsonDocument &data); + BaseJob::Status parseJson(const QJsonDocument &data); SyncDataList&& takeRoomData(); QString nextBatch() const; -- cgit v1.2.3 From a7ee0dfacc2c571572240191b3cf0846a9e32998 Mon Sep 17 00:00:00 2001 From: Roman Plášil Date: Sun, 3 Sep 2017 14:43:05 +0800 Subject: More fixes --- connection.cpp | 3 +-- jobs/syncjob.cpp | 5 ++--- room.cpp | 17 ++++++++++------- room.h | 2 +- 4 files changed, 14 insertions(+), 13 deletions(-) (limited to 'jobs') diff --git a/connection.cpp b/connection.cpp index fe0cb251..d2acf928 100644 --- a/connection.cpp +++ b/connection.cpp @@ -333,8 +333,7 @@ void Connection::saveState(const QUrl &toFile) { QJsonObject rooms; for (auto i : this->roomMap()) { - QJsonObject roomObj; - i->toJson(roomObj); + QJsonObject roomObj = i->toJson(); rooms[i->id()] = roomObj; } diff --git a/jobs/syncjob.cpp b/jobs/syncjob.cpp index 1e71e215..bbec968e 100644 --- a/jobs/syncjob.cpp +++ b/jobs/syncjob.cpp @@ -62,8 +62,7 @@ SyncDataList&& SyncData::takeRoomData() BaseJob::Status SyncJob::parseJson(const QJsonDocument& data) { - d->parseJson(data); - return Success; + return d->parseJson(data); } BaseJob::Status SyncData::parseJson(const QJsonDocument &data) { @@ -89,7 +88,7 @@ BaseJob::Status SyncData::parseJson(const QJsonDocument &data) { roomData.emplace_back(rkey, roomState.enumVal, rs[rkey].toObject()); } qCDebug(PROFILER) << "*** SyncData::parseJson():" << et.elapsed() << "ms"; - return Success; + return BaseJob::Success; } SyncRoomData::SyncRoomData(const QString& roomId_, JoinState joinState_, diff --git a/room.cpp b/room.cpp index 3841eab8..212c8acd 100644 --- a/room.cpp +++ b/room.cpp @@ -119,7 +119,7 @@ class Room::Private void setLastReadEvent(User* u, const QString& eventId); rev_iter_pair_t promoteReadMarker(User* u, rev_iter_t newMarker); - void toJson(QJsonObject &out); + QJsonObject toJson() const; private: QString calculateDisplayname() const; @@ -877,7 +877,7 @@ void Room::Private::updateDisplayname() emit q->displaynameChanged(q); } -void Room::Private::toJson(QJsonObject &out) { +QJsonObject Room::Private::toJson() const { QJsonValue nowTimestamp { QDateTime::currentMSecsSinceEpoch() }; QJsonArray stateEvents; @@ -890,7 +890,7 @@ void Room::Private::toJson(QJsonObject &out) { nameEvent.insert("content", nameEventContent); stateEvents.append(nameEvent); - for (auto i : this->membersMap) { + for (const auto &i : this->membersMap) { QJsonObject content; content.insert("membership", QStringLiteral("join")); content.insert("displayname", i->displayname()); @@ -908,7 +908,7 @@ void Room::Private::toJson(QJsonObject &out) { { QJsonArray aliases; - for (auto i : this->aliases) { + for (const auto &i : this->aliases) { aliases.append(QJsonValue(i)); } @@ -935,11 +935,14 @@ void Room::Private::toJson(QJsonObject &out) { QJsonObject roomStateObj; roomStateObj.insert("events", stateEvents); - out.insert("state", roomStateObj); + + QJsonObject result; + result.insert("state", roomStateObj); + return result; } -void Room::toJson(QJsonObject &out) const { - d->toJson(out); +QJsonObject Room::toJson() const { + return d->toJson(); } MemberSorter Room::memberSorter() const diff --git a/room.h b/room.h index 9e363556..12de0f31 100644 --- a/room.h +++ b/room.h @@ -142,7 +142,7 @@ namespace QMatrixClient MemberSorter memberSorter() const; - void toJson(QJsonObject &out) const; + QJsonObject toJson() const; public slots: void postMessage(const QString& plainText, -- cgit v1.2.3 From 56d34ecab5eb35c426a6e64b034bf2507761dd09 Mon Sep 17 00:00:00 2001 From: Roman Plášil Date: Mon, 4 Sep 2017 10:35:45 +0800 Subject: Use SyncJob::SyncData as a plain member --- connection.cpp | 2 +- jobs/syncjob.cpp | 8 +------- jobs/syncjob.h | 5 ++--- 3 files changed, 4 insertions(+), 11 deletions(-) (limited to 'jobs') diff --git a/connection.cpp b/connection.cpp index d2acf928..9fc2f85b 100644 --- a/connection.cpp +++ b/connection.cpp @@ -160,7 +160,7 @@ void Connection::sync(int timeout) auto job = d->syncJob = callApi(d->data->lastEvent(), filter, timeout); connect( job, &SyncJob::success, [=] () { - onSyncSuccess(*job->data()); + onSyncSuccess(job->data()); d->syncJob = nullptr; emit syncDone(); }); diff --git a/jobs/syncjob.cpp b/jobs/syncjob.cpp index bbec968e..062f1b15 100644 --- a/jobs/syncjob.cpp +++ b/jobs/syncjob.cpp @@ -28,7 +28,6 @@ SyncJob::SyncJob(const ConnectionData* connection, const QString& since, const QString& filter, int timeout, const QString& presence) : BaseJob(connection, HttpVerb::Get, QString("SyncJob-%1").arg(++jobId), "_matrix/client/r0/sync") - , d(new SyncData) { setLoggingCategory(SYNCJOB); QUrlQuery query; @@ -45,11 +44,6 @@ SyncJob::SyncJob(const ConnectionData* connection, const QString& since, setMaxRetries(std::numeric_limits::max()); } -SyncJob::~SyncJob() -{ - delete d; -} - QString SyncData::nextBatch() const { return nextBatch_; @@ -62,7 +56,7 @@ SyncDataList&& SyncData::takeRoomData() BaseJob::Status SyncJob::parseJson(const QJsonDocument& data) { - return d->parseJson(data); + return d.parseJson(data); } BaseJob::Status SyncData::parseJson(const QJsonDocument &data) { diff --git a/jobs/syncjob.h b/jobs/syncjob.h index 16ac5895..80cc6735 100644 --- a/jobs/syncjob.h +++ b/jobs/syncjob.h @@ -86,14 +86,13 @@ namespace QMatrixClient explicit SyncJob(const ConnectionData* connection, const QString& since = {}, const QString& filter = {}, int timeout = -1, const QString& presence = {}); - virtual ~SyncJob(); - SyncData *data() const { return d; } + SyncData &data() { return d; } protected: Status parseJson(const QJsonDocument& data) override; private: - SyncData* d; + SyncData d; }; } // namespace QMatrixClient -- cgit v1.2.3 From 071856d31995f665ee9219b3e05510ab83f9f4d8 Mon Sep 17 00:00:00 2001 From: Roman Plášil Date: Mon, 4 Sep 2017 19:23:50 +0800 Subject: Use move on SyncData --- connection.cpp | 9 ++++----- connection.h | 2 +- jobs/syncjob.h | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) (limited to 'jobs') diff --git a/connection.cpp b/connection.cpp index 9fc2f85b..27f0a86f 100644 --- a/connection.cpp +++ b/connection.cpp @@ -160,7 +160,7 @@ void Connection::sync(int timeout) auto job = d->syncJob = callApi(d->data->lastEvent(), filter, timeout); connect( job, &SyncJob::success, [=] () { - onSyncSuccess(job->data()); + onSyncSuccess(job->takeData()); d->syncJob = nullptr; emit syncDone(); }); @@ -174,7 +174,7 @@ void Connection::sync(int timeout) }); } -void Connection::onSyncSuccess(SyncData &data) { +void Connection::onSyncSuccess(SyncData &&data) { d->data->setLastEvent(data.nextBatch()); for( auto&& roomData: data.takeRoomData() ) { @@ -333,8 +333,7 @@ void Connection::saveState(const QUrl &toFile) { QJsonObject rooms; for (auto i : this->roomMap()) { - QJsonObject roomObj = i->toJson(); - rooms[i->id()] = roomObj; + rooms[i->id()] = i->toJson(); } QJsonObject roomObj; @@ -372,5 +371,5 @@ void Connection::loadState(const QUrl &fromFile) { QJsonDocument doc { QJsonDocument::fromJson(data) }; SyncData sync; sync.parseJson(doc); - onSyncSuccess(sync); + onSyncSuccess(std::move(sync)); } diff --git a/connection.h b/connection.h index 0265d92f..ad161d7c 100644 --- a/connection.h +++ b/connection.h @@ -151,7 +151,7 @@ namespace QMatrixClient /** * Completes loading sync data. */ - void onSyncSuccess(SyncData &data); + void onSyncSuccess(SyncData &&data); private: class Private; diff --git a/jobs/syncjob.h b/jobs/syncjob.h index 80cc6735..2ded0df3 100644 --- a/jobs/syncjob.h +++ b/jobs/syncjob.h @@ -87,7 +87,7 @@ namespace QMatrixClient const QString& filter = {}, int timeout = -1, const QString& presence = {}); - SyncData &data() { return d; } + SyncData &&takeData() { return std::move(d); } protected: Status parseJson(const QJsonDocument& data) override; -- cgit v1.2.3 From da975f68f6a8503bf5466292dcdceed8c6f7fa6f Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Tue, 5 Sep 2017 19:23:13 +0900 Subject: Initialize more properly to fix a warning --- jobs/basejob.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'jobs') diff --git a/jobs/basejob.cpp b/jobs/basejob.cpp index 26ceb268..157ac034 100644 --- a/jobs/basejob.cpp +++ b/jobs/basejob.cpp @@ -263,13 +263,13 @@ void BaseJob::finishJob() BaseJob::duration_t BaseJob::getCurrentTimeout() const { - static const std::array timeouts = { 90, 90, 120, 120 }; + static const std::array timeouts ({ 90, 90, 120, 120 }); return timeouts[std::min(d->retriesTaken, timeouts.size() - 1)] * 1000; } BaseJob::duration_t BaseJob::getNextRetryInterval() const { - static const std::array intervals = { 5, 10, 30 }; + static const std::array intervals ({ 5, 10, 30 }); return intervals[std::min(d->retriesTaken, intervals.size() - 1)] * 1000; } -- cgit v1.2.3 From 180d62e094a1a6b6fc69c99b291ef075dc649135 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 8 Sep 2017 16:51:03 +0900 Subject: Revert previous commit as it breaks building with VC 2015 This reverts commit da975f68f6a8503bf5466292dcdceed8c6f7fa6f. --- jobs/basejob.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'jobs') diff --git a/jobs/basejob.cpp b/jobs/basejob.cpp index 157ac034..26ceb268 100644 --- a/jobs/basejob.cpp +++ b/jobs/basejob.cpp @@ -263,13 +263,13 @@ void BaseJob::finishJob() BaseJob::duration_t BaseJob::getCurrentTimeout() const { - static const std::array timeouts ({ 90, 90, 120, 120 }); + static const std::array timeouts = { 90, 90, 120, 120 }; return timeouts[std::min(d->retriesTaken, timeouts.size() - 1)] * 1000; } BaseJob::duration_t BaseJob::getNextRetryInterval() const { - static const std::array intervals ({ 5, 10, 30 }); + static const std::array intervals = { 5, 10, 30 }; return intervals[std::min(d->retriesTaken, intervals.size() - 1)] * 1000; } -- cgit v1.2.3 From d57485bb3a7d980642e7f68edd5785c144acc742 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 8 Sep 2017 18:36:44 +0900 Subject: converters.h: Facility methods for generated jobs A cherry-pick from the kitsune-apigen branch; a family of toJson() and fromJson<>() functions to unify conversion of data back and forth. --- jobs/converters.h | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 jobs/converters.h (limited to 'jobs') diff --git a/jobs/converters.h b/jobs/converters.h new file mode 100644 index 00000000..376dfeab --- /dev/null +++ b/jobs/converters.h @@ -0,0 +1,89 @@ +/****************************************************************************** +* Copyright (C) 2017 Kitsune Ral +* +* 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 +*/ + +#pragma once + +#include +#include +#include + +namespace QMatrixClient +{ + template + inline QJsonValue toJson(T val) + { + return QJsonValue(val); + } + + template + inline QJsonValue toJson(const QVector& vals) + { + QJsonArray ar; + for (const auto& v: vals) + ar.push_back(toJson(v)); + return ar; + } + + inline QJsonValue toJson(const QStringList& strings) + { + return QJsonArray::fromStringList(strings); + } + + template + inline T fromJson(const QJsonValue& jv) + { + return QVariant(jv).value(); + } + + template <> + inline int fromJson(const QJsonValue& jv) + { + return jv.toInt(); + } + + template <> + inline qint64 fromJson(const QJsonValue& jv) + { + return static_cast(jv.toDouble()); + } + + template <> + inline double fromJson(const QJsonValue& jv) + { + return jv.toDouble(); + } + + template <> + inline QString fromJson(const QJsonValue& jv) + { + return jv.toString(); + } + + template <> + inline QDateTime fromJson(const QJsonValue& jv) + { + return QDateTime::fromMSecsSinceEpoch(fromJson(jv), Qt::UTC); + } + + template <> + inline QDate fromJson(const QJsonValue& jv) + { + return QDateTime::fromMSecsSinceEpoch( + fromJson(jv), Qt::UTC).date(); + } +} // namespace QMatrixClient \ No newline at end of file -- cgit v1.2.3 From 8ae1da50f8474a698ce83f61233b3a8975faeaee Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Sat, 9 Sep 2017 20:14:08 +0900 Subject: First files made by api-generator Actual usage will come with the next commit. --- jobs/generated/inviting.cpp | 37 +++++++++++++++++++++++++++++++++++++ jobs/generated/inviting.h | 42 ++++++++++++++++++++++++++++++++++++++++++ jobs/generated/kicking.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ jobs/generated/kicking.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 165 insertions(+) create mode 100644 jobs/generated/inviting.cpp create mode 100644 jobs/generated/inviting.h create mode 100644 jobs/generated/kicking.cpp create mode 100644 jobs/generated/kicking.h (limited to 'jobs') diff --git a/jobs/generated/inviting.cpp b/jobs/generated/inviting.cpp new file mode 100644 index 00000000..e5e7f410 --- /dev/null +++ b/jobs/generated/inviting.cpp @@ -0,0 +1,37 @@ +/****************************************************************************** + * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN + */ + + +#include "inviting.h" + + +#include "../converters.h" + +#include + +using namespace QMatrixClient; + + + +static const auto basePath = QStringLiteral("/_matrix/client/r0"); + + +InviteUserJob::InviteUserJob(const ConnectionData* connection, + QString roomId + , + QString user_id + ) + : BaseJob(connection, HttpVerb::Post, "InviteUserJob" + , basePath % "/rooms/" % roomId % "/invite" + , Query { } + , Data { + { "user_id", toJson(user_id) } + } + + ) +{ } + + + + diff --git a/jobs/generated/inviting.h b/jobs/generated/inviting.h new file mode 100644 index 00000000..af5a426d --- /dev/null +++ b/jobs/generated/inviting.h @@ -0,0 +1,42 @@ +/****************************************************************************** + * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN + */ + + +#pragma once + + +#include "../basejob.h" + + + +#include + + + + +namespace QMatrixClient +{ + + + // Operations + + /** + + */ + class InviteUserJob : public BaseJob + { + public: + InviteUserJob(const ConnectionData* connection + + , + QString roomId + + , + QString user_id + ); + + }; + + +} // namespace QMatrixClient diff --git a/jobs/generated/kicking.cpp b/jobs/generated/kicking.cpp new file mode 100644 index 00000000..726f6fb0 --- /dev/null +++ b/jobs/generated/kicking.cpp @@ -0,0 +1,41 @@ +/****************************************************************************** + * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN + */ + + +#include "kicking.h" + + +#include "../converters.h" + +#include + +using namespace QMatrixClient; + + + +static const auto basePath = QStringLiteral("/_matrix/client/r0"); + + +KickJob::KickJob(const ConnectionData* connection, + QString roomId + , + QString user_id + , + QString reason + ) + : BaseJob(connection, HttpVerb::Post, "KickJob" + , basePath % "/rooms/" % roomId % "/kick" + , Query { } + , Data { + { "user_id", toJson(user_id) }, + + { "reason", toJson(reason) } + } + + ) +{ } + + + + diff --git a/jobs/generated/kicking.h b/jobs/generated/kicking.h new file mode 100644 index 00000000..7b183b08 --- /dev/null +++ b/jobs/generated/kicking.h @@ -0,0 +1,45 @@ +/****************************************************************************** + * THIS FILE IS GENERATED - ANY EDITS WILL BE OVERWRITTEN + */ + + +#pragma once + + +#include "../basejob.h" + + + +#include + + + + +namespace QMatrixClient +{ + + + // Operations + + /** + + */ + class KickJob : public BaseJob + { + public: + KickJob(const ConnectionData* connection + + , + QString roomId + + , + QString user_id + + , + QString reason + ); + + }; + + +} // namespace QMatrixClient -- cgit v1.2.3 From 24e3d967d7c9029147202e10385b0b8e8881e4d9 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Sat, 9 Sep 2017 20:17:42 +0900 Subject: Kicking, inviting, exposing rooms in Invite state Kicking and inviting use generated job classes. Rooms in Invite state are stored separately in the hash from those in Join/Leave state because The Spec says so. For clients, this means that the same room may appear twice in the rooms map if it's been left and then the user was again invited to it. The code in Quaternion that properly processes this will arrive shortly. --- connection.cpp | 69 ++++++++++++++++++++++++++++++++++---------------------- connection.h | 18 +++++++++++---- jobs/syncjob.cpp | 5 ++-- jobs/syncjob.h | 1 - room.cpp | 23 +++++++++++++++---- room.h | 5 +++- 6 files changed, 80 insertions(+), 41 deletions(-) (limited to 'jobs') diff --git a/connection.cpp b/connection.cpp index 2c9ee88a..5d8a42e3 100644 --- a/connection.cpp +++ b/connection.cpp @@ -50,7 +50,11 @@ class Connection::Private Connection* q; ConnectionData* data; - QHash roomMap; + // A complex key below is a pair of room name and whether its + // state is Invited. The spec mandates to keep Invited room state + // separately so we should, e.g., keep objects for Invite and + // Leave state of the same room. + QHash, Room*> roomMap; QHash userMap; QString username; QString password; @@ -160,7 +164,7 @@ void Connection::sync(int timeout) d->data->setLastEvent(job->nextBatch()); for( auto&& roomData: job->takeRoomData() ) { - if ( auto* r = provideRoom(roomData.roomId) ) + if ( auto* r = provideRoom(roomData.roomId, roomData.joinState) ) r->updateData(std::move(roomData)); } d->syncJob = nullptr; @@ -197,20 +201,12 @@ PostReceiptJob* Connection::postReceipt(Room* room, RoomEvent* event) const JoinRoomJob* Connection::joinRoom(const QString& roomAlias) { - auto job = callApi(roomAlias); - connect( job, &BaseJob::success, [=] () { - if ( Room* r = provideRoom(job->roomId()) ) - emit joinedRoom(r); - }); - return job; + return callApi(roomAlias); } void Connection::leaveRoom(Room* room) { - auto job = callApi(room->id()); - connect( job, &BaseJob::success, [=] () { - emit leftRoom(room); - }); + callApi(room->id()); } RoomMessagesJob* Connection::getMessages(Room* room, const QString& from) const @@ -275,7 +271,7 @@ int Connection::millisToReconnect() const return d->syncJob ? d->syncJob->millisToRetry() : 0; } -QHash< QString, Room* > Connection::roomMap() const +const QHash< QPair, Room* >& Connection::roomMap() const { return d->roomMap; } @@ -285,36 +281,55 @@ const ConnectionData* Connection::connectionData() const return d->data; } -Room* Connection::provideRoom(const QString& id) +Room* Connection::provideRoom(const QString& id, JoinState joinState) { + // TODO: This whole function is a strong case for a RoomManager class. if (id.isEmpty()) { qCDebug(MAIN) << "Connection::provideRoom() with empty id, doing nothing"; return nullptr; } - if (d->roomMap.contains(id)) - return d->roomMap.value(id); - - // Not yet in the map, create a new one. - auto* room = createRoom(this, id); - if (room) + const auto roomKey = qMakePair(id, joinState == JoinState::Invite); + auto* room = d->roomMap.value(roomKey, nullptr); + if (!room) { - d->roomMap.insert( id, room ); + room = createRoom(this, id, joinState); + if (!room) + { + qCritical() << "Failed to create a room!!!" << id; + return nullptr; + } + qCDebug(MAIN) << "Created Room" << id << ", invited:" << roomKey.second; + + d->roomMap.insert(roomKey, room); emit newRoom(room); - } else { - qCritical() << "Failed to create a room!!!" << id; + } + else if (room->joinState() != joinState) + { + room->setJoinState(joinState); + if (joinState == JoinState::Leave) + emit leftRoom(room); + else if (joinState == JoinState::Join) + emit joinedRoom(room); + } + + if (joinState != JoinState::Invite && d->roomMap.contains({id, true})) + { + // Preempt the Invite room after it's been acted upon (joined or left). + qCDebug(MAIN) << "Deleting invited state"; + delete d->roomMap.take({id, true}); } return room; } -std::function Connection::createRoom = - [](Connection* c, const QString& id) { return new Room(c, id); }; +Connection::room_factory_t Connection::createRoom = + [](Connection* c, const QString& id, JoinState joinState) + { return new Room(c, id, joinState); }; -std::function Connection::createUser = +Connection::user_factory_t Connection::createUser = [](Connection* c, const QString& id) { return new User(id, c); }; - QByteArray Connection::generateTxnId() { return d->data->generateTxnId(); diff --git a/connection.h b/connection.h index 4b0413e3..b118ffb0 100644 --- a/connection.h +++ b/connection.h @@ -18,6 +18,8 @@ #pragma once +#include "joinstate.h" + #include #include #include @@ -41,11 +43,16 @@ namespace QMatrixClient class Connection: public QObject { Q_OBJECT public: + using room_factory_t = + std::function; + using user_factory_t = + std::function; + explicit Connection(const QUrl& server, QObject* parent = nullptr); Connection(); virtual ~Connection(); - QHash roomMap() const; + const QHash, Room*>& roomMap() const; Q_INVOKABLE virtual void resolveServer(const QString& domain); Q_INVOKABLE virtual void connectToServer(const QString& user, @@ -102,7 +109,8 @@ namespace QMatrixClient static void setRoomType() { createRoom = - [](Connection* c, const QString& id) { return new T(c, id); }; + [](Connection* c, const QString& id, JoinState joinState) + { return new T(c, id, joinState); }; } template @@ -144,13 +152,13 @@ namespace QMatrixClient * @return a pointer to a Room object with the specified id; nullptr * if roomId is empty if createRoom() failed to create a Room object. */ - Room* provideRoom(const QString& roomId); + Room* provideRoom(const QString& roomId, JoinState joinState); private: class Private; Private* d; - static std::function createRoom; - static std::function createUser; + static room_factory_t createRoom; + static user_factory_t createUser; }; } // namespace QMatrixClient diff --git a/jobs/syncjob.cpp b/jobs/syncjob.cpp index 29ddc2e6..38cfcb2a 100644 --- a/jobs/syncjob.cpp +++ b/jobs/syncjob.cpp @@ -99,15 +99,14 @@ SyncRoomData::SyncRoomData(const QString& roomId_, JoinState joinState_, const QJsonObject& room_) : roomId(roomId_) , joinState(joinState_) - , state("state") + , state(joinState == JoinState::Invite ? "invite_state" : "state") , timeline("timeline") , ephemeral("ephemeral") , accountData("account_data") - , inviteState("invite_state") { switch (joinState) { case JoinState::Invite: - inviteState.fromJson(room_); + state.fromJson(room_); break; case JoinState::Join: state.fromJson(room_); diff --git a/jobs/syncjob.h b/jobs/syncjob.h index 07824e23..57a87c9f 100644 --- a/jobs/syncjob.h +++ b/jobs/syncjob.h @@ -51,7 +51,6 @@ namespace QMatrixClient Batch timeline; Batch ephemeral; Batch accountData; - Batch inviteState; bool timelineLimited; QString timelinePrevBatch; diff --git a/room.cpp b/room.cpp index 547b74c4..78e5b80d 100644 --- a/room.cpp +++ b/room.cpp @@ -18,6 +18,9 @@ #include "room.h" +#include "jobs/generated/kicking.h" +#include "jobs/generated/inviting.h" + #include #include @@ -48,9 +51,9 @@ class Room::Private typedef QMultiHash members_map_t; typedef std::pair rev_iter_pair_t; - Private(Connection* c, QString id_) + Private(Connection* c, QString id_, JoinState initialJoinState) : q(nullptr), connection(c), id(std::move(id_)) - , joinState(JoinState::Join), unreadMessages(false) + , joinState(initialJoinState), unreadMessages(false) , highlightCount(0), notificationCount(0), roomMessagesJob(nullptr) { } @@ -134,8 +137,8 @@ class Room::Private } }; -Room::Room(Connection* connection, QString id) - : QObject(connection), d(new Private(connection, id)) +Room::Room(Connection* connection, QString id, JoinState initialJoinState) + : QObject(connection), d(new Private(connection, id, initialJoinState)) { // See "Accessing the Public Class" section in // https://marcmutz.wordpress.com/translated-articles/pimp-my-pimpl-%E2%80%94-reloaded/ @@ -194,6 +197,8 @@ void Room::setJoinState(JoinState state) if( state == oldState ) return; d->joinState = state; + qCDebug(MAIN) << "Room" << id() << "changed state: " + << int(oldState) << "->" << int(state); emit joinStateChanged(oldState, state); } @@ -601,11 +606,21 @@ void Room::Private::getPreviousContent(int limit) } } +void Room::inviteToRoom(const QString& memberId) const +{ + connection()->callApi(id(), memberId); +} + void Room::leaveRoom() const { connection()->callApi(id()); } +void Room::kickMember(const QString& memberId, const QString& reason) const +{ + connection()->callApi(id(), memberId, reason); +} + void Room::Private::dropDuplicateEvents(RoomEvents* events) const { // Collect all duplicate events at the end of the container diff --git a/room.h b/room.h index 23a1412d..9465a960 100644 --- a/room.h +++ b/room.h @@ -77,7 +77,7 @@ namespace QMatrixClient using Timeline = std::deque; using rev_iter_t = Timeline::const_reverse_iterator; - Room(Connection* connection, QString id); + Room(Connection* connection, QString id, JoinState initialJoinState); virtual ~Room(); Connection* connection() const; @@ -154,7 +154,10 @@ namespace QMatrixClient void getPreviousContent(int limit = 10); + void inviteToRoom(const QString& memberId) const; void leaveRoom() const; + void kickMember(const QString& memberId, const QString& reason) const; + void userRenamed(User* user, QString oldName); /** Mark all messages in the room as read */ -- cgit v1.2.3 From 5ddfbf25f2657f232649a9fdd2ad481127f6c349 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Wed, 13 Sep 2017 21:09:20 +0900 Subject: Add a missing #include --- jobs/converters.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'jobs') diff --git a/jobs/converters.h b/jobs/converters.h index 376dfeab..f9ab0269 100644 --- a/jobs/converters.h +++ b/jobs/converters.h @@ -21,6 +21,7 @@ #include #include #include +#include namespace QMatrixClient { @@ -83,7 +84,6 @@ namespace QMatrixClient template <> inline QDate fromJson(const QJsonValue& jv) { - return QDateTime::fromMSecsSinceEpoch( - fromJson(jv), Qt::UTC).date(); + return fromJson(jv).date(); } -} // namespace QMatrixClient \ No newline at end of file +} // namespace QMatrixClient -- cgit v1.2.3 From cb3848c1e7fe09c2e778d38139c399b9f0484ce5 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Wed, 13 Sep 2017 21:10:36 +0900 Subject: MediaThumbnailJob: get rid of useless pimpl; add scaledThumbnail() Also use scaledThumbnail() in User::requestAvatar() --- jobs/mediathumbnailjob.cpp | 17 +++++------------ jobs/mediathumbnailjob.h | 5 ++--- user.cpp | 5 ++--- 3 files changed, 9 insertions(+), 18 deletions(-) (limited to 'jobs') diff --git a/jobs/mediathumbnailjob.cpp b/jobs/mediathumbnailjob.cpp index 9bb731b9..9579f6b2 100644 --- a/jobs/mediathumbnailjob.cpp +++ b/jobs/mediathumbnailjob.cpp @@ -23,12 +23,6 @@ using namespace QMatrixClient; -class MediaThumbnailJob::Private -{ - public: - QPixmap thumbnail; -}; - MediaThumbnailJob::MediaThumbnailJob(const ConnectionData* data, QUrl url, QSize requestedSize, ThumbnailType thumbnailType) : BaseJob(data, HttpVerb::Get, "MediaThumbnailJob", @@ -39,22 +33,21 @@ MediaThumbnailJob::MediaThumbnailJob(const ConnectionData* data, QUrl url, QSize , { "method", thumbnailType == ThumbnailType::Scale ? "scale" : "crop" } })) - , d(new Private) { } -MediaThumbnailJob::~MediaThumbnailJob() +QPixmap MediaThumbnailJob::thumbnail() { - delete d; + return pixmap; } -QPixmap MediaThumbnailJob::thumbnail() +QPixmap MediaThumbnailJob::scaledThumbnail(QSize toSize) { - return d->thumbnail; + return pixmap.scaled(toSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); } BaseJob::Status MediaThumbnailJob::parseReply(QByteArray data) { - if( !d->thumbnail.loadFromData(data) ) + if( !pixmap.loadFromData(data) ) { qCDebug(JOBS) << "MediaThumbnailJob: could not read image data"; } diff --git a/jobs/mediathumbnailjob.h b/jobs/mediathumbnailjob.h index 307d0a99..186da829 100644 --- a/jobs/mediathumbnailjob.h +++ b/jobs/mediathumbnailjob.h @@ -31,15 +31,14 @@ namespace QMatrixClient public: MediaThumbnailJob(const ConnectionData* data, QUrl url, QSize requestedSize, ThumbnailType thumbnailType=ThumbnailType::Scale); - virtual ~MediaThumbnailJob(); QPixmap thumbnail(); + QPixmap scaledThumbnail(QSize toSize); protected: Status parseReply(QByteArray data) override; private: - class Private; - Private* d; + QPixmap pixmap; }; } diff --git a/user.cpp b/user.cpp index 8d37eef6..f9f48539 100644 --- a/user.cpp +++ b/user.cpp @@ -170,12 +170,11 @@ void User::requestAvatar() void User::Private::requestAvatar() { - MediaThumbnailJob* job = connection->getThumbnail(avatarUrl, requestedSize); + auto* job = connection->callApi(avatarUrl, requestedSize); connect( job, &MediaThumbnailJob::success, [=]() { avatarOngoingRequest = false; avatarValid = true; - avatar = job->thumbnail().scaled(requestedSize, - Qt::KeepAspectRatio, Qt::SmoothTransformation); + avatar = job->scaledThumbnail(requestedSize); scaledAvatars.clear(); emit q->avatarChanged(q); }); -- cgit v1.2.3 From d4cb62523585137dee7879f2143ae1b4dd62513d Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Tue, 19 Sep 2017 11:39:30 +0900 Subject: Fix a race condition leading to a crash on close It seems that some reply processing still might have happened after BaseJob::abandon() (caused in turn by destroying a Connection object), probably because the event from QNetworkReply landed in the event queue after BaseJob::abandon() but before actual deletion of a job object. Now countered by disconnecting from QNetworkReply signals in abandon() and stop(). --- jobs/basejob.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'jobs') diff --git a/jobs/basejob.cpp b/jobs/basejob.cpp index 26ceb268..8c9ef222 100644 --- a/jobs/basejob.cpp +++ b/jobs/basejob.cpp @@ -219,16 +219,17 @@ BaseJob::Status BaseJob::parseJson(const QJsonDocument&) void BaseJob::stop() { d->timer.stop(); - if (!d->reply) + if (d->reply) { - qCWarning(d->logCat) << this << "stopped with empty network reply"; - } - else if (d->reply->isRunning()) - { - qCWarning(d->logCat) << this << "stopped without ready network reply"; d->reply->disconnect(this); // Ignore whatever comes from the reply - d->reply->abort(); + if (d->reply->isRunning()) + { + qCWarning(d->logCat) << this << "stopped without ready network reply"; + d->reply->abort(); + } } + else + qCWarning(d->logCat) << this << "stopped with empty network reply"; } void BaseJob::finishJob() @@ -320,6 +321,9 @@ void BaseJob::setStatus(int code, QString message) void BaseJob::abandon() { + this->disconnect(); + if (d->reply) + d->reply->disconnect(this); deleteLater(); } -- cgit v1.2.3 From 0b11b06379fe668063ea5658a261f53f1dcf117a Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Tue, 19 Sep 2017 12:56:29 +0900 Subject: BaseJob: improved logging Your QT_LOGGING_RULES (especially useful with Qt 5.6 and newer) should work a bit better now: * "Job" prefix is no more needed because the Qt logging prefix (libqmatrixclient.jobs) says it already; * The "created" record didn't follow the logging category if overridden from the concrete job class (see SyncJob); so instead of "created" there's now much more useful "sending request" record. --- jobs/basejob.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'jobs') diff --git a/jobs/basejob.cpp b/jobs/basejob.cpp index 8c9ef222..3057ed75 100644 --- a/jobs/basejob.cpp +++ b/jobs/basejob.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -76,7 +77,7 @@ class BaseJob::Private inline QDebug operator<<(QDebug dbg, const BaseJob* j) { - return dbg << "Job" << j->objectName(); + return dbg << j->objectName(); } BaseJob::BaseJob(const ConnectionData* connection, HttpVerb verb, @@ -89,7 +90,6 @@ BaseJob::BaseJob(const ConnectionData* connection, HttpVerb verb, connect (&d->timer, &QTimer::timeout, this, &BaseJob::timeout); d->retryTimer.setSingleShot(true); connect (&d->retryTimer, &QTimer::timeout, this, &BaseJob::start); - qCDebug(d->logCat) << this << "created"; } BaseJob::~BaseJob() @@ -159,6 +159,8 @@ void BaseJob::start() { emit aboutToStart(); d->retryTimer.stop(); // In case we were counting down at the moment + qCDebug(d->logCat) << this << "sending request to" + << d->apiEndpoint % '?' % d->requestQuery.toString(); d->sendRequest(); connect( d->reply.data(), &QNetworkReply::sslErrors, this, &BaseJob::sslErrors ); connect( d->reply.data(), &QNetworkReply::finished, this, &BaseJob::gotReply ); -- cgit v1.2.3 From 7e8c2ee1d00e43aab90030493c31aef0b4467f71 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Wed, 20 Sep 2017 13:00:21 +0900 Subject: Minor optimisations in sync data parsing --- jobs/syncjob.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'jobs') diff --git a/jobs/syncjob.cpp b/jobs/syncjob.cpp index 062f1b15..78a9e93f 100644 --- a/jobs/syncjob.cpp +++ b/jobs/syncjob.cpp @@ -59,27 +59,30 @@ BaseJob::Status SyncJob::parseJson(const QJsonDocument& data) return d.parseJson(data); } -BaseJob::Status SyncData::parseJson(const QJsonDocument &data) { +BaseJob::Status SyncData::parseJson(const QJsonDocument &data) +{ QElapsedTimer et; et.start(); + QJsonObject json = data.object(); nextBatch_ = json.value("next_batch").toString(); // TODO: presence // TODO: account_data QJsonObject rooms = json.value("rooms").toObject(); - const struct { QString jsonKey; JoinState enumVal; } roomStates[] + static const struct { QString jsonKey; JoinState enumVal; } roomStates[] { { "join", JoinState::Join }, { "invite", JoinState::Invite }, { "leave", JoinState::Leave } }; - for (auto roomState: roomStates) + for (const auto& roomState: roomStates) { const QJsonObject rs = rooms.value(roomState.jsonKey).toObject(); // We have a Qt container on the right and an STL one on the left roomData.reserve(static_cast(rs.size())); - for( auto rkey: rs.keys() ) - roomData.emplace_back(rkey, roomState.enumVal, rs[rkey].toObject()); + for(auto roomIt = rs.begin(); roomIt != rs.end(); ++roomIt) + roomData.emplace_back(roomIt.key(), roomState.enumVal, + roomIt.value().toObject()); } qCDebug(PROFILER) << "*** SyncData::parseJson():" << et.elapsed() << "ms"; return BaseJob::Success; -- cgit v1.2.3 From b01591bddbcc4bcf3957feeb6b4b2875a9a2d978 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Wed, 20 Sep 2017 14:05:16 +0900 Subject: BaseJob: track the outcome of sendRequest() in the logs Also: no reason to start the job timer if the request is not running, so don't even bother. --- jobs/basejob.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'jobs') diff --git a/jobs/basejob.cpp b/jobs/basejob.cpp index 3057ed75..6b2ebc58 100644 --- a/jobs/basejob.cpp +++ b/jobs/basejob.cpp @@ -164,8 +164,14 @@ void BaseJob::start() d->sendRequest(); connect( d->reply.data(), &QNetworkReply::sslErrors, this, &BaseJob::sslErrors ); connect( d->reply.data(), &QNetworkReply::finished, this, &BaseJob::gotReply ); - d->timer.start(getCurrentTimeout()); - emit started(); + if (d->reply->isRunning()) + { + d->timer.start(getCurrentTimeout()); + qCDebug(d->logCat) << this << "request has been sent"; + emit started(); + } + else + qCWarning(d->logCat) << this << "request could not start"; } void BaseJob::gotReply() -- cgit v1.2.3 From d51e7a43736096eb2776acd99e1aab6deeb65667 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 15 Sep 2017 18:43:29 +0900 Subject: jobs: SetRoomStateJob (with or without state key); setting room topic --- CMakeLists.txt | 1 + events/roomtopicevent.h | 12 +++++++++ jobs/setroomstatejob.cpp | 32 ++++++++++++++++++++++++ jobs/setroomstatejob.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ room.cpp | 8 +++++- room.h | 1 + 6 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 jobs/setroomstatejob.cpp create mode 100644 jobs/setroomstatejob.h (limited to 'jobs') diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e3abce1..e55335ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,7 @@ set(libqmatrixclient_SRCS jobs/checkauthmethods.cpp jobs/passwordlogin.cpp jobs/sendeventjob.cpp + jobs/setroomstatejob.cpp jobs/postreceiptjob.cpp jobs/joinroomjob.cpp jobs/leaveroomjob.cpp diff --git a/events/roomtopicevent.h b/events/roomtopicevent.h index fb849afe..95ad0e04 100644 --- a/events/roomtopicevent.h +++ b/events/roomtopicevent.h @@ -25,6 +25,9 @@ namespace QMatrixClient class RoomTopicEvent: public RoomEvent { public: + explicit RoomTopicEvent(const QString& topic) + : RoomEvent(Type::RoomTopic), _topic(topic) + { } explicit RoomTopicEvent(const QJsonObject& obj) : RoomEvent(Type::RoomTopic, obj) , _topic(contentJson()["topic"].toString()) @@ -32,6 +35,15 @@ namespace QMatrixClient QString topic() const { return _topic; } + QJsonObject toJson() const + { + QJsonObject obj; + obj.insert("topic", _topic); + return obj; + } + + static constexpr const char* TypeId = "m.room.topic"; + private: QString _topic; }; diff --git a/jobs/setroomstatejob.cpp b/jobs/setroomstatejob.cpp new file mode 100644 index 00000000..c2beb87b --- /dev/null +++ b/jobs/setroomstatejob.cpp @@ -0,0 +1,32 @@ +/****************************************************************************** + * Copyright (C) 2015 Felix Rohrbach + * + * 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 "setroomstatejob.h" + +using namespace QMatrixClient; + +BaseJob::Status SetRoomStateJob::parseJson(const QJsonDocument& data) +{ + _eventId = data.object().value("event_id").toString(); + if (!_eventId.isEmpty()) + return Success; + + qCDebug(JOBS) << data; + return { UserDefinedError, "No event_id in the JSON response" }; +} + diff --git a/jobs/setroomstatejob.h b/jobs/setroomstatejob.h new file mode 100644 index 00000000..1c72f31c --- /dev/null +++ b/jobs/setroomstatejob.h @@ -0,0 +1,65 @@ +/****************************************************************************** + * Copyright (C) 2015 Felix Rohrbach + * + * 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 + */ + +#pragma once + +#include "basejob.h" + +#include "connectiondata.h" + +namespace QMatrixClient +{ + class SetRoomStateJob: public BaseJob + { + public: + /** + * Constructs a job that sets a state using an arbitrary room event + * with a state key. + */ + template + SetRoomStateJob(const ConnectionData* connection, const QString& roomId, + const EvT* event, const QString& stateKey) + : BaseJob(connection, HttpVerb::Put, "SetRoomStateJob", + QStringLiteral("_matrix/client/r0/rooms/%1/state/%2/%3") + .arg(roomId, EvT::TypeId, stateKey), + Query(), + Data(event->toJson())) + { } + /** + * Constructs a job that sets a state using an arbitrary room event + * without a state key. + */ + template + SetRoomStateJob(const ConnectionData* connection, const QString& roomId, + const EvT* event) + : BaseJob(connection, HttpVerb::Put, "SetRoomStateJob", + QStringLiteral("_matrix/client/r0/rooms/%1/state/%2") + .arg(roomId, EvT::TypeId), + Query(), + Data(event->toJson())) + { } + + QString eventId() const { return _eventId; } + + protected: + Status parseJson(const QJsonDocument& data) override; + + private: + QString _eventId; + }; +} // namespace QMatrixClient diff --git a/room.cpp b/room.cpp index ae8c7e63..2ba3766a 100644 --- a/room.cpp +++ b/room.cpp @@ -26,6 +26,7 @@ #include #include // for efficient string concats (operator%) #include +#include #include "connection.h" #include "state.h" @@ -595,6 +596,12 @@ void Room::postMessage(RoomMessageEvent* event) connection()->callApi(id(), event); } +void Room::setTopic(const QString& newTopic) +{ + RoomTopicEvent evt(newTopic); + connection()->callApi(id(), &evt); +} + void Room::getPreviousContent(int limit) { d->getPreviousContent(limit); @@ -1032,4 +1039,3 @@ bool MemberSorter::operator()(User *u1, User *u2) const n2.remove(0, 1); return n1.localeAwareCompare(n2) < 0; } - diff --git a/room.h b/room.h index 5ea89418..393dced3 100644 --- a/room.h +++ b/room.h @@ -153,6 +153,7 @@ namespace QMatrixClient void postMessage(RoomMessageEvent* event); /** @deprecated */ void postMessage(const QString& type, const QString& plainText); + void setTopic(const QString& newTopic); void getPreviousContent(int limit = 10); -- cgit v1.2.3 From 15feb65dbb17161ccfbda614e0635f2698beacd7 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Fri, 22 Sep 2017 14:04:26 +0900 Subject: BaseJob: Log the sent request more nicely --- jobs/basejob.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'jobs') diff --git a/jobs/basejob.cpp b/jobs/basejob.cpp index 6b2ebc58..ea1a7158 100644 --- a/jobs/basejob.cpp +++ b/jobs/basejob.cpp @@ -159,8 +159,9 @@ void BaseJob::start() { emit aboutToStart(); d->retryTimer.stop(); // In case we were counting down at the moment - qCDebug(d->logCat) << this << "sending request to" - << d->apiEndpoint % '?' % d->requestQuery.toString(); + qCDebug(d->logCat) << this << "sending request to" << d->apiEndpoint; + if (!d->requestQuery.isEmpty()) + qCDebug(d->logCat) << " query:" << d->requestQuery.toString(); d->sendRequest(); connect( d->reply.data(), &QNetworkReply::sslErrors, this, &BaseJob::sslErrors ); connect( d->reply.data(), &QNetworkReply::finished, this, &BaseJob::gotReply ); -- cgit v1.2.3