aboutsummaryrefslogtreecommitdiff
path: root/connection.cpp
diff options
context:
space:
mode:
authorKitsune Ral <Kitsune-Ral@users.sf.net>2017-09-09 20:17:42 +0900
committerKitsune Ral <Kitsune-Ral@users.sf.net>2017-09-09 21:02:15 +0900
commit24e3d967d7c9029147202e10385b0b8e8881e4d9 (patch)
tree7ccc82dd50cbe89ffa4c8900103b1aa736bcc842 /connection.cpp
parent8ae1da50f8474a698ce83f61233b3a8975faeaee (diff)
downloadlibquotient-24e3d967d7c9029147202e10385b0b8e8881e4d9.tar.gz
libquotient-24e3d967d7c9029147202e10385b0b8e8881e4d9.zip
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.
Diffstat (limited to 'connection.cpp')
-rw-r--r--connection.cpp69
1 files changed, 42 insertions, 27 deletions
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<QString, Room*> 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<QPair<QString, bool>, Room*> roomMap;
QHash<QString, User*> 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<JoinRoomJob>(roomAlias);
- connect( job, &BaseJob::success, [=] () {
- if ( Room* r = provideRoom(job->roomId()) )
- emit joinedRoom(r);
- });
- return job;
+ return callApi<JoinRoomJob>(roomAlias);
}
void Connection::leaveRoom(Room* room)
{
- auto job = callApi<LeaveRoomJob>(room->id());
- connect( job, &BaseJob::success, [=] () {
- emit leftRoom(room);
- });
+ callApi<LeaveRoomJob>(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<QString, bool>, 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<Room*(Connection*, const QString&)> 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<User*(Connection*, const QString&)> 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();