Page MenuHomePhorge

D311.1783724445.diff
No OneTemporary

Size
202 KB
Referenced Files
None
Subscribers
None

D311.1783724445.diff

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -35,7 +35,10 @@
qt-job-handler.cpp
qt-job.cpp
${CMAKE_CURRENT_BINARY_DIR}/kazv-version.cpp
+ constants.cpp
matrix-sdk.cpp
+ matrix-session.cpp
+ matrix-session-controller.cpp
sso-login-process.cpp
kazv-session-lock-guard.cpp
matrix-room.cpp
diff --git a/src/constants.hpp b/src/constants.hpp
new file mode 100644
--- /dev/null
+++ b/src/constants.hpp
@@ -0,0 +1,53 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#pragma once
+#include <kazv-defs.hpp>
+#include <client.hpp>
+#include <QObject>
+#include <QQmlEngine>
+
+class Constants : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
+
+public:
+ enum LoadSessionResult {
+ /// Successfully loaded the session
+ SessionLoadSuccess,
+ /// There is no store file
+ SessionNotFound,
+ /// The format of the store file is not supported
+ SessionFormatUnknown,
+ /// The store file cannot be backed up
+ SessionCannotBackup,
+ /// Cannot grab the lock on the session file
+ SessionLockFailed,
+ /// Cannot open store file
+ SessionCannotOpenFile,
+ /// Cannot deserialize the store file
+ SessionDeserializeFailed,
+ };
+
+ Q_ENUM(LoadSessionResult);
+
+ enum CreateRoomPreset {
+ PrivateChat = Kazv::CreateRoomPreset::PrivateChat,
+ PublicChat = Kazv::CreateRoomPreset::PublicChat,
+ TrustedPrivateChat = Kazv::CreateRoomPreset::TrustedPrivateChat,
+ };
+
+ Q_ENUM(CreateRoomPreset);
+
+ enum MediaDownloadEndpointVersion {
+ UnauthenticatedMediaV3, // Classical endpoint series
+ AuthenticatedMediaV1, // Endpoints that needs authorization
+ };
+
+ Q_ENUM(MediaDownloadEndpointVersion);
+};
diff --git a/src/constants.cpp b/src/constants.cpp
new file mode 100644
--- /dev/null
+++ b/src/constants.cpp
@@ -0,0 +1,7 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include "constants.hpp"
diff --git a/src/contents/ui/AddStickerPopup.qml b/src/contents/ui/AddStickerPopup.qml
--- a/src/contents/ui/AddStickerPopup.qml
+++ b/src/contents/ui/AddStickerPopup.qml
@@ -39,7 +39,7 @@
Layout.preferredWidth: addStickerPopup.stickerSize
height: addStickerPopup.stickerSize
width: addStickerPopup.stickerSize
- source: matrixSdk.mxcUriToHttp(event.content.url)
+ source: matrixSession.mxcUriToHttp(event.content.url)
}
ComboBox {
@@ -86,7 +86,7 @@
property var updateStickerPack: Kazv.AsyncHandler {
trigger: () => {
addStickerPopup.addingSticker = true;
- return matrixSdk.updateStickerPack(
+ return matrixSession.updateStickerPack(
addStickerPopup.currentPack.addSticker(shortCodeInput.text, addStickerPopup.event)
);
}
diff --git a/src/contents/ui/AvatarAdapter.qml b/src/contents/ui/AvatarAdapter.qml
--- a/src/contents/ui/AvatarAdapter.qml
+++ b/src/contents/ui/AvatarAdapter.qml
@@ -12,14 +12,14 @@
id: avatar
property string mxcUri
readonly property var manager: kazvIOManager
- readonly property var sdk: matrixSdk
+ readonly property var session: matrixSession
source: fileHandler?.localFile || ''
property var fileHandlerComp: Component {
Kazv.FileHandler {
autoCache: true
kazvIOManager: avatar.manager
- matrixSdk: avatar.sdk
+ matrixSession: avatar.session
}
}
property var fileHandler: null
diff --git a/src/contents/ui/Bubble.qml b/src/contents/ui/Bubble.qml
--- a/src/contents/ui/Bubble.qml
+++ b/src/contents/ui/Bubble.qml
@@ -56,7 +56,7 @@
}
function getIsEditable(event) {
- return event.sender === matrixSdk.userId
+ return event.sender === matrixSession.userId
&& event.type === 'm.room.message'
&& event.content.msgtype === 'm.text';
}
@@ -167,7 +167,7 @@
property var event: room.messageById(bubbleRootLayout.replyToOrAnnotatedEventId)
property var props: ({
event,
- sender: room.member(event.sender || matrixSdk.userId),
+ sender: room.member(event.sender || matrixSession.userId),
stateKeyUser: event.stateKey ? room.member(event.stateKey) : {},
isGapped: timeline.gaps.hasOwnProperty(event.eventId),
})
diff --git a/src/contents/ui/CreateRoomPage.qml b/src/contents/ui/CreateRoomPage.qml
--- a/src/contents/ui/CreateRoomPage.qml
+++ b/src/contents/ui/CreateRoomPage.qml
@@ -163,7 +163,7 @@
}
property var createRoom: Kazv.AsyncHandler {
- trigger: () => matrixSdk.createRoom(
+ trigger: () => matrixSession.createRoom(
/* isPrivate = */ typePrivate.checked || typeDirect.checked,
roomName.text,
roomAlias.text,
@@ -173,17 +173,17 @@
roomTopic.text,
/* powerLevelContentOverride = */ {},
/* preset = */ typeDirect.checked
- ? MK.MatrixSdk.TrustedPrivateChat
+ ? MK.Constants.TrustedPrivateChat
: typePrivate.checked
- ? MK.MatrixSdk.PrivateChat
- : MK.MatrixSdk.PublicChat,
+ ? MK.Constants.PrivateChat
+ : MK.Constants.PublicChat,
/* encrypted = */ encrypted.checked,
)
onResolved: {
if (success) {
if (typeDirect.checked && createRoomPage.inviteUserIds.length === 1) {
- matrixSdk.addDirectRoom(createRoomPage.inviteUserIds[0], data.roomId);
+ matrixSession.addDirectRoom(createRoomPage.inviteUserIds[0], data.roomId);
}
showPassiveNotification(l10n.get('create-room-page-success-prompt'));
pageStack.removePage(createRoomPage);
diff --git a/src/contents/ui/EventReactions.qml b/src/contents/ui/EventReactions.qml
--- a/src/contents/ui/EventReactions.qml
+++ b/src/contents/ui/EventReactions.qml
@@ -28,7 +28,7 @@
function getSelfReactEventId() {
for (let i = 0; i < item.count; ++i) {
const e = item.at(i);
- if (e.sender === matrixSdk.userId) {
+ if (e.sender === matrixSession.userId) {
return e.eventId;
}
}
diff --git a/src/contents/ui/EventViewWrapper.qml b/src/contents/ui/EventViewWrapper.qml
--- a/src/contents/ui/EventViewWrapper.qml
+++ b/src/contents/ui/EventViewWrapper.qml
@@ -13,7 +13,7 @@
import '.' as Kazv
Kazv.EventView {
- sender: room.member(event.sender || matrixSdk.userId)
+ sender: room.member(event.sender || matrixSession.userId)
stateKeyUser: event.stateKey ? room.member(event.stateKey) : {}
isGapped: timeline?.gaps?.hasOwnProperty(event.eventId)
}
diff --git a/src/contents/ui/FileHandler.qml b/src/contents/ui/FileHandler.qml
--- a/src/contents/ui/FileHandler.qml
+++ b/src/contents/ui/FileHandler.qml
@@ -25,10 +25,10 @@
required property var eventContent
required property bool autoCache // thumbnail(if exists) will be downloaded if set to true
required property var kazvIOManager
- required property var matrixSdk
+ required property var matrixSession
- readonly property var httpVer: matrixSdk.checkSpecVersion("v1.11") ? MK.MatrixSdk.AuthenticatedMediaV1 : MK.MatrixSdk.UnauthenticatedMediaV3
- readonly property var token: (httpVer === MK.MatrixSdk.AuthenticatedMediaV1) ? matrixSdk.token : ""
+ readonly property var httpVer: matrixSession.checkSpecVersion("v1.11") ? MK.Constants.AuthenticatedMediaV1 : MK.Constants.UnauthenticatedMediaV3
+ readonly property var token: (httpVer === MK.Constants.AuthenticatedMediaV1) ? matrixSession.token : ""
property var kazvIOJob
readonly property url localFile: kazvIOJob ? '' : cachedFile
@@ -101,10 +101,10 @@
if (!mxcUri) {
return "";
}
- if (httpVer === MK.MatrixSdk.UnauthenticatedMediaV3) {
- return matrixSdk.mxcUriToHttp(mxcUri);
- } else if (httpVer === MK.MatrixSdk.AuthenticatedMediaV1) {
- return matrixSdk.mxcUriToHttpAuthenticatedV1(mxcUri);
+ if (httpVer === MK.Constants.UnauthenticatedMediaV3) {
+ return matrixSession.mxcUriToHttp(mxcUri);
+ } else if (httpVer === MK.Constants.AuthenticatedMediaV1) {
+ return matrixSession.mxcUriToHttpAuthenticatedV1(mxcUri);
} else {
return "";
}
diff --git a/src/contents/ui/ImageAdapter.qml b/src/contents/ui/ImageAdapter.qml
--- a/src/contents/ui/ImageAdapter.qml
+++ b/src/contents/ui/ImageAdapter.qml
@@ -11,14 +11,14 @@
id: image
property string mxcUri
readonly property var manager: kazvIOManager
- readonly property var sdk: matrixSdk
+ readonly property var session: matrixSession
source: fileHandler?.localFile || ''
property var fileHandlerComp: Component {
Kazv.FileHandler {
autoCache: true
kazvIOManager: image.manager
- matrixSdk: image.sdk
+ matrixSession: image.session
}
}
property var fileHandler: null
diff --git a/src/contents/ui/JoinRoomPage.qml b/src/contents/ui/JoinRoomPage.qml
--- a/src/contents/ui/JoinRoomPage.qml
+++ b/src/contents/ui/JoinRoomPage.qml
@@ -57,7 +57,7 @@
property var joinRoomHandler: Kazv.AsyncHandler {
property var serverNames: servers.text.split('\n').map(k => k.trim()).filter(k => k)
property var room: idOrAlias.text
- trigger: () => matrixSdk.joinRoom(room, serverNames)
+ trigger: () => matrixSession.joinRoom(room, serverNames)
onResolved: {
if (success) {
showPassiveNotification(l10n.get('join-room-page-success-prompt', { room }));
diff --git a/src/contents/ui/LoginFlows.qml b/src/contents/ui/LoginFlows.qml
--- a/src/contents/ui/LoginFlows.qml
+++ b/src/contents/ui/LoginFlows.qml
@@ -49,10 +49,8 @@
Layout.fillWidth: true
onClicked: () => {
loginFlows.ownLoading = true;
- if (loginFlows.isSwitchingAccount) {
- matrixSdk.startNewSession();
- }
- matrixSdk.discoverAndGetLoginFlows(userIdField.text, serverUrlField.text);
+ matrixSdk.startNewSession();
+ // go to sdkConns.onSessionChanged
}
}
}
@@ -132,7 +130,7 @@
enabled: !loginPage.loading
onClicked: {
loginFlows.ownLoading = true;
- matrixSdk.login(userIdField.text, passwordField.text, loginTypeScreen.serverUrl);
+ matrixSession.login(userIdField.text, passwordField.text, loginTypeScreen.serverUrl);
}
}
@@ -145,7 +143,7 @@
enabled: !loginFlows.loading
onClicked: {
loginFlows.ownLoading = true;
- loginTypeScreen.ssoRedirectUrl = matrixSdk.ssoLoginStart(loginTypeScreen.serverUrl);
+ loginTypeScreen.ssoRedirectUrl = matrixSession.ssoLoginStart(loginTypeScreen.serverUrl);
if (!inTest) {
Qt.openUrlExternally(loginTypeScreen.ssoRedirectUrl);
}
@@ -168,8 +166,16 @@
}
}
- property var conns: Connections {
+ property var sdkConns: Connections {
target: matrixSdk
+ function onSessionChanged() {
+ if (loginFlows.ownLoading) {
+ matrixSession.discoverAndGetLoginFlows(userIdField.text, serverUrlField.text);
+ }
+ }
+ }
+ property var sessionConns: Connections {
+ target: matrixSession
function onDiscoverFailed(errorCode, errorMsg) {
showPassiveNotification(l10n.get('login-page-discover-failed-enter-prompt', { errorCode, errorMsg }));
loginFlows.discoveredServerUrl = '';
diff --git a/src/contents/ui/LoginPage.qml b/src/contents/ui/LoginPage.qml
--- a/src/contents/ui/LoginPage.qml
+++ b/src/contents/ui/LoginPage.qml
@@ -25,7 +25,7 @@
id: restoreSessionPart
width: parent.width
spacing: Kirigami.Units.largeSpacing
- property var sessions: matrixSdk.allSessions().filter(s => s !== sessionNameFor(matrixSdk.userId, matrixSdk.deviceId))
+ property var sessions: matrixSdk.allSessions().filter(s => s !== sessionNameFor(matrixSession?.userId, matrixSession?.deviceId))
Label {
text: l10n.get('login-page-existing-sessions-prompt')
diff --git a/src/contents/ui/Main.qml b/src/contents/ui/Main.qml
--- a/src/contents/ui/Main.qml
+++ b/src/contents/ui/Main.qml
@@ -39,49 +39,57 @@
property bool loadingSession: false
property var matrixSdk: MK.MatrixSdk {
- onLoginSuccessful: {
+ onSessionChanged: {
+ console.log('session changed');
+ reloadSdkVariables();
+ root.purgeTimer.start();
+ }
+
+ onLoadSessionFinished: (sessionName, res) => {
+ root.loadingSession = false;
+ if (res === MK.Constants.SessionLoadSuccess) {
+ console.log('load session successful');
+ switchToMainPage();
+ recordLastSession();
+ matrixSession.getSpecVersions();
+ } else {
+ showPassiveNotification(getSessionLoadError(res, sessionName));
+ }
+ }
+ }
+
+ property var matrixSession: matrixSdk.session()
+ Connections {
+ target: matrixSession
+ function onLoginSuccessful() {
console.log('Login successful');
switchToMainPage();
recordLastSession();
root.purgeTimer.start();
}
- onLoginFailed: {
+ function onLoginFailed() {
console.log("Login Failed");
showPassiveNotification(l10n.get('login-page-request-failed-prompt', { errorCode, errorMsg }));
}
- onSessionChanged: {
- console.log('session changed');
- reloadSdkVariables();
- root.purgeTimer.start();
- }
- onLogoutSuccessful: {
+
+ function onLogoutSuccessful() {
root.loggedIn = false;
pageStack.clear();
pushLoginPage();
}
- onLogoutFailed: {
+
+ function onLogoutFailed() {
console.warn('Logout failed');
showPassiveNotification(l10n.get('logout-failed-prompt', { errorCode, errorMsg }));
}
- onLoadSessionFinished: (sessionName, res) => {
- root.loadingSession = false;
- if (res === MK.MatrixSdk.SessionLoadSuccess) {
- console.log('load session successful');
- switchToMainPage();
- recordLastSession();
- matrixSdk.getSpecVersions();
- } else {
- showPassiveNotification(getSessionLoadError(res, sessionName));
- }
- }
}
- property var loggedIn: !!matrixSdk.token
+ property var loggedIn: !!matrixSession?.token
property var sdkVars: QtObject {
- property var roomList: matrixSdk.roomList()
- property var userGivenNicknameMap: matrixSdk.userGivenNicknameMap()
+ property var roomList: matrixSession?.roomList()
+ property var userGivenNicknameMap: matrixSession?.userGivenNicknameMap()
property string currentRoomId: ''
}
@@ -90,7 +98,7 @@
repeat: true
triggeredOnStart: true
onTriggered: () => {
- matrixSdk.purgeEventsExceptRooms(
+ matrixSession?.purgeEventsExceptRooms(
sdkVars.currentRoomId ? [sdkVars.currentRoomId] : []);
}
}
@@ -146,7 +154,7 @@
}
}
- title: matrixSdk.userId ? l10n.get('app-title-with-user-id', { userId: matrixSdk.userId }) : l10n.get('app-title-not-logged-in')
+ title: matrixSession?.userId ? l10n.get('app-title-with-user-id', { userId: matrixSession.userId }) : l10n.get('app-title-not-logged-in')
globalDrawer: Kirigami.GlobalDrawer {
title: l10n.get('global-drawer-title')
@@ -342,22 +350,22 @@
function getSessionLoadError(res, sessionName) {
switch (res) {
- case MK.MatrixSdk.SessionNotFound:
+ case MK.Constants.SessionNotFound:
return l10n.get('session-load-failure-not-found', { sessionName });
- case MK.MatrixSdk.SessionFormatUnknown:
+ case MK.Constants.SessionFormatUnknown:
return l10n.get('session-load-failure-format-unknown', { sessionName });
- case MK.MatrixSdk.SessionCannotBackup:
+ case MK.Constants.SessionCannotBackup:
return l10n.get('session-load-failure-cannot-backup', { sessionName });
- case MK.MatrixSdk.SessionLockFailed:
+ case MK.Constants.SessionLockFailed:
return l10n.get('session-load-failure-lock-failed', { sessionName });
- case MK.MatrixSdk.SessionCannotOpenFile:
+ case MK.Constants.SessionCannotOpenFile:
return l10n.get('session-load-failure-cannot-open-file', { sessionName });
- case MK.MatrixSdk.SessionDeserializeFailed:
+ case MK.Constants.SessionDeserializeFailed:
return l10n.get('session-load-failure-deserialize-failed', { sessionName });
default:
@@ -376,12 +384,13 @@
}
function recordLastSession() {
- kazvConfig.lastSession = sessionNameFor(matrixSdk.userId, matrixSdk.deviceId);
+ kazvConfig.lastSession = sessionNameFor(matrixSession?.userId, matrixSession?.deviceId);
}
function reloadSdkVariables() {
- sdkVars.roomList = matrixSdk.roomList();
- sdkVars.userGivenNicknameMap = matrixSdk.userGivenNicknameMap();
+ matrixSession = matrixSdk.session();
+ sdkVars.roomList = matrixSession?.roomList();
+ sdkVars.userGivenNicknameMap = matrixSession?.userGivenNicknameMap();
sdkVars.currentRoomId = '';
}
@@ -390,11 +399,12 @@
}
function hardLogout() {
- matrixSdk.logout();
+ matrixSession?.logout();
}
Component.onCompleted: {
actionCollection.setupShortcuts();
+ matrixSdk.startThread();
loadLastSession();
}
diff --git a/src/contents/ui/MainPage.qml b/src/contents/ui/MainPage.qml
--- a/src/contents/ui/MainPage.qml
+++ b/src/contents/ui/MainPage.qml
@@ -14,7 +14,7 @@
import '.' as Kazv
Kirigami.ScrollablePage {
- title: l10n.get('main-page-title', { userId: matrixSdk.userId })
+ title: l10n.get('main-page-title', { userId: matrixSession.userId })
property var currentTagId: ''
diff --git a/src/contents/ui/MediaFileMenu.qml b/src/contents/ui/MediaFileMenu.qml
--- a/src/contents/ui/MediaFileMenu.qml
+++ b/src/contents/ui/MediaFileMenu.qml
@@ -19,7 +19,7 @@
required property var eventId
property var jobManager: kazvIOManager
- property var mtxSdk: matrixSdk
+ property var session: matrixSession
signal downloadStarted
@@ -28,7 +28,7 @@
autoCache: false
eventContent: mediaFileMenu.eventContent
kazvIOManager: mediaFileMenu.jobManager
- matrixSdk: mediaFileMenu.mtxSdk
+ matrixSession: mediaFileMenu.session
}
property var viewAction: Kirigami.Action {
diff --git a/src/contents/ui/Notifier.qml b/src/contents/ui/Notifier.qml
--- a/src/contents/ui/Notifier.qml
+++ b/src/contents/ui/Notifier.qml
@@ -21,21 +21,21 @@
property var roomNameProvider: Kazv.RoomNameProvider {}
property var conn: Connections {
- target: matrixSdk
+ target: matrixSession
function onReceivedMessage(roomId, eventId) {
- const roomList = matrixSdk.roomList();
+ const roomList = matrixSession.roomList();
const room = roomList.room(roomId);
const event = room.messageById(eventId);
const sender = room.member(event.sender);
const senderName = nameProvider.getName(sender);
- if (matrixSdk.shouldNotify(event)) {
+ if (matrixSession.shouldNotify(event)) {
console.debug('Push rules say we should notify this');
const notification = notificationComp.createObject(
notifier,
{
roomId,
});
- notification.eventId = matrixSdk.shouldPlaySound(event) ? 'message' : 'messageWithoutSound';
+ notification.eventId = matrixSession.shouldPlaySound(event) ? 'message' : 'messageWithoutSound';
notification.title = roomNameProvider.getName(room);
const message = event.content.body;
notification.text = message
diff --git a/src/contents/ui/RoomListView.qml b/src/contents/ui/RoomListView.qml
--- a/src/contents/ui/RoomListView.qml
+++ b/src/contents/ui/RoomListView.qml
@@ -22,8 +22,6 @@
property var iconSize: Kirigami.Units.iconSizes.large
- //matrixSdk.currentRoomId
-
Layout.fillHeight: true
model: roomList
Layout.minimumHeight: childrenRect.height
diff --git a/src/contents/ui/RoomListViewItemDelegate.qml b/src/contents/ui/RoomListViewItemDelegate.qml
--- a/src/contents/ui/RoomListViewItemDelegate.qml
+++ b/src/contents/ui/RoomListViewItemDelegate.qml
@@ -156,10 +156,10 @@
} else if (room.localReadMarker === event.eventId) {
// This message is read locally
return undefined;
- } else if (event.sender === matrixSdk.userId) {
+ } else if (event.sender === matrixSession.userId) {
// Own message here
return undefined;
- } else if (Helpers.isEventReadBy(event, matrixSdk.userId)) {
+ } else if (Helpers.isEventReadBy(event, matrixSession.userId)) {
// This message is read
return undefined;
} else {
diff --git a/src/contents/ui/RoomPage.qml b/src/contents/ui/RoomPage.qml
--- a/src/contents/ui/RoomPage.qml
+++ b/src/contents/ui/RoomPage.qml
@@ -146,7 +146,7 @@
title: l10n.get('room-invite-popup-title')
parent: roomPage.overlay
- property var self: room.member(matrixSdk.userId)
+ property var self: room.member(matrixSession.userId)
property var inviteEvent: self.toEvent()
property var inviter: room.member(inviteEvent.sender)
property var inviterName: Helpers.userNameWithId(inviter, l10n)
@@ -229,7 +229,7 @@
}
property var joinRoomHandler: Kazv.AsyncHandler {
- trigger: () => matrixSdk.joinRoom(roomId, [])
+ trigger: () => matrixSession.joinRoom(roomId, [])
onResolved: {
if (success) {
showPassiveNotification(l10n.get('join-room-page-success-prompt', { room: roomId }));
@@ -264,7 +264,7 @@
function getLastReceiptableEventId(timeline, timelineCount) {
for (let i = 0; i < timelineCount; ++i) {
const event = timeline.at(i);
- if (!event.isLocalEcho && event.sender !== matrixSdk.userId) {
+ if (!event.isLocalEcho && event.sender !== matrixSession.userId) {
return event.eventId;
}
}
@@ -287,7 +287,7 @@
}
const event = roomPage.room.messageById(eventId);
- const readByMe = Helpers.isEventReadBy(event, matrixSdk.userId);
+ const readByMe = Helpers.isEventReadBy(event, matrixSession.userId);
if (!readByMe) {
roomPage.room.postReadReceipt(eventId);
}
@@ -308,7 +308,7 @@
onBackfillRequested: (eventId) => {
if (!paginationRequests[eventId]) {
- paginationRequests[eventId] = matrixSdk.backfillRoomFromEvent(roomId, eventId);
+ paginationRequests[eventId] = matrixSession.backfillRoomFromEvent(roomId, eventId);
paginationRequests[eventId].resolved.connect((isSuccess, data) => {
console.debug(
'finished backfill from', eventId,
diff --git a/src/contents/ui/SendMessageBox.qml b/src/contents/ui/SendMessageBox.qml
--- a/src/contents/ui/SendMessageBox.qml
+++ b/src/contents/ui/SendMessageBox.qml
@@ -462,7 +462,7 @@
function uploadFile(fileUrl) {
kazvIOManager.startNewUploadJob(
- matrixSdk.serverUrl, fileUrl, matrixSdk.token,
+ matrixSession.serverUrl, fileUrl, matrixSession.token,
room.roomId, sdkVars.roomList, room.encrypted,
draftRelType, draftRelatedTo
);
@@ -476,7 +476,7 @@
Kazv.StickerPicker {
Layout.preferredWidth: Math.min(Kirigami.Units.gridUnit * 40, Window.width)
- stickerPackList: matrixSdk.stickerPackList()
+ stickerPackList: matrixSession.stickerPackList()
onSendMessageRequested: eventJson => {
console.log(JSON.stringify(eventJson));
room.sendMessage(eventJson, draftRelType, draftRelatedTo);
diff --git a/src/contents/ui/UploadFileHelper.qml b/src/contents/ui/UploadFileHelper.qml
--- a/src/contents/ui/UploadFileHelper.qml
+++ b/src/contents/ui/UploadFileHelper.qml
@@ -23,7 +23,7 @@
property var fileDialog: Kazv.FileDialogAdapter {
onAccepted: {
- uploadFileHelper.job = kazvIOManager.startNewRoomlessUploadJob(matrixSdk.serverUrl, fileUrl, matrixSdk.token)
+ uploadFileHelper.job = kazvIOManager.startNewRoomlessUploadJob(matrixSession.serverUrl, fileUrl, matrixSession.token)
}
}
diff --git a/src/contents/ui/UserPage.qml b/src/contents/ui/UserPage.qml
--- a/src/contents/ui/UserPage.qml
+++ b/src/contents/ui/UserPage.qml
@@ -178,7 +178,7 @@
}
RowLayout {
- visible: room.membership === MK.MatrixRoom.Join && userPage.userId === matrixSdk.userId
+ visible: room.membership === MK.MatrixRoom.Join && userPage.userId === matrixSession.userId
TextField {
id: selfNameInput
objectName: 'selfNameInput'
@@ -199,7 +199,7 @@
RowLayout {
// Do not allow user to set a name override for themselves
- visible: userPage.userId !== matrixSdk.userId
+ visible: userPage.userId !== matrixSession.userId
TextField {
id: nameOverrideInput
objectName: 'nameOverrideInput'
@@ -388,7 +388,7 @@
Layout.fillHeight: true
Layout.minimumHeight: childrenRect.height
userId: userPage.userId
- devices: matrixSdk.devicesOfUser(userId)
+ devices: matrixSession.devicesOfUser(userId)
}
}
}
diff --git a/src/contents/ui/VerificationsPage.qml b/src/contents/ui/VerificationsPage.qml
--- a/src/contents/ui/VerificationsPage.qml
+++ b/src/contents/ui/VerificationsPage.qml
@@ -14,7 +14,7 @@
Kazv.ClosableScrollableOverlay {
id: verificationsPage
title: l10n.get('verifications-page-title')
- property var verificationList: matrixSdk.verificationList()
+ property var verificationList: matrixSession.verificationList()
Kirigami.CardsListView {
objectName: 'verificationsView'
diff --git a/src/contents/ui/device-mgmt/Device.qml b/src/contents/ui/device-mgmt/Device.qml
--- a/src/contents/ui/device-mgmt/Device.qml
+++ b/src/contents/ui/device-mgmt/Device.qml
@@ -107,7 +107,7 @@
text: l10n.get('device-set-trust-level-dialog-save')
onClicked: {
const current = popup.getNewTrustLevel();
- popup.setTrustLevelPromise = matrixSdk.setDeviceTrustLevel(userId, item.deviceId, current);
+ popup.setTrustLevelPromise = matrixSession.setDeviceTrustLevel(userId, item.deviceId, current);
}
}
@@ -153,7 +153,7 @@
property var requestVerify: Kazv.AsyncHandler {
trigger: () => {
device.sendingVerification = true;
- return matrixSdk.requestVerifyDevice(userId, item.deviceId);
+ return matrixSession.requestVerifyDevice(userId, item.deviceId);
}
onResolved: (success, data) => {
device.sendingVerification = false;
diff --git a/src/contents/ui/event-types/Audio.qml b/src/contents/ui/event-types/Audio.qml
--- a/src/contents/ui/event-types/Audio.qml
+++ b/src/contents/ui/event-types/Audio.qml
@@ -20,7 +20,7 @@
property var gender: 'neutral'
property var body: event.content.body
property var mxcUri: event.content.url
- property var audioUri: matrixSdk.mxcUriToHttp(mxcUri)
+ property var audioUri: matrixSession.mxcUriToHttp(mxcUri)
property var innerContentWidth: upper.contentMaxWidth - bubble.bubbleSpacing
diff --git a/src/contents/ui/event-types/File.qml b/src/contents/ui/event-types/File.qml
--- a/src/contents/ui/event-types/File.qml
+++ b/src/contents/ui/event-types/File.qml
@@ -20,7 +20,7 @@
property var gender: 'neutral'
property var body: event.content.body
property var mxcUri: event.content.url
- property var fileUri: matrixSdk.mxcUriToHttp(mxcUri)
+ property var fileUri: matrixSession.mxcUriToHttp(mxcUri)
property var innerContentWidth: upper.contentMaxWidth - bubble.bubbleSpacing
diff --git a/src/contents/ui/event-types/Image.qml b/src/contents/ui/event-types/Image.qml
--- a/src/contents/ui/event-types/Image.qml
+++ b/src/contents/ui/event-types/Image.qml
@@ -36,7 +36,7 @@
property var innerContentWidth: upper.contentMaxWidth - bubble.bubbleSpacing
property var jobManager: kazvIOManager
- property var mtxSdk: matrixSdk
+ property var session: matrixSession
property var isSticker: event.type === 'm.sticker'
summaryItem: Label {
@@ -52,7 +52,7 @@
eventContent: event.content
autoCache: true
kazvIOManager: upper.jobManager
- matrixSdk: upper.mtxSdk
+ matrixSession: upper.session
}
Types.MediaBubble {
@@ -90,7 +90,7 @@
Kazv.AddStickerPopup {
parent: applicationWindow().overlay
shouldSelfDestroy: true
- stickerPackList: matrixSdk.stickerPackList()
+ stickerPackList: matrixSession.stickerPackList()
event: upper.curEvent
}
}
diff --git a/src/contents/ui/event-types/Simple.qml b/src/contents/ui/event-types/Simple.qml
--- a/src/contents/ui/event-types/Simple.qml
+++ b/src/contents/ui/event-types/Simple.qml
@@ -43,7 +43,7 @@
event.sender === prevEvent.sender
// local echo does not have a sender, will use the current user
|| (!!event.isLocalEcho && !!prevEvent.isLocalEcho)
- || (!!event.isLocalEcho && prevEvent.sender === matrixSdk.userId)
+ || (!!event.isLocalEcho && prevEvent.sender === matrixSession.userId)
)
)
diff --git a/src/contents/ui/event-types/TextTemplate.qml b/src/contents/ui/event-types/TextTemplate.qml
--- a/src/contents/ui/event-types/TextTemplate.qml
+++ b/src/contents/ui/event-types/TextTemplate.qml
@@ -87,7 +87,7 @@
property var openRoomAliasLink: Kazv.AsyncHandler {
property var link
property var joinRoom
- trigger: () => matrixSdk.getRoomIdByAlias(link.identifiers[0])
+ trigger: () => matrixSession.getRoomIdByAlias(link.identifiers[0])
onResolved: {
if (success) {
@@ -153,7 +153,7 @@
}
// If the room with the user already exists, switch to the room.
// Otherwise try to create the room.
- for (const roomId of matrixSdk.directRoomIds(userId)) {
+ for (const roomId of matrixSession.directRoomIds(userId)) {
const invitedOrJoined = (roomId) => {
const membership = sdkVars.roomList.room(roomId).membership;
return (membership == MK.MatrixRoom.Invite) || (membership == MK.MatrixRoom.Join);
diff --git a/src/contents/ui/event-types/Video.qml b/src/contents/ui/event-types/Video.qml
--- a/src/contents/ui/event-types/Video.qml
+++ b/src/contents/ui/event-types/Video.qml
@@ -28,13 +28,13 @@
property var videoMaxHeight: compactMode ? Kirigami.Units.gridUnit * 5 : Infinity
property var thumbnailInfo: videoInfo.thumbnail_info || {}
property var thumbnailMxcUri: videoInfo.thumbnail_url
- property var thumbnailUri: matrixSdk.mxcUriToHttp(thumbnailMxcUri)
+ property var thumbnailUri: matrixSession.mxcUriToHttp(thumbnailMxcUri)
property var hasThumbnail: !! thumbnailMxcUri
property var innerContentWidth: upper.contentMaxWidth - bubble.bubbleSpacing
property var jobManager: kazvIOManager
- property var mtxSdk: matrixSdk
+ property var session: matrixSession
summaryItem: Label {
objectName: 'summaryLabel'
@@ -49,7 +49,7 @@
eventContent: event.content
autoCache: true
kazvIOManager: upper.jobManager
- matrixSdk: upper.mtxSdk
+ matrixSession: upper.session
}
Types.MediaBubble {
diff --git a/src/contents/ui/room-settings/RoomStickerPackItemDelegate.qml b/src/contents/ui/room-settings/RoomStickerPackItemDelegate.qml
--- a/src/contents/ui/room-settings/RoomStickerPackItemDelegate.qml
+++ b/src/contents/ui/room-settings/RoomStickerPackItemDelegate.qml
@@ -64,7 +64,7 @@
}
property var sendAccountData: Kazv.AsyncHandler {
- trigger: () => matrixSdk.sendAccountData(Helpers.imagePackRoomsEventType, content);
+ trigger: () => matrixSession.sendAccountData(Helpers.imagePackRoomsEventType, content);
property var content
onResolved: (success, data) => {
if (!success) {
diff --git a/src/contents/ui/room-settings/RoomStickerPacksPage.qml b/src/contents/ui/room-settings/RoomStickerPacksPage.qml
--- a/src/contents/ui/room-settings/RoomStickerPacksPage.qml
+++ b/src/contents/ui/room-settings/RoomStickerPacksPage.qml
@@ -30,7 +30,7 @@
model: roomStickerPacksPage.stickerPackList
delegate: RoomSettings.RoomStickerPackItemDelegate {
required property int index
- stickerRoomsEvent: matrixSdk.stickerRoomsEvent()
+ stickerRoomsEvent: matrixSession.stickerRoomsEvent()
stickerPack: stickerPackList.at(index)
}
}
diff --git a/src/contents/ui/settings/ProfileSettings.qml b/src/contents/ui/settings/ProfileSettings.qml
--- a/src/contents/ui/settings/ProfileSettings.qml
+++ b/src/contents/ui/settings/ProfileSettings.qml
@@ -31,7 +31,7 @@
property var saveAvatarUrl: Kazv.AsyncHandler {
trigger: () => {
profileSettings.loaded = false;
- return matrixSdk.setAvatarUrl(profileSettings.avatarUrl);
+ return matrixSession.setAvatarUrl(profileSettings.avatarUrl);
}
onResolved: {
if (!success) {
@@ -73,7 +73,7 @@
property var getSelfPromise: Kazv.AsyncHandler {
- trigger: () => matrixSdk.getSelfProfile()
+ trigger: () => matrixSession.getSelfProfile()
onResolved: {
if (!success) {
showPassiveNotification(l10n.get('settings-profile-load-failed-prompt', { errorCode: data.errorCode, errorMsg: data.error }));
@@ -92,7 +92,7 @@
property var saveDisplayName: Kazv.AsyncHandler {
trigger: () => {
profileSettings.loaded = false;
- return matrixSdk.setDisplayName(displayNameEntry.text);
+ return matrixSession.setDisplayName(displayNameEntry.text);
}
onResolved: {
if (!success) {
diff --git a/src/contents/ui/settings/SecuritySettings.qml b/src/contents/ui/settings/SecuritySettings.qml
--- a/src/contents/ui/settings/SecuritySettings.qml
+++ b/src/contents/ui/settings/SecuritySettings.qml
@@ -55,7 +55,7 @@
trigger: () => {
const password = passwordInput.text;
passwordInput.text = '';
- return matrixSdk.importFromKeyBackupFile(securitySettings.fileToImport, password);
+ return matrixSession.importFromKeyBackupFile(securitySettings.fileToImport, password);
}
onResolved: (success, data) => {
if (success) {
diff --git a/src/db-store.hpp b/src/db-store.hpp
--- a/src/db-store.hpp
+++ b/src/db-store.hpp
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
+#pragma once
#include <kazv-defs.hpp>
#include <tuple>
#include <functional>
diff --git a/src/db-store.cpp b/src/db-store.cpp
--- a/src/db-store.cpp
+++ b/src/db-store.cpp
@@ -5,7 +5,7 @@
*/
#include "db-store.hpp"
-#include "matrix-sdk.hpp"
+#include "matrix-session-controller.hpp"
#include "event.hpp"
#include "kazv-log.hpp"
#include <QPromise>
diff --git a/src/helper.hpp b/src/helper.hpp
--- a/src/helper.hpp
+++ b/src/helper.hpp
@@ -11,7 +11,7 @@
#include <QString>
#include <QStringList>
-
+#include <QObject>
#include <zug/transducer/map.hpp>
#include <cursorutil.hpp>
@@ -72,3 +72,14 @@
constexpr auto qStringToTrustLevel = zug::map(qStringToTrustLevelFunc);
inline auto roomMemberToAvatar = Kazv::eventContent | Kazv::jsonAtOr(std::string("avatar_url"), std::string(""));
+
+struct QObjectDeleterDeleteLater
+{
+ void operator()(QObject *obj) const
+ {
+ obj->deleteLater();
+ }
+};
+
+template<class T>
+using UniquePtrDL = std::unique_ptr<T, QObjectDeleterDeleteLater>;
diff --git a/src/matrix-sdk.hpp b/src/matrix-sdk.hpp
--- a/src/matrix-sdk.hpp
+++ b/src/matrix-sdk.hpp
@@ -6,7 +6,11 @@
#pragma once
#include <kazv-defs.hpp>
-
+#include "constants.hpp"
+#include "meta-types.hpp"
+Q_MOC_INCLUDE("matrix-promise.hpp")
+Q_MOC_INCLUDE("matrix-event.hpp")
+Q_MOC_INCLUDE("matrix-session.hpp")
#include <QObject>
#include <QQmlEngine>
#include <QString>
@@ -21,30 +25,13 @@
#include <sdk-model.hpp>
#include <random-generator.hpp>
-#include "meta-types.hpp"
-Q_MOC_INCLUDE("matrix-room-list.hpp")
-Q_MOC_INCLUDE("matrix-device-list.hpp")
-Q_MOC_INCLUDE("matrix-promise.hpp")
-Q_MOC_INCLUDE("matrix-event.hpp")
-Q_MOC_INCLUDE("matrix-sticker-pack-list.hpp")
-Q_MOC_INCLUDE("matrix-user-given-attrs-map.hpp")
-Q_MOC_INCLUDE("matrix-verification-list.hpp")
-
-class MatrixRoomList;
-class MatrixDeviceList;
class MatrixPromise;
-class MatrixSdkTest;
class MatrixSdkSessionsTest;
-class MatrixEvent;
-class MatrixStickerPackList;
-class MatrixUserGivenAttrsMap;
class KazvSessionLockGuard;
class DbStore;
-class MatrixVerificationList;
+class MatrixSession;
struct MatrixSdkPrivate;
-std::filesystem::path sessionDirForUserAndDeviceId(std::filesystem::path userDataDir, std::string userId, std::string deviceId);
-
class MatrixSdk : public QObject
{
Q_OBJECT
@@ -59,121 +46,21 @@
void init();
public:
- enum CreateRoomPreset {
- PrivateChat = Kazv::CreateRoomPreset::PrivateChat,
- PublicChat = Kazv::CreateRoomPreset::PublicChat,
- TrustedPrivateChat = Kazv::CreateRoomPreset::TrustedPrivateChat,
- };
-
- Q_ENUM(CreateRoomPreset);
-
- enum LoadSessionResult {
- /// Successfully loaded the session
- SessionLoadSuccess,
- /// There is no store file
- SessionNotFound,
- /// The format of the store file is not supported
- SessionFormatUnknown,
- /// The store file cannot be backed up
- SessionCannotBackup,
- /// Cannot grab the lock on the session file
- SessionLockFailed,
- /// Cannot open store file
- SessionCannotOpenFile,
- /// Cannot deserialize the store file
- SessionDeserializeFailed,
- };
-
- Q_ENUM(LoadSessionResult);
-
- enum MediaDownloadEndpointVersion {
- UnauthenticatedMediaV3, // Classical endpoint series
- AuthenticatedMediaV1, // Endpoints that needs authorization
- };
-
- Q_ENUM(MediaDownloadEndpointVersion);
-
explicit MatrixSdk(QObject *parent = 0);
~MatrixSdk() override;
- LAGER_QT_READER(QString, serverUrl);
- LAGER_QT_READER(QString, userId);
- LAGER_QT_READER(QString, token);
- LAGER_QT_READER(QString, deviceId);
- LAGER_QT_READER(immer::array<std::string>, specVersions); // The versions of the Matrix Spec supported by the server.
-
- Q_INVOKABLE MatrixRoomList *roomList() const;
-
- Q_INVOKABLE QString mxcUriToHttp(QString mxcUri) const;
-
- Q_INVOKABLE QString mxcUriToHttpAuthenticatedV1(QString mxcUri) const;
-
- Q_INVOKABLE MatrixDeviceList *devicesOfUser(QString userId) const;
-
- // Return true if version is at least as new as the spec version of server
- Q_INVOKABLE bool checkSpecVersion(QString version) const;
-
- // Return true if the spec version of server in the range [minVer, maxVer]
- Q_INVOKABLE bool checkSpecVersionRange(QString minVer, QString maxVer) const;
-
- Q_INVOKABLE QStringList directRoomIds(QString userId) const;
-
- Q_INVOKABLE MatrixVerificationList *verificationList() const;
-
- Kazv::RandomInterface &randomGenerator() const;
-
-private:
- // Replaces the store with another one
- void emplace(std::optional<Kazv::SdkModel> model, std::unique_ptr<KazvSessionLockGuard> lockGuard, std::unique_ptr<DbStore> dbStore);
-
- static std::string validateHomeserverUrl(const QString &url);
+ /**
+ * Get the current session.
+ */
+ Q_INVOKABLE MatrixSession *session() const;
Q_SIGNALS:
- void trigger(Kazv::KazvEvent e);
-
- void loginSuccessful(Kazv::KazvEvent e);
- void loginFailed(QString errorCode, QString errorMsg);
- void discoverFailed(QString errorCode, QString errorMsg);
- void discoverSuccessful(QString serverUrl);
- void getLoginFlowsFailed(QString errorCode, QString errorMsg);
- void getLoginFlowsSuccessful(QJsonValue flows);
- void ssoLoginTokenAvailable();
- void logoutSuccessful();
- void logoutFailed(QString errorCode, QString errorMsg);
-
- void receivedMessage(QString roomId, QString eventId);
-
void sessionChanged();
- void loadSessionFinished(QString sessionName, MatrixSdk::LoadSessionResult result);
+ void loadSessionFinished(QString sessionName, Constants::LoadSessionResult result);
void dbResolved(bool success);
public Q_SLOTS:
- void login(const QString &userId, const QString &password, const QString &homeserverUrl);
-
- /**
- * Auto-discover the server url and then get the login flows from the server.
- *
- * If homeserverUrl is not provided, try to get it from auto-discovery.
- * If discovery is successful, or it is already provided, get the login flows
- * by calling getLoginFlows.
- */
- void discoverAndGetLoginFlows(const QString &userId, const QString &homeserverUrl);
- void getLoginFlows(const QString &serverUrl);
-
- /**
- * Start SSO login flow.
- *
- * It will start an http server on a local port and pass it as
- * the redirect url to the SSO login link.
- *
- * When the user completes the SSO login flow, we get the login token
- * for us to login via the token flow.
- *
- * @return The SSO login link for the user to open.
- */
- QUrl ssoLoginStart(const QString &homeserverUrl);
- void logout();
/**
* Serialize data to <AppDataDir>/sessions/<userid>/<deviceid>/
@@ -217,181 +104,13 @@
*/
QStringList allSessions() const;
- /**
- * Create a new room.
- *
- * @param isPrivate Whether the room is private.
- * @param name The room's name.
- * @param alias The alias of the room.
- * @param invite List of matrix ids of users to invite.
- * @param isDirect Whether it is a direct message room.
- * @param allowFederate Whether to allow users on other servers to join.
- * @param topic The topic of the room.
- * @param powerLevelContentOverride The content to override m.room.power_levels event.
- * @param preset The preset to create the room with.
- * @param encrypted Whether to enable encryption for this room.
- */
- MatrixPromise *createRoom(
- bool isPrivate,
- const QString &name,
- const QString &alias,
- const QStringList &invite,
- bool isDirect,
- bool allowFederate,
- const QString &topic,
- const QJsonValue &powerLevelContentOverride,
- CreateRoomPreset preset,
- bool encrypted
- );
-
- /**
- * Join a room.
- * @param idOrAlias The id or alias of the room to join.
- * @param servers The servers to use when joining the room.
- */
- MatrixPromise *joinRoom(
- const QString &idOrAlias,
- const QStringList &servers
- );
-
- /**
- * Change the trust level of a device.
- *
- * @param userId The user id that owns the device.
- * @param deviceId The device id to set the trust level.
- * @param trustLevel The trust level.
- *
- * @return A MatrixPromise representing the progress.
- */
- MatrixPromise *setDeviceTrustLevel(QString userId, QString deviceId, QString trustLevel);
-
- /**
- * Get the profile of the current user.
- *
- * @return A MatrixPromise representing the progress.
- */
- MatrixPromise *getSelfProfile();
-
- /**
- * Set the display name of the current user.
- *
- * @return A MatrixPromise representing the progress.
- */
- MatrixPromise *setDisplayName(QString displayName);
-
- /**
- * Set the avatar url of the current user.
- *
- * @return A MatrixPromise representing the progress.
- */
- MatrixPromise *setAvatarUrl(QString avatarUrl);
-
- /**
- * Check if an event should be notified.
- *
- * @param event The event to check.
- * @return Whether `event` should be notified.
- */
- bool shouldNotify(MatrixEvent *event) const;
-
- /**
- * Check if an event should be notified with sound.
- *
- * You should only call this method when `shouldNotify(event)`
- * returns true.
- *
- * @param event The event to check.
- * @return Whether `event` should be notified with sound.
- */
- bool shouldPlaySound(MatrixEvent *event) const;
-
- /**
- * Get the sticker pack list for the current account.
- *
- * @return A list of sticker packs associated with the current account.
- */
- MatrixStickerPackList *stickerPackList() const;
-
- /**
- * Get the sticker rooms account data event for the current account.
- *
- * @return A MatrixEvent representing the sticker rooms account data event.
- */
- MatrixEvent *stickerRoomsEvent() const;
-
- /**
- * Update the sticker pack from source.
- *
- * @param source The source of the sticker pack to update.
- * @return A promise that resolves when the sticker pack is updated,
- * or when there is an error.
- */
- MatrixPromise *updateStickerPack(MatrixStickerPackSource source);
-
- MatrixUserGivenAttrsMap *userGivenNicknameMap() const;
-
- MatrixPromise *sendAccountData(const QString &type, const QJsonObject &content);
-
- /**
- * Get all Matrix Spec versions supported by the server.
- * Use MatrixSdk::supportSpecVersion() to check if a version is supported.
- */
- MatrixPromise *getSpecVersions();
-
- MatrixPromise *addDirectRoom(const QString &userId, const QString &roomId);
-
- MatrixPromise *getRoomIdByAlias(const QString &roomAlias);
-
- /**
- * Purge events in all rooms except those specified in roomIds
- *
- * @param roomIds The ids for rooms to NOT be purged. This allows
- * keeping the rooms that are already open intact.
- * @return A MatrixPromise that resolves when the events are purged.
- */
- MatrixPromise *purgeEventsExceptRooms(const QStringList &roomIds);
-
- /**
- * Backfill from the event storage from an existing event in a room.
- *
- * @param roomId The id of the room to operate on.
- * @param eventId The id of the event to backfill from.
- * @return A MatrixPromise that resolves when the events are backfilled.
- * The Promise is considered successful if and only if at least one event
- * is loaded.
- */
- MatrixPromise *backfillRoomFromEvent(const QString &roomId, const QString &eventId);
-
- /**
- * Import from key backup file.
- *
- * @param fileUrl The url of the key backup file. Will be passed to
- * QUrl::toLocalFile(), and must be a local file.
- * @param password The password to decrypt the key backup file.
- * @return A MatrixPromise that resolves when the keys are imported.
- * If successful, `data["imported"]` contains the number of imported keys.
- * If unsuccessful, `data` contains a standard error structure.
- */
- MatrixPromise *importFromKeyBackupFile(QUrl fileUrl, QString password);
-
- /**
- * Send an outbound device verification request.
- *
- * @param userId The user id of the device to verify.
- * @param deviceId The device id of the device to verify.
- */
- MatrixPromise *requestVerifyDevice(QString userId, QString deviceId);
+ void startThread();
-private:
- MatrixPromise *sendAccountDataImpl(Kazv::Event event);
+private Q_SLOTS:
+ void handleLoadSessionResult(QString sessionName, Constants::LoadSessionResult result);
private: // Testing
- friend MatrixSdkTest;
friend MatrixSdkSessionsTest;
- friend MatrixSdk *makeTestSdk(Kazv::SdkModel model);
void setUserDataDir(const std::string &userDataDir);
-
- explicit MatrixSdk(Kazv::SdkModel model, bool testing = false, QObject *parent = 0);
- void startThread();
};
diff --git a/src/matrix-sdk.cpp b/src/matrix-sdk.cpp
--- a/src/matrix-sdk.cpp
+++ b/src/matrix-sdk.cpp
@@ -6,161 +6,69 @@
#include <kazv-defs.hpp>
-#include <boost/archive/text_oarchive.hpp>
-#include <boost/archive/text_iarchive.hpp>
-#include <fstream>
-#include <filesystem>
-#include <chrono>
-
-#include <QMutex>
-#include <QMutexLocker>
#include <QtConcurrent>
-#include <QThreadPool>
-#include <KConfig>
-#include <KConfigGroup>
-#include <QCoroTask>
-#include <eventemitter/lagerstoreeventemitter.hpp>
-#include <client/sdk.hpp>
#include <client/notification-handler.hpp>
#include <crypto/base64.hpp>
-#include <csapi/directory.hpp>
-#include <client/alias.hpp>
-#include <csapi/login.hpp>
#include <zug/util.hpp>
#include <lager/event_loop/qt.hpp>
#include "matrix-sdk.hpp"
-#include "matrix-room-list.hpp"
#include "matrix-promise.hpp"
#include "matrix-event.hpp"
+#include "matrix-session-types.hpp"
#include "helper.hpp"
#include "kazv-path-config.hpp"
#include "kazv-version.hpp"
#include "qt-json.hpp"
#include "qt-rand-adapter.hpp"
-#include "qt-promise-handler.hpp"
#include "qt-job-handler.hpp"
-#include "device-mgmt/matrix-device-list.hpp"
-#include "matrix-sticker-pack-list.hpp"
-#include "matrix-sticker-pack-list-p.hpp"
-#include "matrix-user-given-attrs-map.hpp"
#include "kazv-log.hpp"
#include "matrix-utils.hpp"
+#include "matrix-session-controller.hpp"
#include "kazv-session-lock-guard.hpp"
#include "db-store.hpp"
-#include "sso-login-process.hpp"
-#include "matrix-verification-list.hpp"
using namespace Qt::Literals::StringLiterals;
using namespace Kazv;
-static const std::string clientName = "kazv";
-
-// Sdk with qt event loop, identity transform and no enhancers
-using SdkT =
- decltype(makeSdk(
- SdkModel{},
- detail::declref<JobInterface>(),
- detail::declref<EventInterface>(),
- QtPromiseHandler(detail::declref<QObject>()),
- zug::identity,
- withRandomGenerator(detail::declref<RandomInterface>())));
-
-struct QtEventLoop
-{
- QObject *m_obj;
-
- template<class Fn>
- void async(Fn &&) { throw std::runtime_error{"not implemented!"}; }
-
- template<class Fn>
- void post(Fn &&fn)
- {
- QMetaObject::invokeMethod(
- m_obj, std::forward<Fn>(fn), Qt::QueuedConnection
- );
- }
-
- void finish() {}
- void pause() { throw std::runtime_error{"not implemented!"}; }
- void resume() { throw std::runtime_error{"not implemented!"}; }
-};
-
-QCoro::Task<std::pair<bool, QString>> setupAndImport(SdkModel model, DbStore *dbStore, std::string userDataDir)
-{
- auto res = co_await dbStore->setup(
- userDataDir,
- model.c().userId,
- model.c().deviceId
- );
- if (!res.first) {
- co_return res;
- }
- co_return co_await dbStore->importAllFrom(model);
-}
-
-std::filesystem::path sessionDirForUserAndDeviceId(std::filesystem::path userDataDir, std::string userId, std::string deviceId)
-{
- auto encodedUserId = encodeBase64(userId, Base64Opts::urlSafe);
- auto sessionDir = userDataDir / "sessions"
- / encodedUserId / deviceId;
- return sessionDir;
-}
-
-struct PendingSaveEvents : public SaveEventsRequested
+struct MatrixSdkPrivate
{
- using DataT = immer::map<std::string, EventList>;
- void add(SaveEventsRequested s)
+ MatrixSdkPrivate(MatrixSdk *q)
+ : q(q)
+ , userDataDir(kazvUserDataDir().toStdString())
+ , thread(new QThread())
+ , controller(new MatrixSessionController(thread, userDataDir))
{
- timelineEvents = addOneType(std::move(timelineEvents), s.timelineEvents);
- nonTimelineEvents = addOneType(std::move(nonTimelineEvents), s.nonTimelineEvents);
}
- static DataT addOneType(DataT orig, DataT addon)
+ ~MatrixSdkPrivate()
{
- for (const auto &[roomId, el]: addon) {
- orig = std::move(orig).update(roomId, [&el](EventList origEl) {
- // This works without explicit dedupe because we do not do parallel
- // inserts and the insert order is the same as list order.
- return origEl + el;
- });
+ if (controller) {
+ controller->prepareDestroy();
+ controller->save();
}
- return orig;
+ thread->quit();
+ thread->wait();
+ thread->deleteLater();
}
-};
-enum DbStatus
-{
- Pending,
- Ready,
- Failed,
-};
-
-struct MatrixSdkPrivate
-{
- MatrixSdkPrivate(MatrixSdk *q, bool testing, std::unique_ptr<KazvSessionLockGuard> lockGuard, std::unique_ptr<DbStore> dbStore);
- MatrixSdkPrivate(MatrixSdk *q, bool testing, SdkModel model, std::unique_ptr<KazvSessionLockGuard> lockGuard, std::unique_ptr<DbStore> dbStore);
- bool testing;
+ MatrixSdk *q;
std::string userDataDir;
- std::unique_ptr<KazvSessionLockGuard> lockGuard;
- RandomInterface randomGenerator;
- std::unique_ptr<DbStore> dbStore;
QThread *thread;
- QObject *obj;
- QtJobHandler *jobHandler;
- LagerStoreEventEmitter ee;
- LagerStoreEventEmitter::Watchable watchable;
- SdkT sdk;
+ UniquePtrDL<MatrixSessionController> controller;
QTimer saveTimer;
- QPointer<SsoLoginProcess> ssoLoginProcess{};
- using SecondaryRootT = decltype(sdk.createSecondaryRoot(std::declval<lager::with_qt_event_loop>()));
- SecondaryRootT secondaryRoot;
- Client clientOnSecondaryRoot;
- NotificationHandler notificationHandler;
- DbStatus dbStatus;
- PendingSaveEvents pendingSaveEvents{};
- lager::state<VerificationTrackerModel> verificationTrackerState;
+ void emplaceController()
+ {
+ if (controller) {
+ controller->prepareDestroy();
+ controller->save();
+ }
+ controller.reset(new MatrixSessionController(thread, userDataDir));
+ Q_EMIT q->sessionChanged();
+ QObject::connect(controller.get(), &MatrixSessionController::loadSessionFinished, q, &MatrixSdk::loadSessionFinished);
+ QObject::connect(controller.get(), &MatrixSessionController::sessionReady, q, &MatrixSdk::sessionChanged);
+ }
void runIoContext() {
thread->start();
@@ -171,618 +79,37 @@
void maybeSerialize()
{
- if (!testing) {
- serializeClientToFile(clientOnSecondaryRoot);
- }
- }
-
- void serializeClientToFile(Client c);
-
- void saveOrQueueEvents(SaveEventsRequested s)
- {
- if (dbStatus == Ready) {
- saveEvents(std::move(s));
- } else if (dbStatus == Pending) {
- pendingSaveEvents.add(std::move(s));
- }
- // Database open failed, do not do anything
- }
-
- void saveEvents(SaveEventsRequested s)
- {
- dbStore->saveEvents(std::move(s))
- .then([](const auto &stat) {
- if (!stat.first) {
- qCWarning(kazvLog) << "Cannot save events:" << stat.second;
- }
- });
- }
-};
-
-// Cleaning up notes:
-// 0. Callback functions may store the context for an indefinite time
-// 1. The QThread event loop can be stopped
-// 2. QtJobHandler::submit() should only happen in the primary event loop thread
-// 3. QtJobHandler lives in the primary event loop thread
-// 4. QtJobs live in the primary event loop thread
-// 5. Job callbacks are called in the primary event loop thread
-// 6. QtPromise::then() callbacks are called in the primary event loop thread
-// 7. When the QThread event loop stops, no more callbacks will be executed (there is nothing to post to)
-// 8. The QThread should stop before obj is deleted
-class CleanupHelper : public QObject
-{
- Q_OBJECT
-public:
- explicit CleanupHelper(std::unique_ptr<MatrixSdkPrivate> d)
- : oldD(std::move(d))
- {
- }
-
- std::unique_ptr<MatrixSdkPrivate> oldD;
-
- void cleanup()
- {
- qCInfo(kazvLog) << "start to clean up everything";
- if (oldD->ssoLoginProcess) {
- oldD->ssoLoginProcess->deleteLater();
- }
-
- oldD->clientOnSecondaryRoot.stopSyncing()
- .then([obj=oldD->obj, thread=oldD->thread](auto &&) {
- qCDebug(kazvLog) << "stopped syncing";
- QMetaObject::invokeMethod(obj, [thread]() {
- thread->quit();
- });
- });
- oldD->thread->wait();
- oldD->thread->deleteLater();
- // After the thread's event loop is finished, we can delete the root object
- oldD->obj->deleteLater();
- this->deleteLater();
- qCInfo(kazvLog) << "thread is done";
+ controller->save();
}
};
-void MatrixSdkPrivate::serializeClientToFile(Client c)
-{
- using namespace Kazv::CursorOp;
- auto userId = +c.userId();
- auto deviceId = +c.deviceId();
- if (userId.empty() || deviceId.empty()) {
- qDebug() << "Not logged in, nothing to serialize";
- return;
- }
-
- using StdPath = std::filesystem::path;
- auto userDataDir = StdPath(this->userDataDir);
- auto sessionDir = sessionDirForUserAndDeviceId(userDataDir, userId, deviceId);
-
- auto storeFile = sessionDir / "store";
- auto storeFileNew = sessionDir / "store.new";
-
- auto metadataFile = sessionDir / "metadata";
-
- qDebug() << "storeFile=" << QString::fromStdString(storeFile.string());
-
- std::error_code err;
- if ((! std::filesystem::create_directories(sessionDir, err))
- && err) {
- qDebug() << "Unable to create sessionDir";
- return;
- }
-
- if (!lockGuard) {
- try {
- lockGuard = std::make_unique<KazvSessionLockGuard>(sessionDir);
- } catch (const std::runtime_error &e) {
- qCWarning(kazvLog) << "Error locking session: " << e.what();
- return;
- }
- }
-
- try {
- auto storeStream = std::ofstream(storeFileNew);
- if (! storeStream) {
- qCWarning(kazvLog) << "Unable to open storeFile";
- return;
- }
- using OAr = boost::archive::text_oarchive;
- auto archive = OAr{storeStream};
- c.serializeTo(archive);
- } catch (const std::exception &e) {
- qCWarning(kazvLog) << "Cannot write to store file: " << e.what();
- return;
- }
-
- err.clear();
- std::filesystem::rename(storeFileNew, storeFile, err);
- if (err) {
- qCWarning(kazvLog) << "Cannot move storeFile into place: " << QString::fromStdString(err.message());
- return;
- }
- qDebug() << "Serialization done";
-
-
- // store metadata
- {
- KConfig metadata(QString::fromStdString(metadataFile.string()));
- KConfigGroup mdGroup(&metadata, u"Metadata"_s);
- mdGroup.writeEntry("kazvVersion", QString::fromStdString(kazvVersionString()));
- mdGroup.writeEntry("archiveFormat", "text-with-sqlite");
- }
-}
-
-MatrixSdkPrivate::MatrixSdkPrivate(MatrixSdk *q, bool testing, std::unique_ptr<KazvSessionLockGuard> lockGuard, std::unique_ptr<DbStore> dbStore)
- : testing(testing)
- , userDataDir{kazvUserDataDir().toStdString()}
- , lockGuard(std::move(lockGuard))
- , randomGenerator(QtRandAdapter{})
- , dbStore(std::move(dbStore))
- , thread(new QThread())
- , obj(new QObject())
- , jobHandler(new QtJobHandler(obj))
- , ee{QtEventLoop{obj}}
- , watchable(ee.watchable())
- , sdk(makeDefaultSdkWithCryptoRandom(
- randomGenerator.generateRange<std::string>(makeDefaultSdkWithCryptoRandomSize()),
- static_cast<JobInterface &>(*jobHandler),
- static_cast<EventInterface &>(ee),
- QtPromiseHandler(*obj),
- zug::identity,
- withRandomGenerator(randomGenerator)))
- , secondaryRoot(sdk.createSecondaryRoot(QtEventLoop{q}))
- , clientOnSecondaryRoot(sdk.clientFromSecondaryRoot(secondaryRoot))
- , notificationHandler(clientOnSecondaryRoot.notificationHandler())
- , dbStatus(this->dbStore ? Ready : Pending)
-{
- obj->moveToThread(thread);
-}
-
-MatrixSdkPrivate::MatrixSdkPrivate(MatrixSdk *q, bool testing, SdkModel model, std::unique_ptr<KazvSessionLockGuard> lockGuard, std::unique_ptr<DbStore> dbStore)
- : testing(testing)
- , userDataDir{kazvUserDataDir().toStdString()}
- , lockGuard(std::move(lockGuard))
- , randomGenerator(QtRandAdapter{})
- , dbStore(std::move(dbStore))
- , thread(new QThread())
- , obj(new QObject())
- , jobHandler(new QtJobHandler(obj))
- , ee{QtEventLoop{obj}}
- , watchable(ee.watchable())
- , sdk(makeSdk(
- model,
- static_cast<JobInterface &>(*jobHandler),
- static_cast<EventInterface &>(ee),
- QtPromiseHandler(*obj),
- zug::identity,
- withRandomGenerator(randomGenerator)))
- , secondaryRoot(sdk.createSecondaryRoot(QtEventLoop{q}, std::move(model)))
- , clientOnSecondaryRoot(sdk.clientFromSecondaryRoot(secondaryRoot))
- , notificationHandler(clientOnSecondaryRoot.notificationHandler())
- , dbStatus(this->dbStore ? Ready : Pending)
-{
- obj->moveToThread(thread);
-}
-
MatrixSdk::MatrixSdk(std::unique_ptr<MatrixSdkPrivate> d, QObject *parent)
: QObject(parent)
, m_d(std::move(d))
{
init();
- connect(this, &MatrixSdk::trigger,
- this, [this](KazvEvent e) {
- if (std::holds_alternative<SaveEventsRequested>(e)) {
- auto s = std::get<SaveEventsRequested>(e);
- m_d->saveOrQueueEvents(s);
- }
- });
-
- // loginSuccessful will be emitted only for new sessions (not for loaded
- // sessions),
- connect(this, &MatrixSdk::loginSuccessful, this, [this]() {
- if (m_d->dbStore) {
- qCWarning(kazvLog) << "Trying to replace current db store, ignoring";
- return;
- }
- m_d->dbStore = std::make_unique<DbStore>();
- // This must be called from the GUI thread
- auto model = m_d->secondaryRoot.get();
- setupAndImport(std::move(model), m_d->dbStore.get(), m_d->userDataDir)
- .then([this](const auto &stat) {
- if (!stat.first) {
- qCWarning(kazvLog) << "Cannot set up database:" << stat.second;
- }
- Q_EMIT dbResolved(stat.first);
- });
- });
-
- connect(this, &MatrixSdk::dbResolved, this, [this](bool success) {
- if (!success) {
- m_d->dbStatus = Failed;
- } else {
- qCDebug(kazvLog) << "db loading succeeded";
- auto pendingSaveEvents = std::move(m_d->pendingSaveEvents);
- m_d->pendingSaveEvents = {};
- m_d->saveEvents(std::move(pendingSaveEvents));
- m_d->dbStatus = Ready;
- }
- });
}
void MatrixSdk::init()
{
- LAGER_QT(serverUrl) = m_d->clientOnSecondaryRoot.serverUrl().xform(strToQt); Q_EMIT serverUrlChanged(serverUrl());
- LAGER_QT(userId) = m_d->clientOnSecondaryRoot.userId().xform(strToQt); Q_EMIT userIdChanged(userId());
- LAGER_QT(token) = m_d->clientOnSecondaryRoot.token().xform(strToQt); Q_EMIT tokenChanged(token());
- LAGER_QT(deviceId) = m_d->clientOnSecondaryRoot.deviceId().xform(strToQt); Q_EMIT deviceIdChanged(deviceId());
- LAGER_QT(specVersions) = m_d->clientOnSecondaryRoot.supportVersions(); Q_EMIT specVersionsChanged(specVersions());
-
- m_d->watchable.afterAll(
- [this](KazvEvent e) {
- Q_EMIT this->trigger(e);
- });
-
- m_d->watchable.after<LoginSuccessful>(
- [this](LoginSuccessful e) {
- Q_EMIT this->loginSuccessful(e);
- });
-
- m_d->watchable.after<LoginFailed>(
- [this](LoginFailed e) {
- Q_EMIT this->loginFailed(
- QString::fromStdString(e.errorCode),
- QString::fromStdString(e.error)
- );
- });
-
- m_d->watchable.after<ReceivingRoomTimelineEvent>(
- [this](ReceivingRoomTimelineEvent e) {
- Q_EMIT this->receivedMessage(
- QString::fromStdString(e.roomId),
- QString::fromStdString(e.event.id())
- );
- });
-
- m_d->watchable.after<VerificationTrackerModelChanged>(
- [this](VerificationTrackerModelChanged) {
- auto model = lager::get<VerificationTracker>(m_d->sdk.context()).model;
- QMetaObject::invokeMethod(
- this, [this, model=std::move(model)]() {
- qCDebug(kazvLog) << "Verification tracker model changed" << model.processes.size();
- m_d->verificationTrackerState.set(model);
- lager::commit(m_d->verificationTrackerState);
- });
- }
- );
-
connect(&m_d->saveTimer, &QTimer::timeout, &m_d->saveTimer, [m_d=m_d.get()]() {
m_d->maybeSerialize();
});
const int saveIntervalMs = 1000 * 60 * 5;
m_d->saveTimer.start(std::chrono::milliseconds{saveIntervalMs});
-}
-MatrixSdk::MatrixSdk(QObject *parent)
- : MatrixSdk(std::make_unique<MatrixSdkPrivate>(
- this,
- /* testing = */ false,
- std::unique_ptr<KazvSessionLockGuard>(),
- std::unique_ptr<DbStore>()
- ), parent)
-{
+ connect(this, &MatrixSdk::loadSessionFinished, this, &MatrixSdk::handleLoadSessionResult);
}
-MatrixSdk::MatrixSdk(SdkModel model, bool testing, QObject *parent)
+MatrixSdk::MatrixSdk(QObject *parent)
: MatrixSdk(std::make_unique<MatrixSdkPrivate>(
- this,
- testing,
- std::move(model),
- std::unique_ptr<KazvSessionLockGuard>(),
- std::unique_ptr<DbStore>()
+ this
), parent)
{
}
-static void cleanupDPointer(std::unique_ptr<MatrixSdkPrivate> oldD)
-{
- oldD->saveTimer.disconnect();
- oldD->saveTimer.stop();
-
- auto helper = new CleanupHelper(std::move(oldD));
- helper->cleanup();
-}
-
MatrixSdk::~MatrixSdk()
{
- if (m_d) {
- serializeToFile();
- cleanupDPointer(std::move(m_d));
- }
-}
-
-QString MatrixSdk::mxcUriToHttp(QString mxcUri) const
-{
- return QString::fromStdString(m_d->clientOnSecondaryRoot.mxcUriToHttp(mxcUri.toStdString()));
-}
-
-QString MatrixSdk::mxcUriToHttpAuthenticatedV1(QString mxcUri) const
-{
- return QString::fromStdString(m_d->clientOnSecondaryRoot.mxcUriToHttpV1(mxcUri.toStdString()));
-}
-
-MatrixDeviceList *MatrixSdk::devicesOfUser(QString userId) const
-{
- return new MatrixDeviceList(m_d->clientOnSecondaryRoot.devicesOfUser(userId.toStdString()));
-}
-
-bool isIllFormatSpecVersion(const QString &version)
-{
- const bool isLegacy = version.startsWith(u"r"_s);
- if (isLegacy && version.split(u'.').size() == 3) {
- return false;
- }
- if (!isLegacy && version.split(u'.').size() == 2) {
- return false;
- }
- return true;
-}
-
-// Return true if v1 is at least as new as v2, false if v1 is older than v2
-// Return false if v1 or v2 is ill-format
-bool compareSpecVersion(QString v1, QString v2)
-{
- // Check parameters format
- if (isIllFormatSpecVersion(v1) || isIllFormatSpecVersion(v2)) {
- return false;
- }
-
- const bool v1IsLegacy = v1.startsWith(u"r"_s);
- const bool v2IsLegacy = v2.startsWith(u"r"_s);
- if (v1IsLegacy != v2IsLegacy) {
- return v2IsLegacy;
- }
-
- v1.remove(0, 1);
- v2.remove(0, 1);
- auto v1VersionNumbers = v1.split(u'.');
- auto v2VersionNumbers = v2.split(u'.');
-
- for (int i = 0; i < v1VersionNumbers.size(); i++) {
- auto v1VerNum = v1VersionNumbers[i].toInt();
- auto v2VerNum = v2VersionNumbers[i].toInt();
- if (v1VerNum != v2VerNum) {
- return v1VerNum > v2VerNum;
- }
- }
- // v1 is equal to v2
- return true;
-}
-
-// Return true if version in the range [minVer, maxVer]
-// Return false if any parameter is ill-format
-bool compareSpecVersionRange(const QString &version,
- const QString &minVer, const QString &maxVer)
-{
- if (isIllFormatSpecVersion(version)
- || isIllFormatSpecVersion(minVer)
- || isIllFormatSpecVersion(maxVer)) {
- return false;
- }
-
- if (compareSpecVersion(version, minVer) && compareSpecVersion(maxVer, version)) {
- return true;
- }
-
- return false;
-}
-
-bool MatrixSdk::checkSpecVersion(QString version) const
-{
- return std::find_if(specVersions().begin(), specVersions().end(),
- [&version](auto v) {
- return compareSpecVersion(QString::fromStdString(v), version);
- }) != specVersions().end();
-}
-
-bool MatrixSdk::checkSpecVersionRange(QString minVer, QString maxVer) const
-{
- return std::find_if(specVersions().begin(), specVersions().end(),
- [&minVer, maxVer](auto v) {
- return compareSpecVersionRange(QString::fromStdString(v), minVer, maxVer);
- }) != specVersions().end();
-}
-
-QStringList MatrixSdk::directRoomIds(QString userId) const
-{
- auto content = m_d->clientOnSecondaryRoot.accountData().get()["m.direct"].content().get();
- auto roomIds = QStringList{};
- for (auto i : content[userId.toStdString()]) {
- roomIds.push_back(QString::fromStdString(i.get<std::string>()));
- }
- return roomIds;
-}
-
-MatrixVerificationList *MatrixSdk::verificationList() const
-{
- return new MatrixVerificationList(m_d->clientOnSecondaryRoot, m_d->verificationTrackerState);
-}
-
-std::string MatrixSdk::validateHomeserverUrl(const QString &url)
-{
- if (url.isEmpty()) {
- return std::string();
- }
-
- auto u = QUrl::fromUserInput(url);
- if (!u.isValid()) {
- return std::string();
- }
-
- if (u.scheme() == u"http"_s) {
- qCInfo(kazvLog) << "url" << u << "is http. Force switching to https.";
- u.setScheme(u"https"_s);
- } else if (u.scheme() != u"https"_s) {
- qCWarning(kazvLog) << "url" << u << "is not http/https.";
- return std::string();
- }
-
- return u.toString().toStdString();
-}
-
-void MatrixSdk::login(const QString &userId, const QString &password, const QString &homeserverUrl)
-{
- auto loginFunc = [userId, password](const Client &client, const std::string &serverUrl) {
- client.passwordLogin(
- serverUrl,
- userId.toStdString(),
- password.toStdString(),
- clientName
- );
- };
-
- auto validated = validateHomeserverUrl(homeserverUrl);
- if (!validated.empty()) {
- loginFunc(m_d->clientOnSecondaryRoot, validated);
- } else {
- m_d->clientOnSecondaryRoot
- .autoDiscover(userId.toStdString()) // autoDiscover() will dispatch GetVersionAction to get supported versions of the server
- .then([
- this,
- client=m_d->clientOnSecondaryRoot.toEventLoop(),
- userId,
- password,
- loginFunc
- ](auto res) {
- if (!res.success()) {
- // FIXME use real error codes and msgs when available in libkazv
- Q_EMIT this->discoverFailed(u""_s, u""_s);
- return res;
- }
-
- auto serverUrl = res.dataStr("homeserverUrl");
-
- loginFunc(client, serverUrl);
-
- return res;
- });
- }
-
- m_d->runIoContext();
-}
-
-void MatrixSdk::discoverAndGetLoginFlows(const QString &userId, const QString &homeserverUrl)
-{
- auto validated = validateHomeserverUrl(homeserverUrl);
- if (!validated.empty()) {
- getLoginFlows(homeserverUrl);
- } else {
- m_d->clientOnSecondaryRoot
- .autoDiscover(userId.toStdString())
- .then([
- this
- ](const EffectStatus &res) {
- if (!res.success()) {
- Q_EMIT discoverFailed(
- QString::fromStdString(res.dataStr("errorCode")),
- QString::fromStdString(res.dataStr("error"))
- );
- return;
- }
- auto serverUrl = QString::fromStdString(res.dataStr("homeserverUrl"));
- Q_EMIT discoverSuccessful(serverUrl);
- getLoginFlows(serverUrl);
- });
- }
-
- m_d->runIoContext();
-}
-
-void MatrixSdk::getLoginFlows(const QString &serverUrl)
-{
- m_d->jobHandler->submit(
- Api::GetLoginFlowsJob(serverUrl.toStdString()),
- [this](Api::GetLoginFlowsResponse r) {
- if (!r.success()) {
- Q_EMIT getLoginFlowsFailed(
- QString::fromStdString(r.errorCode()),
- QString::fromStdString(r.errorMessage())
- );
- return;
- }
- auto v = std::move(r).jsonBody().get().at("flows").template get<QJsonValue>();
- Q_EMIT getLoginFlowsSuccessful(v);
- }
- );
-}
-
-QUrl MatrixSdk::ssoLoginStart(const QString &homeserverUrl)
-{
- if (m_d->ssoLoginProcess) {
- m_d->ssoLoginProcess->deleteLater();
- }
- m_d->ssoLoginProcess = new SsoLoginProcess();
- if (!m_d->ssoLoginProcess->startServer()) {
- return QUrl();
- }
- auto link = m_d->ssoLoginProcess->getSsoLink(homeserverUrl);
- connect(m_d->ssoLoginProcess.get(), &SsoLoginProcess::loginTokenAvailable,
- this, [this, homeserverUrl](const QString &loginToken) {
- Q_EMIT ssoLoginTokenAvailable();
- qCInfo(kazvLog) << "Got SSO login token";
- m_d->ssoLoginProcess->deleteLater();
- m_d->clientOnSecondaryRoot.mLoginTokenLogin(
- homeserverUrl.toStdString(),
- loginToken.toStdString(),
- clientName
- );
- });
- return link;
-}
-
-void MatrixSdk::logout()
-{
- m_d->clientOnSecondaryRoot.logout()
- .then([&] (EffectStatus stat) {
- if (stat.success()) {
- m_d->stopIoContext();
- Q_EMIT this->logoutSuccessful();
- } else {
- Q_EMIT this->logoutFailed(QString::fromStdString(stat.dataStr("errorCode")), QString::fromStdString(stat.dataStr("error")));
- }
- });
-}
-
-MatrixRoomList *MatrixSdk::roomList() const
-{
- return new MatrixRoomList(m_d->clientOnSecondaryRoot);
-}
-
-void MatrixSdk::emplace(std::optional<SdkModel> model, std::unique_ptr<KazvSessionLockGuard> lockGuard, std::unique_ptr<DbStore> dbStore)
-{
- auto testing = m_d->testing;
- auto userDataDir = m_d->userDataDir;
-
- if (m_d) {
- cleanupDPointer(std::move(m_d));
- }
-
- m_d = model.has_value()
- ? std::make_unique<MatrixSdkPrivate>(
- this, testing, std::move(model.value()),
- std::move(lockGuard), std::move(dbStore))
- : std::make_unique<MatrixSdkPrivate>(
- this, testing, std::move(lockGuard), std::move(dbStore)
- );
- m_d->userDataDir = userDataDir;
-
- // Re-initialize lager-qt cursors and watchable connections
- init();
-
- m_d->runIoContext();
-
- m_d->clientOnSecondaryRoot.startSyncing();
-
- Q_EMIT sessionChanged();
}
QStringList MatrixSdk::allSessions() const
@@ -825,100 +152,8 @@
void MatrixSdk::loadSession(QString sessionName)
{
- using StdPath = std::filesystem::path;
- auto loadFromSession = [this, sessionName](StdPath sessionDir, std::unique_ptr<KazvSessionLockGuard> lockGuard) {
- auto storeFile = sessionDir / "store";
-
- auto metadataFile = sessionDir / "metadata";
-
- if (! std::filesystem::exists(storeFile)) {
- qDebug() << "storeFile does not exist, skip loading session " << sessionName;
- Q_EMIT loadSessionFinished(sessionName, SessionNotFound);
- return;
- }
-
- if (std::filesystem::exists(metadataFile)) {
- KConfig metadata(QString::fromStdString(metadataFile.string()));
- KConfigGroup mdGroup(&metadata, u"Metadata"_s);
- auto format = mdGroup.readEntry(u"archiveFormat"_s);
- if (format != u"text"_s && format != u"text-with-sqlite"_s) {
- qDebug() << "Unknown archive format:" << format;
- Q_EMIT loadSessionFinished(sessionName, SessionFormatUnknown);
- return;
- }
- auto version = mdGroup.readEntry(u"kazvVersion"_s);
- auto curVersion = kazvVersionString();
- if (version != QString::fromStdString(curVersion)) {
- qDebug() << "A different version from the current one, making a backup";
- std::error_code err;
- auto now = std::chrono::system_clock::now();
- auto backupName =
- std::to_string(std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count());
- auto backupDir = sessionDir / "backup" / backupName;
- if (! std::filesystem::create_directories(backupDir, err)
- && err) {
- qDebug() << "Cannot create backup directory";
- Q_EMIT loadSessionFinished(sessionName, SessionCannotBackup);
- return;
- }
- std::filesystem::copy_file(storeFile, backupDir / "store");
- std::filesystem::copy_file(metadataFile, backupDir / "metadata");
- }
- }
-
- SdkModel model;
- try {
- auto storeStream = std::ifstream(storeFile);
- if (! storeStream) {
- qDebug() << "Unable to open storeFile";
- Q_EMIT loadSessionFinished(sessionName, SessionCannotOpenFile);
- return;
- }
- using IAr = boost::archive::text_iarchive;
- auto archive = IAr{storeStream};
- archive >> model;
- qDebug() << "Finished loading session store file";
- } catch (const std::exception &e) {
- qDebug() << "Error when loading session:" << QString::fromStdString(e.what());
- Q_EMIT loadSessionFinished(sessionName, SessionDeserializeFailed);
- return;
- }
-
- auto dbStore = std::make_unique<DbStore>();
- auto stat = QCoro::waitFor(setupAndImport(model, dbStore.get(), m_d->userDataDir));
- if (!stat.first) {
- qCWarning(kazvLog) << "Unable to open db store:" << stat.second;
- Q_EMIT loadSessionFinished(sessionName, SessionDeserializeFailed);
- return;
- }
- QMetaObject::invokeMethod(this, [this, model=std::move(model), lockGuard=std::move(lockGuard), dbStore=std::move(dbStore)]() mutable {
- emplace(std::move(model), std::move(lockGuard), std::move(dbStore));
- });
- Q_EMIT loadSessionFinished(sessionName, SessionLoadSuccess);
- };
-
- qDebug() << "in loadSession(), sessionName=" << sessionName;
- auto userDataDir = StdPath(m_d->userDataDir);
- auto parts = sessionName.split(u'/');
- if (parts.size() == 2) {
- auto userId = parts[0].toStdString();
- auto deviceId = parts[1].toStdString();
- auto sessionDir = sessionDirForUserAndDeviceId(userDataDir, userId, deviceId);
- std::unique_ptr<KazvSessionLockGuard> lockGuard;
- try {
- lockGuard = std::make_unique<KazvSessionLockGuard>(sessionDir);
- } catch (const std::runtime_error &e) {
- qCWarning(kazvLog) << "Error locking session: " << e.what();
- Q_EMIT loadSessionFinished(sessionName, SessionLockFailed);
- return;
- }
- QThreadPool::globalInstance()->start([loadFromSession, sessionDir, lockGuard=std::move(lockGuard)]() mutable {
- loadFromSession(sessionDir, std::move(lockGuard));
- });
- return;
- }
- qDebug(kazvLog) << "no session found for" << sessionName;
- Q_EMIT loadSessionFinished(sessionName, SessionNotFound);
+ m_d->emplaceController();
+ m_d->controller->load(sessionName);
}
bool MatrixSdk::deleteSession(QString sessionName) {
@@ -947,283 +182,21 @@
bool MatrixSdk::startNewSession()
{
- emplace(std::nullopt, std::unique_ptr<KazvSessionLockGuard>(), std::unique_ptr<DbStore>());
+ m_d->emplaceController();
+ m_d->controller->create();
return true;
}
-static std::optional<std::string> optMaybe(QString s)
-{
- if (s.isEmpty()) {
- return std::nullopt;
- } else {
- return s.toStdString();
- }
-}
-
-MatrixPromise *MatrixSdk::createRoom(
- bool isPrivate,
- const QString &name,
- const QString &alias,
- const QStringList &invite,
- bool isDirect,
- bool allowFederate,
- const QString &topic,
- const QJsonValue &powerLevelContentOverride,
- CreateRoomPreset preset,
- bool encrypted
-)
-{
- immer::array<Event> initialState;
-
- if (encrypted) {
- initialState = {Event{json{
- {"type", "m.room.encryption"},
- {"state_key", ""},
- {"content", {
- {"algorithm", "m.megolm.v1.aes-sha2"},
- }},
- }}};
- }
-
- return new MatrixPromise(m_d->clientOnSecondaryRoot.createRoom(
- isPrivate ? Kazv::RoomVisibility::Private : Kazv::RoomVisibility::Public,
- optMaybe(name),
- optMaybe(alias),
- qStringListToStdF(invite),
- isDirect,
- allowFederate,
- optMaybe(topic),
- nlohmann::json(powerLevelContentOverride),
- static_cast<Kazv::CreateRoomPreset>(preset),
- initialState
- ));
-}
-
-MatrixPromise *MatrixSdk::joinRoom(const QString &idOrAlias, const QStringList &servers)
-{
- return new MatrixPromise(m_d->clientOnSecondaryRoot.joinRoom(
- idOrAlias.toStdString(),
- qStringListToStdF(servers)
- ));
-}
-
-MatrixPromise *MatrixSdk::setDeviceTrustLevel(QString userId, QString deviceId, QString trustLevel)
-{
- return new MatrixPromise(
- m_d->clientOnSecondaryRoot.setDeviceTrustLevel(
- userId.toStdString(),
- deviceId.toStdString(),
- qStringToTrustLevelFunc(trustLevel)
- )
- );
-}
-
-MatrixPromise *MatrixSdk::getSelfProfile()
-{
- return new MatrixPromise(
- m_d->clientOnSecondaryRoot.getProfile(userId().toStdString())
- );
-}
-
-MatrixPromise *MatrixSdk::setDisplayName(QString displayName)
-{
- return new MatrixPromise(
- m_d->clientOnSecondaryRoot.setDisplayName(
- displayName.isEmpty() ? std::nullopt : std::optional<std::string>(displayName.toStdString())
- )
- );
-}
-
-MatrixPromise *MatrixSdk::setAvatarUrl(QString avatarUrl)
-{
- return new MatrixPromise(
- m_d->clientOnSecondaryRoot.setAvatarUrl(
- avatarUrl.isEmpty() ? std::nullopt : std::optional<std::string>(avatarUrl.toStdString())
- )
- );
-}
-
void MatrixSdk::startThread()
{
m_d->runIoContext();
}
-RandomInterface &MatrixSdk::randomGenerator() const
+void MatrixSdk::handleLoadSessionResult(QString sessionName, Constants::LoadSessionResult result)
{
- return m_d->randomGenerator;
-}
-
-bool MatrixSdk::shouldNotify(MatrixEvent *event) const
-{
- // Do not notify own event
- if (event->sender() == userId()) {
- return false;
+ if (result == Constants::SessionLoadSuccess) {
+ m_d->controller->startSyncing();
}
- return m_d->notificationHandler.handleNotification(event->underlyingEvent()).shouldNotify;
-}
-
-bool MatrixSdk::shouldPlaySound(MatrixEvent *event) const
-{
- return m_d->notificationHandler.handleNotification(event->underlyingEvent()).sound.has_value();
-}
-
-MatrixStickerPackList *MatrixSdk::stickerPackList() const
-{
- return new MatrixStickerPackList(m_d->clientOnSecondaryRoot);
-}
-
-MatrixEvent *MatrixSdk::stickerRoomsEvent() const
-{
- return new MatrixEvent(m_d->clientOnSecondaryRoot.accountData()[imagePackRoomsEventType][lager::lenses::or_default]);
-}
-
-MatrixPromise *MatrixSdk::updateStickerPack(MatrixStickerPackSource source)
-{
- if (source.source == MatrixStickerPackSource::AccountData) {
- auto eventJson = std::move(source.event).raw().get();
- eventJson["type"] = source.eventType;
- return sendAccountDataImpl(Event(std::move(eventJson)));
- } else if (source.source == MatrixStickerPackSource::RoomState) {
- auto eventJson = std::move(source.event).raw().get();
- eventJson["type"] = source.eventType;
- eventJson["state_key"] = source.stateKey;
- return new MatrixPromise(
- m_d->clientOnSecondaryRoot
- .room(source.roomId)
- .sendStateEvent(Event(std::move(eventJson))));
- } else {
- return 0;
- }
-}
-
-MatrixUserGivenAttrsMap *MatrixSdk::userGivenNicknameMap() const
-{
- return new MatrixUserGivenAttrsMap(
- userGivenNicknameMapFor(m_d->clientOnSecondaryRoot),
- [client=m_d->clientOnSecondaryRoot](json content) {
- return client.setAccountData(json{
- {"type", USER_GIVEN_NICKNAME_EVENT_TYPES[0]},
- {"content", std::move(content)},
- });
- }
- );
-}
-
-MatrixPromise *MatrixSdk::sendAccountData(const QString &type, const QJsonObject &content)
-{
- Event e = json{
- {"type", type.toStdString()},
- {"content", content},
- };
- return sendAccountDataImpl(std::move(e));
-}
-
-MatrixPromise *MatrixSdk::sendAccountDataImpl(Event event)
-{
- return new MatrixPromise(m_d->clientOnSecondaryRoot.setAccountData(event));
-}
-
-MatrixPromise *MatrixSdk::getSpecVersions()
-{
- return new MatrixPromise(m_d->clientOnSecondaryRoot.getVersions(LAGER_QT(serverUrl).get().toStdString()));
-}
-
-MatrixPromise *MatrixSdk::addDirectRoom(const QString &userId, const QString &roomId)
-{
- return new MatrixPromise(m_d->clientOnSecondaryRoot.addDirectRoom(userId.toStdString(), roomId.toStdString()));
-}
-
-MatrixPromise *MatrixSdk::getRoomIdByAlias(const QString &roomAlias)
-{
- auto job = m_d->clientOnSecondaryRoot
- .getRoomIdByAliasJob(roomAlias.toStdString());
- auto jh = m_d->jobHandler;
- return new MatrixPromise(
- m_d->sdk.context().createPromise([jh, job](auto resolve) {
- jh->submit(job, [resolve](GetRoomIdByAliasResponse r) {
- resolve(parseGetRoomIdByAliasResponse(r));
- });
- }));
-}
-
-inline constexpr std::size_t purgeEventsKeepNumber = 5;
-MatrixPromise *MatrixSdk::purgeEventsExceptRooms(const QStringList &roomIds)
-{
- return new MatrixPromise(
- m_d->sdk.context().createResolvedPromise({})
- .then([client=m_d->sdk.client(), roomIds=qStringListToStdF(roomIds)
- ]([[maybe_unused]] auto &&stat) {
- auto map = intoImmer(immer::map<std::string, std::size_t>{},
- zug::filter([&roomIds](const std::string &roomId) {
- return std::find(roomIds.begin(), roomIds.end(), roomId) == roomIds.end();
- })
- | zug::map([](const std::string &roomId) {
- return std::make_pair(roomId, purgeEventsKeepNumber);
- }),
- client.roomIds().make().get()
- );
- return client.purgeRoomEvents(map);
- }).then([](const auto &stat) {
- qCDebug(kazvLog) << "Purge room events stat:" << !!stat;
- return stat;
- })
- );
-}
-
-MatrixPromise *MatrixSdk::backfillRoomFromEvent(const QString &roomId, const QString &eventId)
-{
- return new MatrixPromise(
- m_d->sdk.context().createPromise([
- dbStore=m_d->dbStore.get(),
- client=m_d->sdk.client(),
- roomId,
- eventId
- ](auto resolve) {
- dbStore->getEventsBefore(roomId, eventId).then([client, resolve, roomId](auto &&res) {
- auto [timelineEvents, relatedEvents] = std::move(res);
- auto loadedCount = timelineEvents[roomId.toStdString()].size();
- client.loadEventsFromStorage(timelineEvents, relatedEvents)
- .then([resolve, loadedCount](auto &&) {
- resolve(EffectStatus(
- !!loadedCount,
- json{{"loadedCount", loadedCount}}
- ));
- });
- });
- })
- );
-}
-
-MatrixPromise *MatrixSdk::importFromKeyBackupFile(QUrl fileUrl, QString password)
-{
- if (!fileUrl.isLocalFile()) {
- return new MatrixPromise(m_d->sdk.context().createResolvedPromise({
- /* succ = */ false,
- json{{"error", "Not a local file"}, {"errorCode", "NOT_LOCAL_FILE"}},
- }));
- }
- auto filename = fileUrl.toLocalFile();
- auto f = QFile(filename);
- if (!f.open(QFile::ReadOnly)) {
- return new MatrixPromise(m_d->sdk.context().createResolvedPromise({
- /* succ = */ false,
- json{{"error", "File open failed"}, {"errorCode", "FILE_OPEN_FAILED"}},
- }));
- }
- auto ba = f.readAll();
- auto content = std::string(ba.begin(), ba.end());
- auto passwordStd = std::move(password).toStdString();
- return new MatrixPromise(m_d->clientOnSecondaryRoot.importFromKeyBackupFile(
- std::move(content), std::move(passwordStd)
- ));
-}
-
-MatrixPromise *MatrixSdk::requestVerifyDevice(QString userId, QString deviceId)
-{
- return new MatrixPromise(m_d->clientOnSecondaryRoot.requestOutgoingToDeviceVerification(
- std::move(userId).toStdString(),
- std::move(deviceId).toStdString()
- ));
}
void MatrixSdk::setUserDataDir(const std::string &userDataDir)
@@ -1231,4 +204,7 @@
m_d->userDataDir = userDataDir;
}
-#include "matrix-sdk.moc"
+MatrixSession *MatrixSdk::session() const
+{
+ return m_d->controller->session();
+}
diff --git a/src/matrix-session-controller-p.hpp b/src/matrix-session-controller-p.hpp
new file mode 100644
--- /dev/null
+++ b/src/matrix-session-controller-p.hpp
@@ -0,0 +1,113 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2020-2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#pragma once
+#include <kazv-defs.hpp>
+#include "matrix-session-controller.hpp"
+#include "matrix-session-types.hpp"
+#include "kazv-session-lock-guard.hpp"
+#include "helper.hpp"
+#include "qt-rand-adapter.hpp"
+#include "qt-job-handler.hpp"
+#include "db-store.hpp"
+#include <lager/event_loop/qt.hpp>
+#include <QPointer>
+
+using namespace Kazv;
+
+struct QtEventLoop
+{
+ QObject *m_obj;
+
+ template<class Fn>
+ void async(Fn &&) { throw std::runtime_error{"not implemented!"}; }
+
+ template<class Fn>
+ void post(Fn &&fn)
+ {
+ QMetaObject::invokeMethod(
+ m_obj, std::forward<Fn>(fn), Qt::QueuedConnection
+ );
+ }
+
+ inline void finish() {}
+ inline void pause() { throw std::runtime_error{"not implemented!"}; }
+ inline void resume() { throw std::runtime_error{"not implemented!"}; }
+};
+
+struct PendingSaveEvents : public SaveEventsRequested
+{
+ using DataT = immer::map<std::string, EventList>;
+ void add(SaveEventsRequested s)
+ {
+ timelineEvents = addOneType(std::move(timelineEvents), s.timelineEvents);
+ nonTimelineEvents = addOneType(std::move(nonTimelineEvents), s.nonTimelineEvents);
+ }
+
+ static DataT addOneType(DataT orig, DataT addon)
+ {
+ for (const auto &[roomId, el]: addon) {
+ orig = std::move(orig).update(roomId, [&el](EventList origEl) {
+ // This works without explicit dedupe because we do not do parallel
+ // inserts and the insert order is the same as list order.
+ return origEl + el;
+ });
+ }
+ return orig;
+ }
+};
+
+enum DbStatus
+{
+ Pending,
+ Ready,
+ Failed,
+};
+
+class MatrixSessionControllerPrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ MatrixSessionControllerPrivate(
+ QThread *thread,
+ std::string userDataDir,
+ SdkModel model,
+ std::unique_ptr<KazvSessionLockGuard> lockGuard,
+ std::unique_ptr<DbStore> dbStore,
+ QObject *parent = nullptr
+ );
+
+ ~MatrixSessionControllerPrivate();
+
+ void saveSession();
+
+ void saveOrQueueEvents(SaveEventsRequested s);
+
+ void saveEvents(SaveEventsRequested s);
+
+Q_SIGNALS:
+ void dbResolved(bool success);
+
+private:
+ friend class MatrixSessionController;
+
+ QPointer<QThread> thread;
+ std::string userDataDir;
+ UniquePtrDL<QObject> obj;
+ std::unique_ptr<KazvSessionLockGuard> lockGuard;
+ RandomInterface randomGenerator;
+ DbStatus dbStatus;
+ std::unique_ptr<DbStore> dbStore;
+ QPointer<QtJobHandler> jobHandler;
+ LagerStoreEventEmitter ee;
+ LagerStoreEventEmitter::Watchable watchable;
+ MatrixSessionSdkT sdk;
+ SecondaryRootT secondaryRoot;
+ Client clientOnSecondaryRoot;
+ PendingSaveEvents pendingSaveEvents{};
+ lager::state<VerificationTrackerModel> verificationTrackerState;
+};
diff --git a/src/matrix-session-controller.hpp b/src/matrix-session-controller.hpp
new file mode 100644
--- /dev/null
+++ b/src/matrix-session-controller.hpp
@@ -0,0 +1,104 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2020-2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#pragma once
+#include <kazv-defs.hpp>
+#include "constants.hpp"
+#include "helper.hpp"
+#include <QObject>
+#include <QThread>
+#include <QPointer>
+#include <memory>
+
+namespace Kazv
+{
+ struct SdkModel;
+}
+
+class MatrixSession;
+class MatrixSessionControllerPrivate;
+
+std::filesystem::path sessionDirForUserAndDeviceId(std::filesystem::path userDataDir, std::string userId, std::string deviceId);
+
+/**
+ * Control the creation/loading/saving of a session.
+ *
+ * The controller object should be in the GUI thread.
+ * However, it owns objects that are in worker thread
+ * passed in as the argument of the constructor.
+ */
+class MatrixSessionController : public QObject
+{
+ Q_OBJECT
+
+public:
+ MatrixSessionController(
+ QThread *workerThread,
+ std::string userDataDir,
+ QObject *parent = nullptr
+ );
+
+ ~MatrixSessionController();
+
+ /**
+ * Get the MatrixSession representing the current session.
+ *
+ * If there is no current session, this returns nullptr.
+ */
+ Q_INVOKABLE MatrixSession *session() const;
+
+Q_SIGNALS:
+ void loadSessionFinished(
+ QString sessionName,
+ Constants::LoadSessionResult result
+ );
+
+ /**
+ * Signals that the session is ready.
+ *
+ * This is emitted after successfully loading a session or after
+ * creating a new session.
+ */
+ void sessionReady();
+
+public Q_SLOTS:
+ /**
+ * Load session at <userDataDir>/sessions/<sessionName> asynchronously.
+ *
+ * When the session is loaded or when there is an error, loadSessionFinished
+ * will be called with the result.
+ *
+ * @param sessionName A string in the form of <userid>/<deviceid> .
+ */
+ void load(QString sessionName);
+
+ /**
+ * Create a new empty session.
+ */
+ void create();
+
+ /**
+ * Create a new session with model m.
+ */
+ void createWithModel(const Kazv::SdkModel &m);
+
+ void save() const;
+
+ /**
+ * Prepare the MatrixSessionController for destruction.
+ *
+ * After calling this function, you can call deleteLater().
+ */
+ void prepareDestroy();
+
+ void startSyncing();
+
+private:
+ QPointer<QThread> m_thread;
+ std::string m_userDataDir;
+
+ UniquePtrDL<MatrixSessionControllerPrivate> m_d;
+};
diff --git a/src/matrix-session-controller.cpp b/src/matrix-session-controller.cpp
new file mode 100644
--- /dev/null
+++ b/src/matrix-session-controller.cpp
@@ -0,0 +1,454 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2020-2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <kazv-defs.hpp>
+#include "matrix-session-controller-p.hpp"
+#include "matrix-session.hpp"
+#include "kazv-log.hpp"
+#include "kazv-version.hpp"
+#include <crypto/base64.hpp>
+#include <KConfig>
+#include <KConfigGroup>
+#include <QCoroTask>
+#include <boost/archive/text_oarchive.hpp>
+#include <boost/archive/text_iarchive.hpp>
+#include <fstream>
+#include <filesystem>
+#include <chrono>
+
+using namespace Qt::Literals::StringLiterals;
+using namespace Kazv;
+
+std::filesystem::path sessionDirForUserAndDeviceId(std::filesystem::path userDataDir, std::string userId, std::string deviceId)
+{
+ auto encodedUserId = encodeBase64(userId, Base64Opts::urlSafe);
+ auto sessionDir = userDataDir / "sessions"
+ / encodedUserId / deviceId;
+ return sessionDir;
+}
+
+QCoro::Task<std::pair<bool, QString>> setupAndImport(SdkModel model, DbStore *dbStore, std::string userDataDir)
+{
+ auto res = co_await dbStore->setup(
+ userDataDir,
+ model.c().userId,
+ model.c().deviceId
+ );
+ if (!res.first) {
+ co_return res;
+ }
+ co_return co_await dbStore->importAllFrom(model);
+}
+
+MatrixSessionControllerPrivate::MatrixSessionControllerPrivate(
+ QThread *threadArg,
+ std::string userDataDirArg,
+ SdkModel model,
+ std::unique_ptr<KazvSessionLockGuard> lockGuardArg,
+ std::unique_ptr<DbStore> dbStoreArg,
+ QObject *parent
+)
+ : QObject(parent)
+ , thread(threadArg)
+ , userDataDir(userDataDirArg)
+ , obj(new QObject())
+ , lockGuard(std::move(lockGuardArg))
+ , randomGenerator(QtRandAdapter{})
+ , dbStatus(dbStoreArg ? Ready : Pending)
+ , dbStore(dbStoreArg ? std::move(dbStoreArg) : std::make_unique<DbStore>())
+ , jobHandler(new QtJobHandler(obj.get()))
+ , ee{QtEventLoop{obj.get()}}
+ , watchable(ee.watchable())
+ , sdk(makeSdk(
+ model,
+ static_cast<JobInterface &>(*jobHandler),
+ static_cast<EventInterface &>(ee),
+ QtPromiseHandler(*obj),
+ zug::identity,
+ withRandomGenerator(randomGenerator)))
+ , secondaryRoot(sdk.createSecondaryRoot(QtEventLoop{this}, std::move(model)))
+ , clientOnSecondaryRoot(sdk.clientFromSecondaryRoot(secondaryRoot))
+{
+ obj->moveToThread(thread);
+
+ watchable.after<SaveEventsRequested>([this](SaveEventsRequested e) {
+ QMetaObject::invokeMethod(this, [this, e=std::move(e)]() mutable {
+ saveOrQueueEvents(std::move(e));
+ });
+ });
+
+ watchable.after<LoginSuccessful>([this](LoginSuccessful) {
+ QMetaObject::invokeMethod(this, [this]() {
+ if (dbStatus == Ready) {
+ qCWarning(kazvLog) << "Trying to replace current db store, ignoring";
+ return;
+ }
+ // This must be called from the GUI thread
+ auto model = secondaryRoot.get();
+ setupAndImport(std::move(model), dbStore.get(), userDataDir)
+ .then([this](const auto &stat) {
+ if (!stat.first) {
+ qCWarning(kazvLog) << "Cannot set up database:" << stat.second;
+ }
+ Q_EMIT dbResolved(stat.first);
+ });
+ });
+ });
+
+ watchable.after<VerificationTrackerModelChanged>([this](VerificationTrackerModelChanged) {
+ auto model = lager::get<VerificationTracker>(sdk.context()).model;
+ QMetaObject::invokeMethod(
+ this, [this, model=std::move(model)]() {
+ qCDebug(kazvLog) << "Verification tracker model changed" << model.processes.size();
+ verificationTrackerState.set(model);
+ lager::commit(verificationTrackerState);
+ });
+ });
+
+
+ connect(this, &MatrixSessionControllerPrivate::dbResolved, this, [this](bool success) {
+ if (!success) {
+ dbStatus = Failed;
+ } else {
+ qCDebug(kazvLog) << "db loading succeeded";
+ auto origPendingSaveEvents = std::move(pendingSaveEvents);
+ pendingSaveEvents = {};
+ saveEvents(std::move(pendingSaveEvents));
+ dbStatus = Ready;
+ }
+ });
+}
+
+void MatrixSessionControllerPrivate::saveSession()
+{
+ using namespace Kazv::CursorOp;
+ auto &c = clientOnSecondaryRoot;
+ auto userId = +c.userId();
+ auto deviceId = +c.deviceId();
+ if (userId.empty() || deviceId.empty()) {
+ qDebug() << "Not logged in, nothing to serialize";
+ return;
+ }
+
+ using StdPath = std::filesystem::path;
+ auto userDataDir = StdPath(this->userDataDir);
+ auto sessionDir = sessionDirForUserAndDeviceId(userDataDir, userId, deviceId);
+
+ auto storeFile = sessionDir / "store";
+ auto storeFileNew = sessionDir / "store.new";
+
+ auto metadataFile = sessionDir / "metadata";
+
+ qDebug() << "storeFile=" << QString::fromStdString(storeFile.string());
+
+ std::error_code err;
+ if ((! std::filesystem::create_directories(sessionDir, err))
+ && err) {
+ qDebug() << "Unable to create sessionDir";
+ return;
+ }
+
+ if (!lockGuard) {
+ try {
+ lockGuard = std::make_unique<KazvSessionLockGuard>(sessionDir);
+ } catch (const std::runtime_error &e) {
+ qCWarning(kazvLog) << "Error locking session: " << e.what();
+ return;
+ }
+ }
+
+ try {
+ auto storeStream = std::ofstream(storeFileNew);
+ if (! storeStream) {
+ qCWarning(kazvLog) << "Unable to open storeFile";
+ return;
+ }
+ using OAr = boost::archive::text_oarchive;
+ auto archive = OAr{storeStream};
+ c.serializeTo(archive);
+ } catch (const std::exception &e) {
+ qCWarning(kazvLog) << "Cannot write to store file: " << e.what();
+ return;
+ }
+
+ err.clear();
+ std::filesystem::rename(storeFileNew, storeFile, err);
+ if (err) {
+ qCWarning(kazvLog) << "Cannot move storeFile into place: " << QString::fromStdString(err.message());
+ return;
+ }
+ qDebug() << "Serialization done";
+
+
+ // store metadata
+ {
+ KConfig metadata(QString::fromStdString(metadataFile.string()));
+ KConfigGroup mdGroup(&metadata, u"Metadata"_s);
+ mdGroup.writeEntry("kazvVersion", QString::fromStdString(kazvVersionString()));
+ mdGroup.writeEntry("archiveFormat", "text-with-sqlite");
+ }
+}
+
+void MatrixSessionControllerPrivate::saveOrQueueEvents(SaveEventsRequested s)
+{
+ if (dbStatus == Ready) {
+ saveEvents(std::move(s));
+ } else if (dbStatus == Pending) {
+ pendingSaveEvents.add(std::move(s));
+ }
+ // Database open failed, do not do anything
+}
+
+void MatrixSessionControllerPrivate::saveEvents(SaveEventsRequested s)
+{
+ dbStore->saveEvents(std::move(s))
+ .then([](const auto &stat) {
+ if (!stat.first) {
+ qCWarning(kazvLog) << "Cannot save events:" << stat.second;
+ }
+ });
+}
+
+MatrixSessionControllerPrivate::~MatrixSessionControllerPrivate()
+{
+}
+
+MatrixSessionController::MatrixSessionController(
+ QThread *workerThread,
+ std::string userDataDir,
+ QObject *parent
+)
+ : QObject(parent)
+ , m_thread(workerThread)
+ , m_userDataDir(userDataDir)
+ , m_d(nullptr)
+{
+}
+
+MatrixSessionController::~MatrixSessionController() = default;
+
+// Cleaning up notes:
+// 0. Callback functions may store the context for an indefinite time
+// 1. The QThread event loop can be stopped
+// 2. QtJobHandler::submit() should only happen in the primary event loop thread
+// 3. QtJobHandler lives in the primary event loop thread
+// 4. QtJobs live in the primary event loop thread
+// 5. Job callbacks are called in the primary event loop thread
+// 6. QtPromise::then() callbacks are called in the primary event loop thread
+// 7. When the QThread event loop stops, no more callbacks will be executed (there is nothing to post to)
+// 8. The QThread should stop before obj is deleted
+// class CleanupHelper : public QObject
+// {
+// Q_OBJECT
+// public:
+// explicit CleanupHelper(std::unique_ptr<MatrixSdkPrivate> d)
+// : oldD(std::move(d))
+// {
+// }
+
+// std::unique_ptr<MatrixSdkPrivate> oldD;
+
+// void cleanup()
+// {
+// qCInfo(kazvLog) << "start to clean up everything";
+
+// oldD->clientOnSecondaryRoot.stopSyncing()
+// .then([obj=oldD->obj, thread=oldD->thread](auto &&) {
+// qCDebug(kazvLog) << "stopped syncing";
+// QMetaObject::invokeMethod(obj, [thread]() {
+// thread->quit();
+// });
+// });
+// oldD->thread->wait();
+// oldD->thread->deleteLater();
+// // After the thread's event loop is finished, we can delete the root object
+// oldD->obj->deleteLater();
+// this->deleteLater();
+// qCInfo(kazvLog) << "thread is done";
+// }
+// };
+
+// static void cleanupDPointer(std::unique_ptr<MatrixSdkPrivate> oldD)
+// {
+// oldD->saveTimer.disconnect();
+// oldD->saveTimer.stop();
+
+// auto helper = new CleanupHelper(std::move(oldD));
+// helper->cleanup();
+// }
+
+void MatrixSessionController::load(QString sessionName)
+{
+ if (m_d) {
+ qCWarning(kazvLog) << "MatrixSessionController: attempting to load when there is already a session";
+ return;
+ }
+ using StdPath = std::filesystem::path;
+ auto loadFromSession = [this, sessionName](StdPath sessionDir, std::unique_ptr<KazvSessionLockGuard> lockGuard) {
+ auto storeFile = sessionDir / "store";
+
+ auto metadataFile = sessionDir / "metadata";
+
+ if (! std::filesystem::exists(storeFile)) {
+ qDebug() << "storeFile does not exist, skip loading session " << sessionName;
+ Q_EMIT loadSessionFinished(sessionName, Constants::SessionNotFound);
+ return;
+ }
+
+ if (std::filesystem::exists(metadataFile)) {
+ KConfig metadata(QString::fromStdString(metadataFile.string()));
+ KConfigGroup mdGroup(&metadata, u"Metadata"_s);
+ auto format = mdGroup.readEntry(u"archiveFormat"_s);
+ if (format != u"text"_s && format != u"text-with-sqlite"_s) {
+ qDebug() << "Unknown archive format:" << format;
+ Q_EMIT loadSessionFinished(sessionName, Constants::SessionFormatUnknown);
+ return;
+ }
+ auto version = mdGroup.readEntry(u"kazvVersion"_s);
+ auto curVersion = kazvVersionString();
+ if (version != QString::fromStdString(curVersion)) {
+ qDebug() << "A different version from the current one, making a backup";
+ std::error_code err;
+ auto now = std::chrono::system_clock::now();
+ auto backupName =
+ std::to_string(std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count());
+ auto backupDir = sessionDir / "backup" / backupName;
+ if (! std::filesystem::create_directories(backupDir, err)
+ && err) {
+ qDebug() << "Cannot create backup directory";
+ Q_EMIT loadSessionFinished(sessionName, Constants::SessionCannotBackup);
+ return;
+ }
+ std::filesystem::copy_file(storeFile, backupDir / "store");
+ std::filesystem::copy_file(metadataFile, backupDir / "metadata");
+ }
+ }
+
+ SdkModel model;
+ try {
+ auto storeStream = std::ifstream(storeFile);
+ if (! storeStream) {
+ qDebug() << "Unable to open storeFile";
+ Q_EMIT loadSessionFinished(sessionName, Constants::SessionCannotOpenFile);
+ return;
+ }
+ using IAr = boost::archive::text_iarchive;
+ auto archive = IAr{storeStream};
+ archive >> model;
+ qDebug() << "Finished loading session store file";
+ } catch (const std::exception &e) {
+ qDebug() << "Error when loading session:" << QString::fromStdString(e.what());
+ Q_EMIT loadSessionFinished(sessionName, Constants::SessionDeserializeFailed);
+ return;
+ }
+
+ auto dbStore = std::make_unique<DbStore>();
+ auto stat = QCoro::waitFor(setupAndImport(model, dbStore.get(), m_userDataDir));
+ if (!stat.first) {
+ qCWarning(kazvLog) << "Unable to open db store:" << stat.second;
+ Q_EMIT loadSessionFinished(sessionName, Constants::SessionDeserializeFailed);
+ return;
+ }
+ QMetaObject::invokeMethod(this, [this, model=std::move(model), lockGuard=std::move(lockGuard), dbStore=std::move(dbStore)]() mutable {
+ m_d.reset(new MatrixSessionControllerPrivate(
+ m_thread, m_userDataDir,
+ std::move(model), std::move(lockGuard), std::move(dbStore)
+ ));
+ Q_EMIT sessionReady();
+ });
+ Q_EMIT loadSessionFinished(sessionName, Constants::SessionLoadSuccess);
+ };
+
+ qDebug() << "in loadSession(), sessionName=" << sessionName;
+ auto userDataDir = StdPath(m_userDataDir);
+ auto parts = sessionName.split(u'/');
+ if (parts.size() == 2) {
+ auto userId = parts[0].toStdString();
+ auto deviceId = parts[1].toStdString();
+ auto sessionDir = sessionDirForUserAndDeviceId(userDataDir, userId, deviceId);
+ std::unique_ptr<KazvSessionLockGuard> lockGuard;
+ try {
+ lockGuard = std::make_unique<KazvSessionLockGuard>(sessionDir);
+ } catch (const std::runtime_error &e) {
+ qCWarning(kazvLog) << "Error locking session: " << e.what();
+ Q_EMIT loadSessionFinished(sessionName, Constants::SessionLockFailed);
+ return;
+ }
+ QThreadPool::globalInstance()->start([loadFromSession, sessionDir, lockGuard=std::move(lockGuard)]() mutable {
+ loadFromSession(sessionDir, std::move(lockGuard));
+ });
+ return;
+ }
+ qDebug(kazvLog) << "no session found for" << sessionName;
+ Q_EMIT loadSessionFinished(sessionName, Constants::SessionNotFound);
+}
+
+void MatrixSessionController::create()
+{
+ auto model = SdkModel{};
+ RandomData random(Crypto::constructRandomSize(), '\0');
+ QRandomGenerator::securelySeeded().generate(random.begin(), random.end());
+ model.client.crypto = Crypto(
+ RandomTag{},
+ std::move(random)
+ );
+
+ createWithModel(model);
+}
+
+void MatrixSessionController::createWithModel(const Kazv::SdkModel &model)
+{
+ if (m_d) {
+ qCWarning(kazvLog) << "MatrixSessionController: attempting to create when there is already a session";
+ return;
+ }
+ m_d.reset(new MatrixSessionControllerPrivate(
+ m_thread,
+ m_userDataDir,
+ model,
+ /* lockGuard = */ nullptr,
+ /* dbStore = */ nullptr
+ ));
+ Q_EMIT sessionReady();
+}
+
+void MatrixSessionController::save() const
+{
+ if (m_d) {
+ m_d->saveSession();
+ }
+}
+
+void MatrixSessionController::prepareDestroy()
+{
+ if (m_d) {
+ qCDebug(kazvLog) << "MatrixSessionController::prepareDestroy";
+ m_d->clientOnSecondaryRoot.stopSyncing();
+ m_d->obj = nullptr;
+ }
+}
+
+void MatrixSessionController::startSyncing()
+{
+ m_d->clientOnSecondaryRoot.startSyncing();
+}
+
+MatrixSession *MatrixSessionController::session() const
+{
+ if (m_d) {
+ return new MatrixSession(
+ m_d->sdk.context(),
+ m_d->clientOnSecondaryRoot,
+ m_d->ee.watchable(),
+ m_d->verificationTrackerState,
+ [d=m_d.get()]() -> DbStore & { return *(d->dbStore); }
+ );
+ } else {
+ return nullptr;
+ }
+}
+
+#include "moc_matrix-session-controller-p.cpp"
diff --git a/src/matrix-session-types.hpp b/src/matrix-session-types.hpp
new file mode 100644
--- /dev/null
+++ b/src/matrix-session-types.hpp
@@ -0,0 +1,27 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2020-2024 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#pragma once
+#include <kazv-defs.hpp>
+#include "qt-promise-handler.hpp"
+#include <lagerstoreeventemitter.hpp>
+#include <sdk.hpp>
+#include <lager/event_loop/qt.hpp>
+#include <QObject>
+
+// Sdk with qt event loop, identity transform and no enhancers
+using MatrixSessionSdkT =
+ decltype(Kazv::makeSdk(
+ Kazv::SdkModel{},
+ Kazv::detail::declref<Kazv::JobInterface>(),
+ Kazv::detail::declref<Kazv::EventInterface>(),
+ QtPromiseHandler(Kazv::detail::declref<QObject>()),
+ zug::identity,
+ withRandomGenerator(Kazv::detail::declref<Kazv::RandomInterface>())));
+
+using MatrixSessionContextT = decltype(std::declval<MatrixSessionSdkT>().context());
+
+using SecondaryRootT = decltype(std::declval<MatrixSessionSdkT>().createSecondaryRoot(std::declval<lager::with_qt_event_loop>()));
diff --git a/src/matrix-sdk.hpp b/src/matrix-session.hpp
copy from src/matrix-sdk.hpp
copy to src/matrix-session.hpp
--- a/src/matrix-sdk.hpp
+++ b/src/matrix-session.hpp
@@ -1,27 +1,22 @@
/*
* This file is part of kazv.
- * SPDX-FileCopyrightText: 2020-2023 tusooa <tusooa@kazv.moe>
+ * SPDX-FileCopyrightText: 2020-2026 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#pragma once
#include <kazv-defs.hpp>
-
+#include "helper.hpp"
+#include "meta-types.hpp"
+#include "matrix-session-types.hpp"
+#include "constants.hpp"
+#include <client.hpp>
+#include <notification-handler.hpp>
+#include <lagerstoreeventemitter.hpp>
+#include <lager/extra/qt.hpp>
#include <QObject>
#include <QQmlEngine>
-#include <QString>
-
-#include <string>
-#include <memory>
-#include <filesystem>
-
-#include <lager/extra/qt.hpp>
-#include <immer/map.hpp>
-
-#include <sdk-model.hpp>
-#include <random-generator.hpp>
-#include "meta-types.hpp"
Q_MOC_INCLUDE("matrix-room-list.hpp")
Q_MOC_INCLUDE("matrix-device-list.hpp")
Q_MOC_INCLUDE("matrix-promise.hpp")
@@ -33,68 +28,42 @@
class MatrixRoomList;
class MatrixDeviceList;
class MatrixPromise;
-class MatrixSdkTest;
-class MatrixSdkSessionsTest;
class MatrixEvent;
class MatrixStickerPackList;
class MatrixUserGivenAttrsMap;
-class KazvSessionLockGuard;
-class DbStore;
class MatrixVerificationList;
-struct MatrixSdkPrivate;
-
-std::filesystem::path sessionDirForUserAndDeviceId(std::filesystem::path userDataDir, std::string userId, std::string deviceId);
+class SsoLoginProcess;
+class DbStore;
-class MatrixSdk : public QObject
+/**
+ * Represent all operations that can be taken within a Matrix session.
+ */
+class MatrixSession : public QObject
{
Q_OBJECT
QML_ELEMENT
+ QML_UNCREATABLE("")
- std::unique_ptr<MatrixSdkPrivate> m_d;
-
- /// @param d A dynamically allocated d-pointer, whose ownership
- /// will be transferred to this MatrixSdk.
- explicit MatrixSdk(std::unique_ptr<MatrixSdkPrivate> d, QObject *parent);
-
- void init();
+ MatrixSessionContextT m_context;
+ Kazv::Client m_clientOnSecondaryRoot;
+ Kazv::LagerStoreEventEmitter::Watchable m_watchable;
+ Kazv::NotificationHandler m_notificationHandler;
+ lager::reader<Kazv::VerificationTrackerModel> m_verificationTrackerState;
+ UniquePtrDL<SsoLoginProcess> m_ssoLoginProcess;
+ std::function<DbStore &()> m_dbStoreGetter;
public:
- enum CreateRoomPreset {
- PrivateChat = Kazv::CreateRoomPreset::PrivateChat,
- PublicChat = Kazv::CreateRoomPreset::PublicChat,
- TrustedPrivateChat = Kazv::CreateRoomPreset::TrustedPrivateChat,
- };
-
- Q_ENUM(CreateRoomPreset);
-
- enum LoadSessionResult {
- /// Successfully loaded the session
- SessionLoadSuccess,
- /// There is no store file
- SessionNotFound,
- /// The format of the store file is not supported
- SessionFormatUnknown,
- /// The store file cannot be backed up
- SessionCannotBackup,
- /// Cannot grab the lock on the session file
- SessionLockFailed,
- /// Cannot open store file
- SessionCannotOpenFile,
- /// Cannot deserialize the store file
- SessionDeserializeFailed,
- };
-
- Q_ENUM(LoadSessionResult);
-
- enum MediaDownloadEndpointVersion {
- UnauthenticatedMediaV3, // Classical endpoint series
- AuthenticatedMediaV1, // Endpoints that needs authorization
- };
-
- Q_ENUM(MediaDownloadEndpointVersion);
-
- explicit MatrixSdk(QObject *parent = 0);
- ~MatrixSdk() override;
+ MatrixSession(
+ MatrixSessionContextT context,
+ Kazv::Client client,
+ Kazv::LagerStoreEventEmitter::Watchable watchable,
+ lager::reader<Kazv::VerificationTrackerModel> verificationTrackerState,
+ std::function<DbStore &()> dbStoreGetter,
+ QObject *parent = nullptr
+ );
+ ~MatrixSession() override;
+
+ static std::string validateHomeserverUrl(const QString &url);
LAGER_QT_READER(QString, serverUrl);
LAGER_QT_READER(QString, userId);
@@ -120,14 +89,6 @@
Q_INVOKABLE MatrixVerificationList *verificationList() const;
- Kazv::RandomInterface &randomGenerator() const;
-
-private:
- // Replaces the store with another one
- void emplace(std::optional<Kazv::SdkModel> model, std::unique_ptr<KazvSessionLockGuard> lockGuard, std::unique_ptr<DbStore> dbStore);
-
- static std::string validateHomeserverUrl(const QString &url);
-
Q_SIGNALS:
void trigger(Kazv::KazvEvent e);
@@ -143,11 +104,6 @@
void receivedMessage(QString roomId, QString eventId);
- void sessionChanged();
-
- void loadSessionFinished(QString sessionName, MatrixSdk::LoadSessionResult result);
- void dbResolved(bool success);
-
public Q_SLOTS:
void login(const QString &userId, const QString &password, const QString &homeserverUrl);
@@ -175,48 +131,6 @@
QUrl ssoLoginStart(const QString &homeserverUrl);
void logout();
- /**
- * Serialize data to <AppDataDir>/sessions/<userid>/<deviceid>/
- *
- * If not logged in, do nothing.
- */
- void serializeToFile() const;
-
- /**
- * Load session at <AppDataDir>/sessions/<sessionName> asynchronously.
- *
- * When the session is loaded or when there is an error, loadSessionFinished
- * will be called with the result.
- *
- * @param sessionName A string in the form of <userid>/<deviceid> .
- */
- void loadSession(QString sessionName);
-
- /**
- * Delete session at <AppDataDir>/sessions/<sessionName> .
- *
- * @param sessionName A string in the form of <userid>/<deviceid> .
- *
- * @return true if successful, false otherwise.
- */
- bool deleteSession(QString sessionName);
-
- /**
- * Start an empty session.
- *
- * The new session is not logged in, and need to call login().
- *
- * @return true if successful, false otherwise.
- */
- bool startNewSession();
-
- /**
- * Get all saved sessions.
- *
- * @return A list of session names in the form of <userid>/<deviceid> .
- */
- QStringList allSessions() const;
-
/**
* Create a new room.
*
@@ -240,7 +154,7 @@
bool allowFederate,
const QString &topic,
const QJsonValue &powerLevelContentOverride,
- CreateRoomPreset preset,
+ Constants::CreateRoomPreset preset,
bool encrypted
);
@@ -384,14 +298,4 @@
private:
MatrixPromise *sendAccountDataImpl(Kazv::Event event);
-
-private: // Testing
- friend MatrixSdkTest;
- friend MatrixSdkSessionsTest;
- friend MatrixSdk *makeTestSdk(Kazv::SdkModel model);
-
- void setUserDataDir(const std::string &userDataDir);
-
- explicit MatrixSdk(Kazv::SdkModel model, bool testing = false, QObject *parent = 0);
- void startThread();
};
diff --git a/src/matrix-session.cpp b/src/matrix-session.cpp
new file mode 100644
--- /dev/null
+++ b/src/matrix-session.cpp
@@ -0,0 +1,597 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2020-2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <kazv-defs.hpp>
+#include "matrix-session.hpp"
+#include "matrix-utils.hpp"
+#include "matrix-room-list.hpp"
+#include "matrix-promise.hpp"
+#include "matrix-event.hpp"
+#include "device-mgmt/matrix-device-list.hpp"
+#include "matrix-sticker-pack-list.hpp"
+#include "matrix-sticker-pack-list-p.hpp"
+#include "matrix-user-given-attrs-map.hpp"
+#include "matrix-verification-list.hpp"
+#include "sso-login-process.hpp"
+#include "db-store.hpp"
+#include "helper.hpp"
+#include "kazv-log.hpp"
+#include <csapi/login.hpp>
+#include <csapi/directory.hpp>
+#include <client/alias.hpp>
+#include <QFile>
+
+using namespace Qt::Literals::StringLiterals;
+using namespace Kazv;
+
+static const std::string clientName = "kazv";
+
+MatrixSession::MatrixSession(
+ MatrixSessionContextT context,
+ Client client,
+ LagerStoreEventEmitter::Watchable watchable,
+ lager::reader<VerificationTrackerModel> verificationTrackerState,
+ std::function<DbStore &()> dbStoreGetter,
+ QObject *parent
+)
+ : QObject(parent)
+ , m_context(std::move(context))
+ , m_clientOnSecondaryRoot(std::move(client))
+ , m_watchable(std::move(watchable))
+ , m_notificationHandler(m_clientOnSecondaryRoot.notificationHandler())
+ , m_verificationTrackerState(std::move(verificationTrackerState))
+ , m_ssoLoginProcess()
+ , m_dbStoreGetter(std::move(dbStoreGetter))
+ , LAGER_QT(serverUrl)(m_clientOnSecondaryRoot.serverUrl().xform(strToQt))
+ , LAGER_QT(userId)(m_clientOnSecondaryRoot.userId().xform(strToQt))
+ , LAGER_QT(token)(m_clientOnSecondaryRoot.token().xform(strToQt))
+ , LAGER_QT(deviceId)(m_clientOnSecondaryRoot.deviceId().xform(strToQt))
+ , LAGER_QT(specVersions)(m_clientOnSecondaryRoot.supportVersions())
+{
+ m_watchable.afterAll(
+ [this](KazvEvent e) {
+ Q_EMIT this->trigger(e);
+ });
+
+ m_watchable.after<LoginSuccessful>(
+ [this](LoginSuccessful e) {
+ Q_EMIT this->loginSuccessful(e);
+ });
+
+ m_watchable.after<LoginFailed>(
+ [this](LoginFailed e) {
+ Q_EMIT this->loginFailed(
+ QString::fromStdString(e.errorCode),
+ QString::fromStdString(e.error)
+ );
+ });
+
+ m_watchable.after<ReceivingRoomTimelineEvent>(
+ [this](ReceivingRoomTimelineEvent e) {
+ Q_EMIT this->receivedMessage(
+ QString::fromStdString(e.roomId),
+ QString::fromStdString(e.event.id())
+ );
+ });
+}
+
+MatrixSession::~MatrixSession() = default;
+
+QString MatrixSession::mxcUriToHttp(QString mxcUri) const
+{
+ return QString::fromStdString(m_clientOnSecondaryRoot.mxcUriToHttp(mxcUri.toStdString()));
+}
+
+QString MatrixSession::mxcUriToHttpAuthenticatedV1(QString mxcUri) const
+{
+ return QString::fromStdString(m_clientOnSecondaryRoot.mxcUriToHttpV1(mxcUri.toStdString()));
+}
+
+MatrixDeviceList *MatrixSession::devicesOfUser(QString userId) const
+{
+ return new MatrixDeviceList(m_clientOnSecondaryRoot.devicesOfUser(userId.toStdString()));
+}
+
+bool isIllFormatSpecVersion(const QString &version)
+{
+ const bool isLegacy = version.startsWith(u"r"_s);
+ if (isLegacy && version.split(u'.').size() == 3) {
+ return false;
+ }
+ if (!isLegacy && version.split(u'.').size() == 2) {
+ return false;
+ }
+ return true;
+}
+
+// Return true if v1 is at least as new as v2, false if v1 is older than v2
+// Return false if v1 or v2 is ill-format
+bool compareSpecVersion(QString v1, QString v2)
+{
+ // Check parameters format
+ if (isIllFormatSpecVersion(v1) || isIllFormatSpecVersion(v2)) {
+ return false;
+ }
+
+ const bool v1IsLegacy = v1.startsWith(u"r"_s);
+ const bool v2IsLegacy = v2.startsWith(u"r"_s);
+ if (v1IsLegacy != v2IsLegacy) {
+ return v2IsLegacy;
+ }
+
+ v1.remove(0, 1);
+ v2.remove(0, 1);
+ auto v1VersionNumbers = v1.split(u'.');
+ auto v2VersionNumbers = v2.split(u'.');
+
+ for (int i = 0; i < v1VersionNumbers.size(); i++) {
+ auto v1VerNum = v1VersionNumbers[i].toInt();
+ auto v2VerNum = v2VersionNumbers[i].toInt();
+ if (v1VerNum != v2VerNum) {
+ return v1VerNum > v2VerNum;
+ }
+ }
+ // v1 is equal to v2
+ return true;
+}
+
+// Return true if version in the range [minVer, maxVer]
+// Return false if any parameter is ill-format
+bool compareSpecVersionRange(const QString &version,
+ const QString &minVer, const QString &maxVer)
+{
+ if (isIllFormatSpecVersion(version)
+ || isIllFormatSpecVersion(minVer)
+ || isIllFormatSpecVersion(maxVer)) {
+ return false;
+ }
+
+ if (compareSpecVersion(version, minVer) && compareSpecVersion(maxVer, version)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool MatrixSession::checkSpecVersion(QString version) const
+{
+ return std::find_if(specVersions().begin(), specVersions().end(),
+ [&version](auto v) {
+ return compareSpecVersion(QString::fromStdString(v), version);
+ }) != specVersions().end();
+}
+
+bool MatrixSession::checkSpecVersionRange(QString minVer, QString maxVer) const
+{
+ return std::find_if(specVersions().begin(), specVersions().end(),
+ [&minVer, maxVer](auto v) {
+ return compareSpecVersionRange(QString::fromStdString(v), minVer, maxVer);
+ }) != specVersions().end();
+}
+
+QStringList MatrixSession::directRoomIds(QString userId) const
+{
+ auto content = m_clientOnSecondaryRoot.accountData().get()["m.direct"].content().get();
+ auto roomIds = QStringList{};
+ for (auto i : content[userId.toStdString()]) {
+ roomIds.push_back(QString::fromStdString(i.get<std::string>()));
+ }
+ return roomIds;
+}
+
+MatrixVerificationList *MatrixSession::verificationList() const
+{
+ return new MatrixVerificationList(m_clientOnSecondaryRoot, m_verificationTrackerState);
+}
+
+std::string MatrixSession::validateHomeserverUrl(const QString &url)
+{
+ if (url.isEmpty()) {
+ return std::string();
+ }
+
+ auto u = QUrl::fromUserInput(url);
+ if (!u.isValid()) {
+ return std::string();
+ }
+
+ if (u.scheme() == u"http"_s) {
+ qCInfo(kazvLog) << "url" << u << "is http. Force switching to https.";
+ u.setScheme(u"https"_s);
+ } else if (u.scheme() != u"https"_s) {
+ qCWarning(kazvLog) << "url" << u << "is not http/https.";
+ return std::string();
+ }
+
+ return u.toString().toStdString();
+}
+
+void MatrixSession::login(const QString &userId, const QString &password, const QString &homeserverUrl)
+{
+ auto loginFunc = [userId, password](const Client &client, const std::string &serverUrl) {
+ client.passwordLogin(
+ serverUrl,
+ userId.toStdString(),
+ password.toStdString(),
+ clientName
+ );
+ };
+
+ auto validated = validateHomeserverUrl(homeserverUrl);
+ if (!validated.empty()) {
+ loginFunc(m_clientOnSecondaryRoot, validated);
+ } else {
+ m_clientOnSecondaryRoot
+ .autoDiscover(userId.toStdString()) // autoDiscover() will dispatch GetVersionAction to get supported versions of the server
+ .then([
+ this,
+ client=m_clientOnSecondaryRoot.toEventLoop(),
+ userId,
+ password,
+ loginFunc
+ ](auto res) {
+ if (!res.success()) {
+ // FIXME use real error codes and msgs when available in libkazv
+ Q_EMIT this->discoverFailed(u""_s, u""_s);
+ return res;
+ }
+
+ auto serverUrl = res.dataStr("homeserverUrl");
+
+ loginFunc(client, serverUrl);
+
+ return res;
+ });
+ }
+}
+
+void MatrixSession::discoverAndGetLoginFlows(const QString &userId, const QString &homeserverUrl)
+{
+ auto validated = validateHomeserverUrl(homeserverUrl);
+ if (!validated.empty()) {
+ getLoginFlows(homeserverUrl);
+ } else {
+ m_clientOnSecondaryRoot
+ .autoDiscover(userId.toStdString())
+ .then([
+ this
+ ](const EffectStatus &res) {
+ if (!res.success()) {
+ Q_EMIT discoverFailed(
+ QString::fromStdString(res.dataStr("errorCode")),
+ QString::fromStdString(res.dataStr("error"))
+ );
+ return;
+ }
+ auto serverUrl = QString::fromStdString(res.dataStr("homeserverUrl"));
+ Q_EMIT discoverSuccessful(serverUrl);
+ getLoginFlows(serverUrl);
+ });
+ }
+}
+
+void MatrixSession::getLoginFlows(const QString &serverUrl)
+{
+ lager::get<JobInterface &>(m_context).submit(
+ Api::GetLoginFlowsJob(serverUrl.toStdString()),
+ [this](Api::GetLoginFlowsResponse r) {
+ if (!r.success()) {
+ Q_EMIT getLoginFlowsFailed(
+ QString::fromStdString(r.errorCode()),
+ QString::fromStdString(r.errorMessage())
+ );
+ return;
+ }
+ auto v = std::move(r).jsonBody().get().at("flows").template get<QJsonValue>();
+ Q_EMIT getLoginFlowsSuccessful(v);
+ }
+ );
+}
+
+QUrl MatrixSession::ssoLoginStart(const QString &homeserverUrl)
+{
+ if (m_ssoLoginProcess) {
+ m_ssoLoginProcess.reset();
+ }
+ m_ssoLoginProcess.reset(new SsoLoginProcess());
+ if (!m_ssoLoginProcess->startServer()) {
+ return QUrl();
+ }
+ auto link = m_ssoLoginProcess->getSsoLink(homeserverUrl);
+ connect(m_ssoLoginProcess.get(), &SsoLoginProcess::loginTokenAvailable,
+ this, [this, homeserverUrl](const QString &loginToken) {
+ Q_EMIT ssoLoginTokenAvailable();
+ qCInfo(kazvLog) << "Got SSO login token";
+ m_ssoLoginProcess.reset();
+ m_clientOnSecondaryRoot.mLoginTokenLogin(
+ homeserverUrl.toStdString(),
+ loginToken.toStdString(),
+ clientName
+ );
+ });
+ return link;
+}
+
+void MatrixSession::logout()
+{
+ m_clientOnSecondaryRoot.logout()
+ .then([&] (EffectStatus stat) {
+ if (stat.success()) {
+ Q_EMIT this->logoutSuccessful();
+ } else {
+ Q_EMIT this->logoutFailed(QString::fromStdString(stat.dataStr("errorCode")), QString::fromStdString(stat.dataStr("error")));
+ }
+ });
+}
+
+MatrixRoomList *MatrixSession::roomList() const
+{
+ return new MatrixRoomList(m_clientOnSecondaryRoot);
+}
+
+static std::optional<std::string> optMaybe(QString s)
+{
+ if (s.isEmpty()) {
+ return std::nullopt;
+ } else {
+ return s.toStdString();
+ }
+}
+
+MatrixPromise *MatrixSession::createRoom(
+ bool isPrivate,
+ const QString &name,
+ const QString &alias,
+ const QStringList &invite,
+ bool isDirect,
+ bool allowFederate,
+ const QString &topic,
+ const QJsonValue &powerLevelContentOverride,
+ Constants::CreateRoomPreset preset,
+ bool encrypted
+)
+{
+ immer::array<Event> initialState;
+
+ if (encrypted) {
+ initialState = {Event{json{
+ {"type", "m.room.encryption"},
+ {"state_key", ""},
+ {"content", {
+ {"algorithm", "m.megolm.v1.aes-sha2"},
+ }},
+ }}};
+ }
+
+ return new MatrixPromise(m_clientOnSecondaryRoot.createRoom(
+ isPrivate ? Kazv::RoomVisibility::Private : Kazv::RoomVisibility::Public,
+ optMaybe(name),
+ optMaybe(alias),
+ qStringListToStdF(invite),
+ isDirect,
+ allowFederate,
+ optMaybe(topic),
+ nlohmann::json(powerLevelContentOverride),
+ static_cast<Kazv::CreateRoomPreset>(preset),
+ initialState
+ ));
+}
+
+MatrixPromise *MatrixSession::joinRoom(const QString &idOrAlias, const QStringList &servers)
+{
+ return new MatrixPromise(m_clientOnSecondaryRoot.joinRoom(
+ idOrAlias.toStdString(),
+ qStringListToStdF(servers)
+ ));
+}
+
+MatrixPromise *MatrixSession::setDeviceTrustLevel(QString userId, QString deviceId, QString trustLevel)
+{
+ return new MatrixPromise(
+ m_clientOnSecondaryRoot.setDeviceTrustLevel(
+ userId.toStdString(),
+ deviceId.toStdString(),
+ qStringToTrustLevelFunc(trustLevel)
+ )
+ );
+}
+
+MatrixPromise *MatrixSession::getSelfProfile()
+{
+ return new MatrixPromise(
+ m_clientOnSecondaryRoot.getProfile(userId().toStdString())
+ );
+}
+
+MatrixPromise *MatrixSession::setDisplayName(QString displayName)
+{
+ return new MatrixPromise(
+ m_clientOnSecondaryRoot.setDisplayName(
+ displayName.isEmpty() ? std::nullopt : std::optional<std::string>(displayName.toStdString())
+ )
+ );
+}
+
+MatrixPromise *MatrixSession::setAvatarUrl(QString avatarUrl)
+{
+ return new MatrixPromise(
+ m_clientOnSecondaryRoot.setAvatarUrl(
+ avatarUrl.isEmpty() ? std::nullopt : std::optional<std::string>(avatarUrl.toStdString())
+ )
+ );
+}
+
+bool MatrixSession::shouldNotify(MatrixEvent *event) const
+{
+ // Do not notify own event
+ if (event->sender() == userId()) {
+ return false;
+ }
+ return m_notificationHandler.handleNotification(event->underlyingEvent()).shouldNotify;
+}
+
+bool MatrixSession::shouldPlaySound(MatrixEvent *event) const
+{
+ return m_notificationHandler.handleNotification(event->underlyingEvent()).sound.has_value();
+}
+
+MatrixStickerPackList *MatrixSession::stickerPackList() const
+{
+ return new MatrixStickerPackList(m_clientOnSecondaryRoot);
+}
+
+MatrixEvent *MatrixSession::stickerRoomsEvent() const
+{
+ return new MatrixEvent(m_clientOnSecondaryRoot.accountData()[imagePackRoomsEventType][lager::lenses::or_default]);
+}
+
+MatrixPromise *MatrixSession::updateStickerPack(MatrixStickerPackSource source)
+{
+ if (source.source == MatrixStickerPackSource::AccountData) {
+ auto eventJson = std::move(source.event).raw().get();
+ eventJson["type"] = source.eventType;
+ return sendAccountDataImpl(Event(std::move(eventJson)));
+ } else if (source.source == MatrixStickerPackSource::RoomState) {
+ auto eventJson = std::move(source.event).raw().get();
+ eventJson["type"] = source.eventType;
+ eventJson["state_key"] = source.stateKey;
+ return new MatrixPromise(
+ m_clientOnSecondaryRoot
+ .room(source.roomId)
+ .sendStateEvent(Event(std::move(eventJson))));
+ } else {
+ return 0;
+ }
+}
+
+MatrixUserGivenAttrsMap *MatrixSession::userGivenNicknameMap() const
+{
+ return new MatrixUserGivenAttrsMap(
+ userGivenNicknameMapFor(m_clientOnSecondaryRoot),
+ [client=m_clientOnSecondaryRoot](json content) {
+ return client.setAccountData(json{
+ {"type", USER_GIVEN_NICKNAME_EVENT_TYPES[0]},
+ {"content", std::move(content)},
+ });
+ }
+ );
+}
+
+MatrixPromise *MatrixSession::sendAccountData(const QString &type, const QJsonObject &content)
+{
+ Event e = json{
+ {"type", type.toStdString()},
+ {"content", content},
+ };
+ return sendAccountDataImpl(std::move(e));
+}
+
+MatrixPromise *MatrixSession::sendAccountDataImpl(Event event)
+{
+ return new MatrixPromise(m_clientOnSecondaryRoot.setAccountData(event));
+}
+
+MatrixPromise *MatrixSession::getSpecVersions()
+{
+ return new MatrixPromise(m_clientOnSecondaryRoot.getVersions(LAGER_QT(serverUrl).get().toStdString()));
+}
+
+MatrixPromise *MatrixSession::addDirectRoom(const QString &userId, const QString &roomId)
+{
+ return new MatrixPromise(m_clientOnSecondaryRoot.addDirectRoom(userId.toStdString(), roomId.toStdString()));
+}
+
+MatrixPromise *MatrixSession::getRoomIdByAlias(const QString &roomAlias)
+{
+ auto job = m_clientOnSecondaryRoot
+ .getRoomIdByAliasJob(roomAlias.toStdString());
+ return new MatrixPromise(
+ m_context.createPromise([ctx=m_context, job](auto resolve) {
+ lager::get<JobInterface &>(ctx).submit(job, [resolve](GetRoomIdByAliasResponse r) {
+ resolve(parseGetRoomIdByAliasResponse(r));
+ });
+ }));
+}
+
+inline constexpr std::size_t purgeEventsKeepNumber = 5;
+MatrixPromise *MatrixSession::purgeEventsExceptRooms(const QStringList &roomIds)
+{
+ return new MatrixPromise(
+ m_context.createResolvedPromise({})
+ .then([client=m_clientOnSecondaryRoot.toEventLoop(), roomIds=qStringListToStdF(roomIds)
+ ]([[maybe_unused]] auto &&stat) {
+ auto map = intoImmer(immer::map<std::string, std::size_t>{},
+ zug::filter([&roomIds](const std::string &roomId) {
+ return std::find(roomIds.begin(), roomIds.end(), roomId) == roomIds.end();
+ })
+ | zug::map([](const std::string &roomId) {
+ return std::make_pair(roomId, purgeEventsKeepNumber);
+ }),
+ client.roomIds().make().get()
+ );
+ return client.purgeRoomEvents(map);
+ }).then([](const auto &stat) {
+ qCDebug(kazvLog) << "Purge room events stat:" << !!stat;
+ return stat;
+ })
+ );
+}
+
+MatrixPromise *MatrixSession::backfillRoomFromEvent(const QString &roomId, const QString &eventId)
+{
+ return new MatrixPromise(
+ m_context.createPromise([
+ dbStoreGetter=m_dbStoreGetter,
+ client=m_clientOnSecondaryRoot.toEventLoop(),
+ roomId,
+ eventId
+ ](auto resolve) {
+ dbStoreGetter().getEventsBefore(roomId, eventId).then([client, resolve, roomId](auto &&res) {
+ auto [timelineEvents, relatedEvents] = std::move(res);
+ auto loadedCount = timelineEvents[roomId.toStdString()].size();
+ client.loadEventsFromStorage(timelineEvents, relatedEvents)
+ .then([resolve, loadedCount](auto &&) {
+ resolve(EffectStatus(
+ !!loadedCount,
+ json{{"loadedCount", loadedCount}}
+ ));
+ });
+ });
+ })
+ );
+}
+
+MatrixPromise *MatrixSession::importFromKeyBackupFile(QUrl fileUrl, QString password)
+{
+ if (!fileUrl.isLocalFile()) {
+ return new MatrixPromise(m_context.createResolvedPromise({
+ /* succ = */ false,
+ json{{"error", "Not a local file"}, {"errorCode", "NOT_LOCAL_FILE"}},
+ }));
+ }
+ auto filename = fileUrl.toLocalFile();
+ auto f = QFile(filename);
+ if (!f.open(QFile::ReadOnly)) {
+ return new MatrixPromise(m_context.createResolvedPromise({
+ /* succ = */ false,
+ json{{"error", "File open failed"}, {"errorCode", "FILE_OPEN_FAILED"}},
+ }));
+ }
+ auto ba = f.readAll();
+ auto content = std::string(ba.begin(), ba.end());
+ auto passwordStd = std::move(password).toStdString();
+ return new MatrixPromise(m_clientOnSecondaryRoot.importFromKeyBackupFile(
+ std::move(content), std::move(passwordStd)
+ ));
+}
+
+MatrixPromise *MatrixSession::requestVerifyDevice(QString userId, QString deviceId)
+{
+ return new MatrixPromise(m_clientOnSecondaryRoot.requestOutgoingToDeviceVerification(
+ std::move(userId).toStdString(),
+ std::move(deviceId).toStdString()
+ ));
+}
diff --git a/src/qt-promise-handler.hpp b/src/qt-promise-handler.hpp
--- a/src/qt-promise-handler.hpp
+++ b/src/qt-promise-handler.hpp
@@ -6,7 +6,7 @@
#pragma once
#include <kazv-defs.hpp>
-
+#include "kazv-log.hpp"
#include <future>
#include <QObject>
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -18,7 +18,8 @@
qt-promise-handler-test.cpp
qt-json-test.cpp
device-mgmt-test.cpp
- matrix-sdk-test.cpp
+ matrix-session-test.cpp
+ matrix-session-controller-test.cpp
matrix-sdk-sessions-test.cpp
matrix-promise-test.cpp
matrix-room-timeline-test.cpp
diff --git a/src/tests/kazv-io-manager-test.cpp b/src/tests/kazv-io-manager-test.cpp
--- a/src/tests/kazv-io-manager-test.cpp
+++ b/src/tests/kazv-io-manager-test.cpp
@@ -128,8 +128,8 @@
model.client.roomList.rooms =
model.client.roomList.rooms.set(room.roomId, room);
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
KazvIOManager manager;
auto job = manager.startNewUploadJob(QUrl{u"serverUrl"_s}, QUrl{u"localFileUrl"_s},
@@ -172,8 +172,8 @@
model.client.roomList.rooms =
model.client.roomList.rooms.set(room.roomId, room);
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
manager.startNewUploadJob(QUrl{u"serverUrl"_s}, QUrl{u"localFileUrl"_s},
u"token"_s, QString::fromStdString(room.roomId), roomList.get(), false,
u"relType"_s, u"relatedTo"_s);
diff --git a/src/tests/matrix-event-test.cpp b/src/tests/matrix-event-test.cpp
--- a/src/tests/matrix-event-test.cpp
+++ b/src/tests/matrix-event-test.cpp
@@ -46,8 +46,8 @@
}));
auto model = SdkModel{makeClient(withRoom(r))};
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
auto room = toUniquePtr(roomList->room(QString::fromStdString(r.roomId)));
auto timeline = toUniquePtr(room->timeline());
@@ -90,8 +90,8 @@
withRoomTimeline(events)(r);
auto model = SdkModel{makeClient(withRoom(r))};
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
auto room = toUniquePtr(roomList->room(QString::fromStdString(r.roomId)));
auto timeline = toUniquePtr(room->timeline());
@@ -147,8 +147,8 @@
withRoomTimeline(events)(r);
auto model = SdkModel{makeClient(withRoom(r))};
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
auto room = toUniquePtr(roomList->room(QString::fromStdString(r.roomId)));
auto timeline = toUniquePtr(room->timeline());
diff --git a/src/tests/matrix-room-list-test.cpp b/src/tests/matrix-room-list-test.cpp
--- a/src/tests/matrix-room-list-test.cpp
+++ b/src/tests/matrix-room-list-test.cpp
@@ -52,8 +52,8 @@
room.accountData = room.accountData.set("m.tag", tagEvent);
model.client.roomList.rooms = model.client.roomList.rooms.set(room.roomId, room);
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
QCOMPARE(roomList->count(), 2);
@@ -102,8 +102,8 @@
withRoom(room3)(model.client);
withRoom(room4)(model.client);
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
QCOMPARE(roomList->roomIdAt(0), QString::fromStdString(room4.roomId));
QCOMPARE(roomList->roomIdAt(1), QString::fromStdString(room3.roomId));
@@ -141,8 +141,8 @@
withRoom(room2)(model.client);
withRoom(room3)(model.client);
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
QCOMPARE(roomList->roomIdAt(0), QString::fromStdString(room3.roomId));
QCOMPARE(roomList->roomIdAt(1), QString::fromStdString(room1.roomId));
@@ -177,8 +177,8 @@
);
withAccountData({ nicknameEvent })(model.client);
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
roomList->setfilter(u"some"_s);
QCOMPARE(roomList->count(), 2);
@@ -222,8 +222,8 @@
model.client.roomList.rooms = model.client.roomList.rooms.set(
roomFavourited.roomId, roomFavourited);
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
QCOMPARE(roomList->count(), 3);
// Priority: Invite > Favourite
@@ -238,8 +238,8 @@
room.roomId = "!test:tusooa.xyz";
model.client.roomList.rooms = model.client.roomList.rooms.set(room.roomId, room);
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
QVERIFY(roomList->contains(u"!test:tusooa.xyz"_s));
QVERIFY(!roomList->contains(u"!notexist:tusooa.xyz"_s));
}
diff --git a/src/tests/matrix-room-state-test.cpp b/src/tests/matrix-room-state-test.cpp
--- a/src/tests/matrix-room-state-test.cpp
+++ b/src/tests/matrix-room-state-test.cpp
@@ -40,8 +40,8 @@
auto r = makeRoom(withRoomState(state));
auto c = makeClient(withRoom(r));
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(SdkModel{c})};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(SdkModel{c});
+ auto roomList = toUniquePtr(s.session.roomList());
auto room = toUniquePtr(roomList->room(QString::fromStdString(r.roomId)));
auto allState = toUniquePtr(room->allState());
diff --git a/src/tests/matrix-room-timeline-benchmark-test.cpp b/src/tests/matrix-room-timeline-benchmark-test.cpp
--- a/src/tests/matrix-room-timeline-benchmark-test.cpp
+++ b/src/tests/matrix-room-timeline-benchmark-test.cpp
@@ -73,8 +73,8 @@
};
auto model = SdkModel{makeClient(withRoom(r))};
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
auto room = toUniquePtr(roomList->room(QString::fromStdString(r.roomId)));
auto timeline = toUniquePtr(room->timeline());
diff --git a/src/tests/matrix-room-timeline-test.cpp b/src/tests/matrix-room-timeline-test.cpp
--- a/src/tests/matrix-room-timeline-test.cpp
+++ b/src/tests/matrix-room-timeline-test.cpp
@@ -41,8 +41,8 @@
void MatrixRoomTimelineTest::testLocalEcho()
{
auto model = makeTestModel();
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
auto room = toUniquePtr(roomList->room(u"!foo:tusooa.xyz"_s));
auto timeline = toUniquePtr(room->timeline());
@@ -68,8 +68,8 @@
r.eventReadUsers = {{"$1", {"@a:example.com", "@b:example.com"}}};
r.readReceipts = {{"@a:example.com", {"$1", 1234}}, {"@b:example.com", {"$2", 5678}}};
auto model = SdkModel{makeClient(withRoom(r))};
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
auto room = toUniquePtr(roomList->room(QString::fromStdString(r.roomId)));
auto timeline = toUniquePtr(room->timeline());
{
@@ -113,8 +113,8 @@
makeEvent(withEventId("$8") | withEventContent(json{{"body", "seventh"}}) | withEventRelationship("m.replace", "$1") | withEventType("moe.kazv.mxc.some-other-type")),
}));
auto model = SdkModel{makeClient(withRoom(r))};
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
auto room = toUniquePtr(roomList->room(QString::fromStdString(r.roomId)));
auto timeline = toUniquePtr(room->timeline());
@@ -146,8 +146,8 @@
};
auto model = SdkModel{makeClient(withRoom(r))};
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(model)};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(model);
+ auto roomList = toUniquePtr(s.session.roomList());
auto room = toUniquePtr(roomList->room(QString::fromStdString(r.roomId)));
auto timeline = toUniquePtr(room->timeline());
diff --git a/src/tests/matrix-sdk-session-loader.cpp b/src/tests/matrix-sdk-session-loader.cpp
--- a/src/tests/matrix-sdk-session-loader.cpp
+++ b/src/tests/matrix-sdk-session-loader.cpp
@@ -18,9 +18,9 @@
auto app = QCoreApplication(argc, argv);
auto sdk = MatrixSdkSessionsTest::makeMatrixSdkImpl(userDataDir);
QObject::connect(sdk.get(), &MatrixSdk::loadSessionFinished, [](auto, auto res) {
- if (res != MatrixSdk::SessionLoadSuccess) {
+ if (res != Constants::SessionLoadSuccess) {
std::cout << "cannot load session" << std::endl;
- std::exit(res == MatrixSdk::SessionLockFailed ? 1 : 2);
+ std::exit(res == Constants::SessionLockFailed ? 1 : 2);
}
std::cout << "loaded session" << std::endl;
});
diff --git a/src/tests/matrix-sdk-sessions-test.hpp b/src/tests/matrix-sdk-sessions-test.hpp
--- a/src/tests/matrix-sdk-sessions-test.hpp
+++ b/src/tests/matrix-sdk-sessions-test.hpp
@@ -8,6 +8,7 @@
#include <kazv-defs.hpp>
#include <memory>
#include <QObject>
+#include <QTemporaryDir>
#include <matrix-sdk.hpp>
class MatrixSdkSessionsTest : public QObject
@@ -15,6 +16,7 @@
Q_OBJECT
private:
+ QTemporaryDir m_dir;
std::string m_userDataDir;
void clearDir();
@@ -42,7 +44,5 @@
void testListSessions();
void testListLegacySessions();
- void testLoadSession();
void testSessionLock();
- void testSaveSessionFailure();
};
diff --git a/src/tests/matrix-sdk-sessions-test.cpp b/src/tests/matrix-sdk-sessions-test.cpp
--- a/src/tests/matrix-sdk-sessions-test.cpp
+++ b/src/tests/matrix-sdk-sessions-test.cpp
@@ -6,6 +6,7 @@
#include <kazv-defs.hpp>
#include <kazv-platform.hpp>
+#include <matrix-session-controller.hpp>
#include <memory>
#include <filesystem>
#include <fstream>
@@ -25,7 +26,7 @@
void MatrixSdkSessionsTest::initTestCase()
{
- auto dir = StdPath(kazvTestTempDir()) / "sessions-test";
+ auto dir = StdPath(m_dir.path().toStdString()) / "sessions-test";
m_userDataDir = dir.string();
}
@@ -35,6 +36,8 @@
std::error_code ec;
Fs::remove_all(StdPath(m_userDataDir), ec);
QVERIFY(!ec);
+ Fs::create_directories(StdPath(m_userDataDir), ec);
+ QVERIFY(!ec);
}
void MatrixSdkSessionsTest::init() { clearDir(); }
@@ -44,12 +47,14 @@
void MatrixSdkSessionsTest::createSession(std::string userId, std::string deviceId)
{
auto sessionsDir = StdPath(m_userDataDir) / "sessions";
+ auto thread = std::make_unique<QThread>();
SdkModel model;
model.client.userId = userId;
model.client.deviceId = deviceId;
{
- auto sdk = makeMatrixSdk(model, /* testing = */ false);
- sdk->serializeToFile();
+ auto controller = std::make_unique<MatrixSessionController>(thread.get(), m_userDataDir);
+ controller->createWithModel(model);
+ controller->save();
}
// Not ideal, but this is the only way to wait for
// MatrixSdkPravite to be destroyed.
@@ -97,20 +102,6 @@
QCOMPARE(sdk->allSessions(), expected);
}
-void MatrixSdkSessionsTest::testLoadSession()
-{
- createSession("@mew:example.com", "device4");
-
- auto sdk = makeMatrixSdk();
- auto spy = QSignalSpy(sdk.get(), &MatrixSdk::loadSessionFinished);
- sdk->loadSession(u"@mew:example.com/device4"_s);
- spy.wait();
- auto res = spy.first().at(1);
- QCOMPARE(res, MatrixSdk::SessionLoadSuccess);
- QCOMPARE(sdk->userId(), QStringLiteral("@mew:example.com"));
- QCOMPARE(sdk->deviceId(), QStringLiteral("device4"));
-}
-
void MatrixSdkSessionsTest::testSessionLock()
{
#if KAZV_IS_WINDOWS
@@ -140,71 +131,6 @@
#endif
}
-void MatrixSdkSessionsTest::testSaveSessionFailure()
-{
-#if KAZV_IS_WINDOWS
- QSKIP("Skipping because session the condition cannot be easily satisfied on Windows");
-#endif
-
- auto userId = std::string("@mew:example.com");
- auto deviceId = std::string("device1");
- createSession(userId, deviceId);
-
- auto sessionDir = sessionDirForUserAndDeviceId(Fs::path(m_userDataDir), userId, deviceId);
- // there is store, metadata and lock under the sessionDir
- auto dbFullDir = sessionDir / DbStore::dbDirName;
- auto dbName = dbFullDir / DbStore::dbBaseName;
- std::error_code err;
- Fs::create_directories(dbFullDir, err);
- QVERIFY(!err);
- {
- std::ofstream s(dbName, std::ios_base::binary);
- s.flush();
- }
-
- // make the sessionDir readonly, so that new file cannot be created
- Fs::permissions(
- sessionDir,
- Fs::perms::owner_read | Fs::perms::owner_exec,
- Fs::perm_options::replace,
- err);
- QVERIFY(!err);
- err.clear();
-
- // a model that is slightly different from the original one
- SdkModel model;
- model.client.userId = userId;
- model.client.deviceId = deviceId;
- model.client.serverUrl = "https://example.com";
-
- {
- auto sdk = makeMatrixSdk(model, /* testing = */ false);
- // this should fail
- sdk->serializeToFile();
- }
- // Not ideal, but this is the only way to wait for
- // MatrixSdkPravite to be destroyed.
- QTest::qWait(100);
-
- auto sdk = makeMatrixSdk();
- auto spy = QSignalSpy(sdk.get(), &MatrixSdk::loadSessionFinished);
- sdk->loadSession(QString::fromStdString(userId + "/" + deviceId));
- spy.wait();
- auto res = spy.first().at(1);
- QCOMPARE(res, MatrixSdk::SessionLoadSuccess);
- // verify that the original data is kept
- QCOMPARE(sdk->serverUrl(), u""_s);
-
- // before cleaning up, add write permissions back so the files can be removed
- Fs::permissions(
- sessionDir,
- Fs::perms::owner_read | Fs::perms::owner_write | Fs::perms::owner_exec,
- Fs::perm_options::replace,
- err);
- QVERIFY(!err);
- err.clear();
-}
-
#ifndef MATRIX_SDK_SESSIONS_TEST_NO_MAIN
QTEST_MAIN(MatrixSdkSessionsTest)
#endif
diff --git a/src/tests/matrix-session-controller-test.cpp b/src/tests/matrix-session-controller-test.cpp
new file mode 100644
--- /dev/null
+++ b/src/tests/matrix-session-controller-test.cpp
@@ -0,0 +1,158 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <kazv-defs.hpp>
+#include "test-utils.hpp"
+#include <matrix-session-controller.hpp>
+#include <matrix-session.hpp>
+#include <constants.hpp>
+#include <db-store.hpp>
+#include <QTemporaryDir>
+#include <QSignalSpy>
+#include <QtTest>
+#include <fstream>
+
+using namespace Qt::Literals::StringLiterals;
+using namespace Kazv;
+namespace Fs = std::filesystem;
+using StdPath = Fs::path;
+
+struct ControllerSetup
+{
+ QPointer<QThread> thread;
+ QTemporaryDir dir;
+ QPointer<MatrixSessionController> controller;
+
+ ControllerSetup(QObject *q)
+ : thread(new QThread(q))
+ , dir()
+ {
+ controller = new MatrixSessionController(thread, dir.path().toStdString(), q);
+ thread->start();
+ }
+
+ ~ControllerSetup()
+ {
+ controller->prepareDestroy();
+ thread->quit();
+ thread->wait();
+ controller->deleteLater();
+ thread->deleteLater();
+ }
+};
+
+class MatrixSessionControllerTest : public QObject
+{
+ Q_OBJECT
+
+ static void createSession(std::string userDataDir, std::string userId, std::string deviceId);
+
+private Q_SLOTS:
+ void testLoadSession();
+ void testSaveSessionFailure();
+};
+
+void MatrixSessionControllerTest::createSession(std::string userDataDir, std::string userId, std::string deviceId)
+{
+ SdkModel model;
+ model.client.userId = userId;
+ model.client.deviceId = deviceId;
+ QThread thread;
+ {
+ MatrixSessionController controller(&thread, userDataDir);
+ controller.createWithModel(model);
+ controller.save();
+ }
+}
+
+void MatrixSessionControllerTest::testLoadSession()
+{
+ auto s = ControllerSetup(this);
+ createSession(s.dir.path().toStdString(), "@user1:example.org", "device1");
+ s.controller->load(u"@user1:example.org/device1"_s);
+ auto spy = QSignalSpy(s.controller.get(), &MatrixSessionController::loadSessionFinished);
+ spy.wait();
+ auto res = spy.first().at(1);
+ QCOMPARE(res, Constants::SessionLoadSuccess);
+ auto session = toUniquePtr(s.controller->session());
+ QCOMPARE(session->userId(), u"@user1:example.org"_s);
+ QCOMPARE(session->deviceId(), u"device1"_s);
+}
+
+void MatrixSessionControllerTest::testSaveSessionFailure()
+{
+#if KAZV_IS_WINDOWS
+ QSKIP("Skipping because session the condition cannot be easily satisfied on Windows");
+#endif
+
+ auto s = ControllerSetup(this);
+
+ auto userId = std::string("@mew:example.com");
+ auto deviceId = std::string("device1");
+ auto userDataDir = s.dir.path().toStdString();
+ createSession(userDataDir, userId, deviceId);
+
+ auto sessionDir = sessionDirForUserAndDeviceId(Fs::path(userDataDir), userId, deviceId);
+ // there is store, metadata and lock under the sessionDir
+ auto dbFullDir = sessionDir / DbStore::dbDirName;
+ auto dbName = dbFullDir / DbStore::dbBaseName;
+ std::error_code err;
+ Fs::create_directories(dbFullDir, err);
+ QVERIFY(!err);
+ {
+ std::ofstream stream(dbName, std::ios_base::binary);
+ stream.flush();
+ }
+
+ // make the sessionDir readonly, so that new file cannot be created
+ Fs::permissions(
+ sessionDir,
+ Fs::perms::owner_read | Fs::perms::owner_exec,
+ Fs::perm_options::replace,
+ err);
+ QVERIFY(!err);
+ err.clear();
+
+ // a model that is slightly different from the original one
+ SdkModel model;
+ model.client.userId = userId;
+ model.client.deviceId = deviceId;
+ model.client.serverUrl = "https://example.com";
+
+ {
+ auto controller = MatrixSessionController(s.thread, userDataDir);
+ controller.createWithModel(model);
+ // this should fail
+ controller.save();
+ }
+ // Not ideal, but this is the only way to wait for
+ // MatrixSdkPravite to be destroyed.
+ QTest::qWait(100);
+
+ auto spy = QSignalSpy(s.controller.get(), &MatrixSessionController::loadSessionFinished);
+ s.controller->load(QString::fromStdString(userId + "/" + deviceId));
+ spy.wait();
+ auto res = spy.first().at(1);
+ QCOMPARE(res, Constants::SessionLoadSuccess);
+ // verify that the original data is kept
+ {
+ auto session = toUniquePtr(s.controller->session());
+ QCOMPARE(session->serverUrl(), u""_s);
+ }
+
+ // before cleaning up, add write permissions back so the files can be removed
+ Fs::permissions(
+ sessionDir,
+ Fs::perms::owner_read | Fs::perms::owner_write | Fs::perms::owner_exec,
+ Fs::perm_options::replace,
+ err);
+ QVERIFY(!err);
+ err.clear();
+}
+
+QTEST_MAIN(MatrixSessionControllerTest)
+
+#include "matrix-session-controller-test.moc"
diff --git a/src/tests/matrix-sdk-test.cpp b/src/tests/matrix-session-test.cpp
rename from src/tests/matrix-sdk-test.cpp
rename to src/tests/matrix-session-test.cpp
--- a/src/tests/matrix-sdk-test.cpp
+++ b/src/tests/matrix-session-test.cpp
@@ -5,24 +5,20 @@
*/
#include <kazv-defs.hpp>
-
-#include <memory>
-
-#include <QtTest>
-#include <QSignalSpy>
-
-#include <matrix-sdk.hpp>
+#include "test-model.hpp"
+#include "test-utils.hpp"
#include <matrix-device-list.hpp>
#include <matrix-device.hpp>
#include <matrix-promise.hpp>
-
-#include "test-model.hpp"
-#include "test-utils.hpp"
+#include <lager/event_loop/qt.hpp>
+#include <QtTest>
+#include <QSignalSpy>
+#include <memory>
using namespace Qt::Literals::StringLiterals;
using namespace Kazv;
-class MatrixSdkTest : public QObject
+class MatrixSessionTest : public QObject
{
Q_OBJECT
@@ -34,27 +30,25 @@
void testDirectRoomIds();
};
-void MatrixSdkTest::testDevicesOfUser()
+void MatrixSessionTest::testDevicesOfUser()
{
auto model = makeTestModel();
- std::unique_ptr<MatrixSdk> sdk{new MatrixSdk(model, /* testing = */ true)};
+ SessionSetup s(model);
- auto devices = toUniquePtr(sdk->devicesOfUser(QStringLiteral("@test1:test1.org")));
+ auto devices = toUniquePtr(s.session.devicesOfUser(QStringLiteral("@test1:test1.org")));
QVERIFY(devices->count() == 2);
auto dev = toUniquePtr(devices->at(0));
QVERIFY(dev->deviceId() == u"device1"_s);
QVERIFY(dev->trustLevel() == u"unseen"_s);
}
-void MatrixSdkTest::testSetDeviceTrustLevel()
+void MatrixSessionTest::testSetDeviceTrustLevel()
{
auto model = makeTestModel();
- std::unique_ptr<MatrixSdk> sdk{new MatrixSdk(model, /* testing = */ true)};
-
- sdk->startThread();
+ SessionSetup s(model);
auto promise = toUniquePtr(
- sdk->setDeviceTrustLevel(
+ s.session.setDeviceTrustLevel(
QStringLiteral("@test1:test1.org"),
QStringLiteral("device1"),
QStringLiteral("verified")
@@ -64,17 +58,17 @@
auto spy = QSignalSpy(promise.get(), &MatrixPromise::succeeded);
spy.wait();
- auto devices = toUniquePtr(sdk->devicesOfUser(QStringLiteral("@test1:test1.org")));
+ auto devices = toUniquePtr(s.session.devicesOfUser(QStringLiteral("@test1:test1.org")));
QVERIFY(devices->count() == 2);
auto dev = toUniquePtr(devices->at(0));
QVERIFY(dev->deviceId() == u"device1"_s);
QTRY_VERIFY(dev->trustLevel() == u"verified"_s); // wait for the change to propagate to this thread
}
-void MatrixSdkTest::testValidateHomeserverUrl()
+void MatrixSessionTest::testValidateHomeserverUrl()
{
auto v = [](const QString &u) {
- return QString::fromStdString(MatrixSdk::validateHomeserverUrl(u));
+ return QString::fromStdString(MatrixSession::validateHomeserverUrl(u));
};
QCOMPARE(v(u"example.com"_s), u"https://example.com"_s);
@@ -84,32 +78,38 @@
QCOMPARE(v(u"ea.pl"_s), u"https://ea.pl"_s);
}
-void MatrixSdkTest::testSpecVersion()
+void MatrixSessionTest::testSpecVersion()
{
auto model = makeTestModel();
model.client.versions = immer::array{"v1.11"s, "v1.12"s};
- std::unique_ptr<MatrixSdk> sdk{new MatrixSdk(model, /* testing = */ true)};
- QVERIFY(sdk->checkSpecVersion(u"r0.5.0"_s));
- QVERIFY(sdk->checkSpecVersion(u"v1.10"_s));
- QVERIFY(sdk->checkSpecVersion(u"v1.11"_s));
- QVERIFY(!sdk->checkSpecVersion(u"v1.13"_s));
- QVERIFY(!sdk->checkSpecVersion(u"mew"_s));
- QVERIFY(sdk->checkSpecVersionRange(u"r0.5.0"_s, u"v1.12"_s));
- QVERIFY(sdk->checkSpecVersionRange(u"v1.10"_s, u"v1.12"_s));
- QVERIFY(sdk->checkSpecVersionRange(u"v1.11"_s, u"v1.13"_s));
- QVERIFY(!sdk->checkSpecVersionRange(u"r0.4.0"_s, u"v1.9"_s));
- QVERIFY(!sdk->checkSpecVersionRange(u"v1.13"_s, u"v1.14"_s));
+
+ {
+ SessionSetup s(model);
+
+ QVERIFY(s.session.checkSpecVersion(u"r0.5.0"_s));
+ QVERIFY(s.session.checkSpecVersion(u"v1.10"_s));
+ QVERIFY(s.session.checkSpecVersion(u"v1.11"_s));
+ QVERIFY(!s.session.checkSpecVersion(u"v1.13"_s));
+ QVERIFY(!s.session.checkSpecVersion(u"mew"_s));
+ QVERIFY(s.session.checkSpecVersionRange(u"r0.5.0"_s, u"v1.12"_s));
+ QVERIFY(s.session.checkSpecVersionRange(u"v1.10"_s, u"v1.12"_s));
+ QVERIFY(s.session.checkSpecVersionRange(u"v1.11"_s, u"v1.13"_s));
+ QVERIFY(!s.session.checkSpecVersionRange(u"r0.4.0"_s, u"v1.9"_s));
+ QVERIFY(!s.session.checkSpecVersionRange(u"v1.13"_s, u"v1.14"_s));
+ }
model.client.versions = immer::array{"r0.4.0"s};
- sdk.reset(new MatrixSdk(model, /* testing = */ true));
- QVERIFY(sdk->checkSpecVersion(u"r0.4.0"_s));
- QVERIFY(!sdk->checkSpecVersion(u"v1.1"_s));
- QVERIFY(sdk->checkSpecVersionRange(u"r0.3.5"_s, u"r0.4.0"_s));
- QVERIFY(!sdk->checkSpecVersionRange(u"r0.3.0"_s, u"r0.3.5"_s));
- QVERIFY(!sdk->checkSpecVersionRange(u"r0.4.1"_s, u"r0.4.5"_s));
- QVERIFY(!sdk->checkSpecVersionRange(u"v1.1"_s, u"v1.2"_s));
+ {
+ SessionSetup s(model);
+ QVERIFY(s.session.checkSpecVersion(u"r0.4.0"_s));
+ QVERIFY(!s.session.checkSpecVersion(u"v1.1"_s));
+ QVERIFY(s.session.checkSpecVersionRange(u"r0.3.5"_s, u"r0.4.0"_s));
+ QVERIFY(!s.session.checkSpecVersionRange(u"r0.3.0"_s, u"r0.3.5"_s));
+ QVERIFY(!s.session.checkSpecVersionRange(u"r0.4.1"_s, u"r0.4.5"_s));
+ QVERIFY(!s.session.checkSpecVersionRange(u"v1.1"_s, u"v1.2"_s));
+ }
}
-void MatrixSdkTest::testDirectRoomIds()
+void MatrixSessionTest::testDirectRoomIds()
{
auto model = makeTestModel();
auto j = R"({
@@ -122,13 +122,13 @@
}
})"_json;
model.client.accountData = model.client.accountData.set("m.direct", j);
- std::unique_ptr<MatrixSdk> sdk{new MatrixSdk(model, /* testing = */ true)};
+ SessionSetup s(model);
const auto rooms = QStringList{u"!somewhere1:example.org"_s, u"!somewhere2:example.org"_s};
- const auto directRoomIds = sdk->directRoomIds(u"@mew:example.org"_s);
+ const auto directRoomIds = s.session.directRoomIds(u"@mew:example.org"_s);
QCOMPARE(QSet(directRoomIds.begin(), directRoomIds.end()),
QSet(rooms.begin(), rooms.end()));
}
-QTEST_MAIN(MatrixSdkTest)
+QTEST_MAIN(MatrixSessionTest)
-#include "matrix-sdk-test.moc"
+#include "matrix-session-test.moc"
diff --git a/src/tests/matrix-sticker-pack-test.cpp b/src/tests/matrix-sticker-pack-test.cpp
--- a/src/tests/matrix-sticker-pack-test.cpp
+++ b/src/tests/matrix-sticker-pack-test.cpp
@@ -179,8 +179,8 @@
| withRoomState({getRoomStickersEvent("", "Pack 3")})
))
);
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(SdkModel{model})};
- auto stickerPackList = toUniquePtr(sdk->stickerPackList());
+ SessionSetup s(SdkModel{model});
+ auto stickerPackList = toUniquePtr(s.session.stickerPackList());
QCOMPARE(stickerPackList->rowCount(QModelIndex()), 4);
QCOMPARE(stickerPackList->count(), 4);
@@ -267,8 +267,8 @@
})
))
);
- std::unique_ptr<MatrixSdk> sdk{makeTestSdk(SdkModel{model})};
- auto roomList = toUniquePtr(sdk->roomList());
+ SessionSetup s(SdkModel{model});
+ auto roomList = toUniquePtr(s.session.roomList());
auto room = toUniquePtr(roomList->room(u"!someroom:example.org"_s));
auto stickerPackList = toUniquePtr(room->stickerPackList());
QCOMPARE(stickerPackList->count(), 2);
diff --git a/src/tests/quick-tests/test-helpers/MatrixSdkMock.qml b/src/tests/quick-tests/test-helpers/MatrixSdkMock.qml
--- a/src/tests/quick-tests/test-helpers/MatrixSdkMock.qml
+++ b/src/tests/quick-tests/test-helpers/MatrixSdkMock.qml
@@ -7,84 +7,16 @@
import QtQuick 2.15
QtObject {
- property var userId: ''
- property var serverUrl: 'https://example.com'
- property var token: 'token'
- property var updateStickerPack: mockHelper.promise()
- property var createRoom: mockHelper.promise([
- 'isPrivate',
- 'name',
- 'alias',
- 'invites',
- 'isDirect',
- 'allowFederate',
- 'topic',
- 'powerLevelContentOverride',
- 'preset',
- 'encrypted',
- ])
- property var joinRoom: mockHelper.promise()
- property var sendAccountData: mockHelper.promise()
- property var login: mockHelper.noop()
- property var ssoLoginStart: mockHelper.func((serverUrl) => serverUrl + '/_matrix/client/v3/login/sso/redirect?redirectUrl=http://127.0.0.1:7456/sso-redirect/random')
- property var discoverAndGetLoginFlows: mockHelper.noop()
- property var addDirectRoom: mockHelper.promise([
- 'userId',
- 'roomId'
- ])
- property var getRoomIdByAlias: mockHelper.promise([
- 'roomAlias'
- ])
- property var importFromKeyBackupFile: mockHelper.promise([
- 'fileUrl',
- 'password',
- ])
- property var requestVerifyDevice: mockHelper.promise([
- 'userId',
- 'deviceId',
- ])
-
+ id: matrixSdkMock
property var sessions: []
- property var specVersions: ["v1.11"]
-
- signal discoverFailed(string errorCode, string errorMsg)
- signal discoverSuccessful(string serverUrl)
- signal getLoginFlowsFailed(string errorCode, string errorMsg)
- signal getLoginFlowsSuccessful(var flows)
- signal loginFailed(string errorCode, string errorMsg)
-
function allSessions() {
return sessions;
}
- function mxcUriToHttp (uri) {
- console.log('mxcUriToHttp');
- return uri || '';
- }
-
- function mxcUriToHttpAuthenticatedV1 (uri) {
- console.log('mxcUriToHttpAuthenticatedV1');
- return uri || '';
- }
+ signal sessionChanged()
- function devicesOfUser (userId) {
- return [];
- }
-
- function checkSpecVersion (ver) {
- return !!specVersions.includes(ver);
- }
-
- function directRoomIds(userId) {
- const directRoomMap = {
- "@someonejoined:example.org": ["!joinedroomid:example.org"],
- "@someoneinvited:example.org": ["!invitedroomid:example.org"],
- "@someoneleft:example.org": ["!leftroomid:example.org"]
- };
- if (!directRoomMap[userId]) {
- return [];
- }
- return directRoomMap[userId];
- }
+ property var startNewSession: mockHelper.func(() => {
+ matrixSdkMock.sessionChanged();
+ })
}
diff --git a/src/tests/quick-tests/test-helpers/MatrixSdkMock.qml b/src/tests/quick-tests/test-helpers/MatrixSessionMock.qml
copy from src/tests/quick-tests/test-helpers/MatrixSdkMock.qml
copy to src/tests/quick-tests/test-helpers/MatrixSessionMock.qml
--- a/src/tests/quick-tests/test-helpers/MatrixSdkMock.qml
+++ b/src/tests/quick-tests/test-helpers/MatrixSessionMock.qml
@@ -1,10 +1,10 @@
/*
* This file is part of kazv.
- * SPDX-FileCopyrightText: 2023 tusooa <tusooa@kazv.moe>
+ * SPDX-FileCopyrightText: 2023-2026 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-import QtQuick 2.15
+import QtQuick
QtObject {
property var userId: ''
@@ -44,8 +44,6 @@
'deviceId',
])
- property var sessions: []
-
property var specVersions: ["v1.11"]
signal discoverFailed(string errorCode, string errorMsg)
@@ -54,10 +52,6 @@
signal getLoginFlowsSuccessful(var flows)
signal loginFailed(string errorCode, string errorMsg)
- function allSessions() {
- return sessions;
- }
-
function mxcUriToHttp (uri) {
console.log('mxcUriToHttp');
return uri || '';
diff --git a/src/tests/quick-tests/test-helpers/TestItem.qml b/src/tests/quick-tests/test-helpers/TestItem.qml
--- a/src/tests/quick-tests/test-helpers/TestItem.qml
+++ b/src/tests/quick-tests/test-helpers/TestItem.qml
@@ -19,7 +19,12 @@
property var promiseComp: Component {
QmlHelpers.MatrixPromiseMock {}
}
+ property var matrixSession: QmlHelpers.MatrixSessionMock {
+ }
property var matrixSdk: QmlHelpers.MatrixSdkMock {
+ function session() {
+ return item.matrixSession;
+ }
}
property var sdkVars: QtObject {
property var roomList: ({})
diff --git a/src/tests/quick-tests/tst_AddStickerPopup.qml b/src/tests/quick-tests/tst_AddStickerPopup.qml
--- a/src/tests/quick-tests/tst_AddStickerPopup.qml
+++ b/src/tests/quick-tests/tst_AddStickerPopup.qml
@@ -72,8 +72,8 @@
const button = findChild(addStickerPopup, 'addStickerButton');
verify(button.enabled);
mouseClick(button);
- tryVerify(() => matrixSdk.updateStickerPack.calledTimes() === 1);
- verify(Helpers.deepEqual(matrixSdk.updateStickerPack.lastArgs()[0].event.content.images, {
+ tryVerify(() => matrixSession.updateStickerPack.calledTimes() === 1);
+ verify(Helpers.deepEqual(matrixSession.updateStickerPack.lastArgs()[0].event.content.images, {
'bar': {
url: 'mxc://example.org/something',
}
@@ -82,7 +82,7 @@
tryVerify(() => !button.enabled);
tryVerify(() => findChild(addStickerPopup, 'shortCodeInput').readOnly);
verify(addStickerPopup.close.calledTimes() === 0);
- matrixSdk.updateStickerPack.lastRetVal().resolve(true, {});
+ matrixSession.updateStickerPack.lastRetVal().resolve(true, {});
tryVerify(() => addStickerPopup.close.calledTimes() === 1);
}
@@ -94,8 +94,8 @@
const button = findChild(addStickerPopup, 'addStickerButton');
verify(button.enabled);
mouseClick(button);
- tryVerify(() => matrixSdk.updateStickerPack.calledTimes() === 1);
- compare(matrixSdk.updateStickerPack.lastArgs()[0]._packIndex, 1);
+ tryVerify(() => matrixSession.updateStickerPack.calledTimes() === 1);
+ compare(matrixSession.updateStickerPack.lastArgs()[0]._packIndex, 1);
}
function test_addStickerFailed() {
@@ -104,13 +104,13 @@
const button = findChild(addStickerPopup, 'addStickerButton');
verify(button.enabled);
mouseClick(button);
- tryVerify(() => matrixSdk.updateStickerPack.calledTimes() === 1);
- verify(Helpers.deepEqual(matrixSdk.updateStickerPack.lastArgs()[0].event.content.images, {
+ tryVerify(() => matrixSession.updateStickerPack.calledTimes() === 1);
+ verify(Helpers.deepEqual(matrixSession.updateStickerPack.lastArgs()[0].event.content.images, {
'bar': {
url: 'mxc://example.org/something',
}
}));
- matrixSdk.updateStickerPack.lastRetVal().resolve(false, {});
+ matrixSession.updateStickerPack.lastRetVal().resolve(false, {});
tryVerify(() => button.enabled);
verify(addStickerPopup.close.calledTimes() === 0);
}
@@ -121,8 +121,8 @@
const button = findChild(addStickerPopup, 'addStickerButton');
verify(button.enabled);
mouseClick(button);
- tryVerify(() => matrixSdk.updateStickerPack.calledTimes() === 1);
- verify(Helpers.deepEqual(matrixSdk.updateStickerPack.lastArgs()[0].event.content.images, {
+ tryVerify(() => matrixSession.updateStickerPack.calledTimes() === 1);
+ verify(Helpers.deepEqual(matrixSession.updateStickerPack.lastArgs()[0].event.content.images, {
'foo': {
url: 'mxc://example.org/something',
}
@@ -131,7 +131,7 @@
tryVerify(() => !button.enabled);
tryVerify(() => findChild(addStickerPopup, 'shortCodeInput').readOnly);
verify(addStickerPopup.close.calledTimes() === 0);
- matrixSdk.updateStickerPack.lastRetVal().resolve(true, {});
+ matrixSession.updateStickerPack.lastRetVal().resolve(true, {});
tryVerify(() => addStickerPopup.close.calledTimes() === 1);
}
}
diff --git a/src/tests/quick-tests/tst_CreateRoomPage.qml b/src/tests/quick-tests/tst_CreateRoomPage.qml
--- a/src/tests/quick-tests/tst_CreateRoomPage.qml
+++ b/src/tests/quick-tests/tst_CreateRoomPage.qml
@@ -51,8 +51,8 @@
verify(button.enabled);
mouseClick(button);
- tryVerify(() => item.matrixSdk.createRoom.calledTimes() === 1, 1000);
- verify(JsHelpers.deepEqual(item.matrixSdk.createRoom.lastArgs(), {
+ tryVerify(() => item.matrixSession.createRoom.calledTimes() === 1, 1000);
+ verify(JsHelpers.deepEqual(item.matrixSession.createRoom.lastArgs(), {
isPrivate: false,
name: 'some name',
alias: 'alias',
@@ -61,7 +61,7 @@
isDirect: false,
allowFederate: true,
powerLevelContentOverride: {},
- preset: MK.MatrixSdk.PublicChat,
+ preset: MK.Constants.PublicChat,
encrypted: false,
}));
}
@@ -76,8 +76,8 @@
verify(button.enabled);
mouseClick(button);
- tryVerify(() => item.matrixSdk.createRoom.calledTimes() === 1, 1000);
- verify(JsHelpers.deepEqual(item.matrixSdk.createRoom.lastArgs(), {
+ tryVerify(() => item.matrixSession.createRoom.calledTimes() === 1, 1000);
+ verify(JsHelpers.deepEqual(item.matrixSession.createRoom.lastArgs(), {
isPrivate: true,
name: 'some name',
alias: 'alias',
@@ -86,7 +86,7 @@
isDirect: false,
allowFederate: true,
powerLevelContentOverride: {},
- preset: MK.MatrixSdk.PrivateChat,
+ preset: MK.Constants.PrivateChat,
encrypted: true,
}));
}
@@ -101,8 +101,8 @@
verify(button.enabled);
mouseClick(button);
- tryVerify(() => item.matrixSdk.createRoom.calledTimes() === 1, 1000);
- verify(JsHelpers.deepEqual(item.matrixSdk.createRoom.lastArgs(), {
+ tryVerify(() => item.matrixSession.createRoom.calledTimes() === 1, 1000);
+ verify(JsHelpers.deepEqual(item.matrixSession.createRoom.lastArgs(), {
isPrivate: true,
name: 'some name',
alias: 'alias',
@@ -111,10 +111,10 @@
isDirect: false,
allowFederate: true,
powerLevelContentOverride: {},
- preset: MK.MatrixSdk.TrustedPrivateChat,
+ preset: MK.Constants.TrustedPrivateChat,
encrypted: true,
}));
- tryVerify(() => item.matrixSdk.addDirectRoom.calledTimes() === 0, 1000);
+ tryVerify(() => item.matrixSession.addDirectRoom.calledTimes() === 0, 1000);
}
function test_createRoomDirectInviteOne() {
@@ -134,8 +134,8 @@
verify(button.enabled);
mouseClick(button);
- tryVerify(() => item.matrixSdk.createRoom.calledTimes() === 1, 1000);
- verify(JsHelpers.deepEqual(item.matrixSdk.createRoom.lastArgs(), {
+ tryVerify(() => item.matrixSession.createRoom.calledTimes() === 1, 1000);
+ verify(JsHelpers.deepEqual(item.matrixSession.createRoom.lastArgs(), {
isPrivate: true,
name: 'some name',
alias: 'alias',
@@ -144,12 +144,12 @@
isDirect: true,
allowFederate: true,
powerLevelContentOverride: {},
- preset: MK.MatrixSdk.TrustedPrivateChat,
+ preset: MK.Constants.TrustedPrivateChat,
encrypted: true,
}));
- item.matrixSdk.createRoom.lastRetVal().resolve(true, { 'roomId': '!somewhere:example.org' });
- tryVerify(() => item.matrixSdk.addDirectRoom.calledTimes() === 1, 1000);
- verify(JsHelpers.deepEqual(item.matrixSdk.addDirectRoom.lastArgs(), {
+ item.matrixSession.createRoom.lastRetVal().resolve(true, { 'roomId': '!somewhere:example.org' });
+ tryVerify(() => item.matrixSession.addDirectRoom.calledTimes() === 1, 1000);
+ verify(JsHelpers.deepEqual(item.matrixSession.addDirectRoom.lastArgs(), {
userId: '@foo:example.org',
roomId: '!somewhere:example.org'
}));
@@ -176,8 +176,8 @@
verify(button.enabled);
mouseClick(button);
- tryVerify(() => item.matrixSdk.createRoom.calledTimes() === 1, 1000);
- verify(JsHelpers.deepEqual(item.matrixSdk.createRoom.lastArgs(), {
+ tryVerify(() => item.matrixSession.createRoom.calledTimes() === 1, 1000);
+ verify(JsHelpers.deepEqual(item.matrixSession.createRoom.lastArgs(), {
isPrivate: true,
name: 'some name',
alias: 'alias',
@@ -186,7 +186,7 @@
isDirect: false,
allowFederate: true,
powerLevelContentOverride: {},
- preset: MK.MatrixSdk.TrustedPrivateChat,
+ preset: MK.Constants.TrustedPrivateChat,
encrypted: true,
}));
}
@@ -230,8 +230,8 @@
return label && label.text === '@baz:example.org'
}, 50000);
- tryVerify(() => item.matrixSdk.createRoom.calledTimes() === 1, 1000);
- verify(JsHelpers.deepEqual(item.matrixSdk.createRoom.lastArgs(), {
+ tryVerify(() => item.matrixSession.createRoom.calledTimes() === 1, 1000);
+ verify(JsHelpers.deepEqual(item.matrixSession.createRoom.lastArgs(), {
isPrivate: false,
name: 'some name',
alias: 'alias',
@@ -240,7 +240,7 @@
isDirect: false,
allowFederate: true,
powerLevelContentOverride: {},
- preset: MK.MatrixSdk.PublicChat,
+ preset: MK.Constants.PublicChat,
encrypted: false,
}));
}
diff --git a/src/tests/quick-tests/tst_Device.qml b/src/tests/quick-tests/tst_Device.qml
--- a/src/tests/quick-tests/tst_Device.qml
+++ b/src/tests/quick-tests/tst_Device.qml
@@ -49,7 +49,7 @@
verify(!action.enabled);
verify(item.pushVerificationsPage.calledTimes() == 0);
verify(device.sendingVerification);
- item.matrixSdk.requestVerifyDevice.lastRetVal().resolve(true, {});
+ item.matrixSession.requestVerifyDevice.lastRetVal().resolve(true, {});
verify(item.pushVerificationsPage.calledTimes() == 1);
}
@@ -60,7 +60,7 @@
verify(!action.enabled);
verify(item.pushVerificationsPage.calledTimes() == 0);
verify(device.sendingVerification);
- item.matrixSdk.requestVerifyDevice.lastRetVal().resolve(false, {});
+ item.matrixSession.requestVerifyDevice.lastRetVal().resolve(false, {});
verify(item.pushVerificationsPage.calledTimes() == 0);
verify(action.enabled);
verify(item.showPassiveNotification.calledTimes() == 1);
diff --git a/src/tests/quick-tests/tst_EventReactions.qml b/src/tests/quick-tests/tst_EventReactions.qml
--- a/src/tests/quick-tests/tst_EventReactions.qml
+++ b/src/tests/quick-tests/tst_EventReactions.qml
@@ -76,7 +76,7 @@
function init() {
item.mockHelper.clearAll();
- item.matrixSdk.userId = '@foo0:example.com';
+ item.matrixSession.userId = '@foo0:example.com';
}
function test_reactionEvent() {
diff --git a/src/tests/quick-tests/tst_EventView.qml b/src/tests/quick-tests/tst_EventView.qml
--- a/src/tests/quick-tests/tst_EventView.qml
+++ b/src/tests/quick-tests/tst_EventView.qml
@@ -459,7 +459,7 @@
when: windowShown
function init() {
- item.matrixSdk.userId = '@foo:tusooa.xyz';
+ item.matrixSession.userId = '@foo:tusooa.xyz';
eventView.event = item.localEcho;
mockHelper.clearAll();
}
diff --git a/src/tests/quick-tests/tst_FileHandler.qml b/src/tests/quick-tests/tst_FileHandler.qml
--- a/src/tests/quick-tests/tst_FileHandler.qml
+++ b/src/tests/quick-tests/tst_FileHandler.qml
@@ -97,12 +97,12 @@
return "file:///somefileurl";
}
}
- property var matrixSdk: QmlHelpers.MatrixSdkMock {}
- property var matrixSdkUnauthenticatedMediaV3: QmlHelpers.MatrixSdkMock {
+ property var matrixSession: QmlHelpers.MatrixSessionMock {}
+ property var matrixSessionUnauthenticatedMediaV3: QmlHelpers.MatrixSessionMock {
specVersions: []
property var mxcUriToHttp: mockHelper.noop()
}
- property var matrixSdkAuthenticatedMediaV1: QmlHelpers.MatrixSdkMock {
+ property var matrixSessionAuthenticatedMediaV1: QmlHelpers.MatrixSessionMock {
property var mxcUriToHttpAuthenticatedV1: mockHelper.noop()
}
@@ -111,7 +111,7 @@
eventContent: ({})
autoCache: false
kazvIOManager: item.kazvIOManager
- matrixSdk: item.matrixSdk
+ matrixSession: item.matrixSession
}
TestCase {
@@ -122,20 +122,20 @@
function init() {
fileHandler.autoCache = false;
fileHandler.eventContent = ({});
- fileHandler.matrixSdk = item.matrixSdk;
+ fileHandler.matrixSession = item.matrixSession;
fileHandler.kazvIOManager = kazvIOManager;
mockHelper.clearAll();
}
// https://spec.matrix.org/v1.16/client-server-api/#get_matrixmediav3downloadservernamemediaid
function test_unauthenticatedMediaV3() {
- fileHandler.matrixSdk = matrixSdkUnauthenticatedMediaV3;
+ fileHandler.matrixSession = matrixSessionUnauthenticatedMediaV3;
fileHandler.autoCache = true;
fileHandler.eventContent = unencryptedEventContent;
- compare(fileHandler.httpVer, MK.MatrixSdk.UnauthenticatedMediaV3);
- compare(matrixSdkUnauthenticatedMediaV3.mxcUriToHttp.calledTimes(), 1);
- compare(matrixSdkUnauthenticatedMediaV3.mxcUriToHttp.lastArgs()[0], "mxc://someunencrypted");
+ compare(fileHandler.httpVer, MK.Constants.UnauthenticatedMediaV3);
+ compare(matrixSessionUnauthenticatedMediaV3.mxcUriToHttp.calledTimes(), 1);
+ compare(matrixSessionUnauthenticatedMediaV3.mxcUriToHttp.lastArgs()[0], "mxc://someunencrypted");
compare(kazvIOManager.cacheFile.calledTimes(), 1);
compare(kazvIOManager.cacheFile.lastArgs()[3], "");
@@ -146,19 +146,19 @@
// https://spec.matrix.org/v1.16/client-server-api/#get_matrixclientv1mediadownloadservernamemediaid
function test_authenticatedMediaV1() {
- fileHandler.matrixSdk = matrixSdkAuthenticatedMediaV1;
+ fileHandler.matrixSession = matrixSessionAuthenticatedMediaV1;
fileHandler.autoCache = true;
fileHandler.eventContent = unencryptedEventContent;
- compare(fileHandler.httpVer, MK.MatrixSdk.AuthenticatedMediaV1);
- compare(fileHandler.matrixSdk.mxcUriToHttpAuthenticatedV1.calledTimes(), 1);
- compare(fileHandler.matrixSdk.mxcUriToHttpAuthenticatedV1.lastArgs()[0], "mxc://someunencrypted");
+ compare(fileHandler.httpVer, MK.Constants.AuthenticatedMediaV1);
+ compare(fileHandler.matrixSession.mxcUriToHttpAuthenticatedV1.calledTimes(), 1);
+ compare(fileHandler.matrixSession.mxcUriToHttpAuthenticatedV1.lastArgs()[0], "mxc://someunencrypted");
compare(kazvIOManager.cacheFile.calledTimes(), 1);
- compare(kazvIOManager.cacheFile.lastArgs()[3], fileHandler.matrixSdk.token);
+ compare(kazvIOManager.cacheFile.lastArgs()[3], fileHandler.matrixSession.token);
fileHandler.downloadFile("fileUrl");
compare(kazvIOManager.startNewDownloadJob.calledTimes(), 1);
- compare(kazvIOManager.startNewDownloadJob.lastArgs()[4], fileHandler.matrixSdk.token);
+ compare(kazvIOManager.startNewDownloadJob.lastArgs()[4], fileHandler.matrixSession.token);
}
function test_autoCacheEncrypted() {
@@ -167,7 +167,7 @@
const cacheFunc = kazvIOManager.cacheFile;
compare(cacheFunc.calledTimes(), 1);
compare(cacheFunc.lastArgs()[0],
- matrixSdk.mxcUriToHttpAuthenticatedV1("mxc://someencrypted"));
+ matrixSession.mxcUriToHttpAuthenticatedV1("mxc://someencrypted"));
compare(cacheFunc.lastArgs()[2], "somesha256hash");
compare(cacheFunc.lastArgs()[4], "somekey");
compare(cacheFunc.lastArgs()[5], "someiv");
@@ -179,7 +179,7 @@
const cacheFunc = kazvIOManager.cacheFile;
compare(cacheFunc.calledTimes(), 1);
compare(cacheFunc.lastArgs()[0],
- matrixSdk.mxcUriToHttpAuthenticatedV1("mxc://someunencrypted"));
+ matrixSession.mxcUriToHttpAuthenticatedV1("mxc://someunencrypted"));
}
// Prefer thumbnail when caching
@@ -189,7 +189,7 @@
const cacheFunc = kazvIOManager.cacheFile;
compare(cacheFunc.calledTimes(), 1);
compare(cacheFunc.lastArgs()[0],
- matrixSdk.mxcUriToHttpAuthenticatedV1("mxc://someunencryptedthumbnail"));
+ matrixSession.mxcUriToHttpAuthenticatedV1("mxc://someunencryptedthumbnail"));
}
function test_autoCacheEncryptedThumbnail() {
@@ -198,7 +198,7 @@
const cacheFunc = kazvIOManager.cacheFile;
compare(cacheFunc.calledTimes(), 1);
compare(cacheFunc.lastArgs()[0],
- matrixSdk.mxcUriToHttpAuthenticatedV1("mxc://someencryptedthumbnail"));
+ matrixSession.mxcUriToHttpAuthenticatedV1("mxc://someencryptedthumbnail"));
compare(cacheFunc.lastArgs()[2], "somesha256hashofthumbnail");
compare(cacheFunc.lastArgs()[4], "somekeyofthumbnail");
compare(cacheFunc.lastArgs()[5], "someivofthumbnail");
@@ -209,7 +209,7 @@
fileHandler.downloadFile("fileUrl");
const downloadFunc = kazvIOManager.startNewDownloadJob;
compare(downloadFunc.calledTimes(), 1);
- compare(downloadFunc.lastArgs()[0], matrixSdk.mxcUriToHttpAuthenticatedV1("mxc://someencrypted"));
+ compare(downloadFunc.lastArgs()[0], matrixSession.mxcUriToHttpAuthenticatedV1("mxc://someencrypted"));
compare(downloadFunc.lastArgs()[1], "fileUrl");
compare(downloadFunc.lastArgs()[3], "somesha256hash");
compare(downloadFunc.lastArgs()[5], "somekey");
@@ -223,7 +223,7 @@
compare(downloadFunc.calledTimes(), 1);
const args = downloadFunc.lastArgs();
- compare(downloadFunc.lastArgs()[0], matrixSdk.mxcUriToHttpAuthenticatedV1("mxc://someunencrypted"));
+ compare(downloadFunc.lastArgs()[0], matrixSession.mxcUriToHttpAuthenticatedV1("mxc://someunencrypted"));
compare(downloadFunc.lastArgs()[1], "fileUrl");
compare(downloadFunc.lastArgs()[3], "");
compare(downloadFunc.lastArgs()[5], "");
diff --git a/src/tests/quick-tests/tst_JoinRoomPage.qml b/src/tests/quick-tests/tst_JoinRoomPage.qml
--- a/src/tests/quick-tests/tst_JoinRoomPage.qml
+++ b/src/tests/quick-tests/tst_JoinRoomPage.qml
@@ -43,13 +43,13 @@
verify(button.enabled);
mouseClick(button);
- tryVerify(() => item.matrixSdk.joinRoom.calledTimes() === 1, 1000);
- verify(JsHelpers.deepEqual(item.matrixSdk.joinRoom.lastArgs(), [
+ tryVerify(() => item.matrixSession.joinRoom.calledTimes() === 1, 1000);
+ verify(JsHelpers.deepEqual(item.matrixSession.joinRoom.lastArgs(), [
'#foo:example.com',
['example.com', 'example.org'],
]));
- item.matrixSdk.joinRoom.lastRetVal().resolve(true, {});
+ item.matrixSession.joinRoom.lastRetVal().resolve(true, {});
tryVerify(() => item.pageStack.removePage.calledTimes() === 1);
}
@@ -60,13 +60,13 @@
verify(button.enabled);
mouseClick(button);
- tryVerify(() => item.matrixSdk.joinRoom.calledTimes() === 1, 1000);
- verify(JsHelpers.deepEqual(item.matrixSdk.joinRoom.lastArgs(), [
+ tryVerify(() => item.matrixSession.joinRoom.calledTimes() === 1, 1000);
+ verify(JsHelpers.deepEqual(item.matrixSession.joinRoom.lastArgs(), [
'#foo:example.com',
[],
]));
- item.matrixSdk.joinRoom.lastRetVal().resolve(true, {});
+ item.matrixSession.joinRoom.lastRetVal().resolve(true, {});
tryVerify(() => item.pageStack.removePage.calledTimes() === 1);
}
@@ -77,9 +77,9 @@
verify(button.enabled);
mouseClick(button);
- tryVerify(() => item.matrixSdk.joinRoom.calledTimes() === 1, 1000);
+ tryVerify(() => item.matrixSession.joinRoom.calledTimes() === 1, 1000);
- item.matrixSdk.joinRoom.lastRetVal().resolve(false, {});
+ item.matrixSession.joinRoom.lastRetVal().resolve(false, {});
tryVerify(() => item.pageStack.removePage.calledTimes() === 0);
}
}
diff --git a/src/tests/quick-tests/tst_LoginPage.qml b/src/tests/quick-tests/tst_LoginPage.qml
--- a/src/tests/quick-tests/tst_LoginPage.qml
+++ b/src/tests/quick-tests/tst_LoginPage.qml
@@ -54,8 +54,8 @@
waitForRendering(loginFlows);
wait(500);
mouseClick(findChild(loginPage, 'userIdNextButton'));
- tryVerify(() => item.matrixSdk.discoverAndGetLoginFlows.calledTimes() === 1);
- compare(item.matrixSdk.discoverAndGetLoginFlows.lastArgs()[1], 'https://mxs.example.org');
+ tryVerify(() => item.matrixSession.discoverAndGetLoginFlows.calledTimes() === 1);
+ compare(item.matrixSession.discoverAndGetLoginFlows.lastArgs()[1], 'https://mxs.example.org');
}
function test_ssoLoginFlow() {
@@ -63,11 +63,11 @@
const loginFlows = findChild(loginPage, 'loginFlows');
findChild(loginPage, 'serverUrlField').text = '';
mouseClick(findChild(loginPage, 'userIdNextButton'));
- tryVerify(() => item.matrixSdk.discoverAndGetLoginFlows.calledTimes() === 1);
- compare(item.matrixSdk.discoverAndGetLoginFlows.lastArgs()[1], '');
- item.matrixSdk.discoverSuccessful('https://mxs.example.org');
+ tryVerify(() => item.matrixSession.discoverAndGetLoginFlows.calledTimes() === 1);
+ compare(item.matrixSession.discoverAndGetLoginFlows.lastArgs()[1], '');
+ item.matrixSession.discoverSuccessful('https://mxs.example.org');
tryVerify(() => loginFlows.discoveredServerUrl === 'https://mxs.example.org');
- item.matrixSdk.getLoginFlowsSuccessful(allFlows());
+ item.matrixSession.getLoginFlowsSuccessful(allFlows());
tryVerify(() => findChild(loginPage, 'passwordRadio').enabled);
tryVerify(() => findChild(loginPage, 'ssoRadio').enabled);
tryVerify(() => findChild(loginPage, 'ssoRadio').visible);
@@ -87,11 +87,11 @@
const loginFlows = findChild(loginPage, 'loginFlows');
findChild(loginPage, 'serverUrlField').text = '';
mouseClick(findChild(loginPage, 'userIdNextButton'));
- tryVerify(() => item.matrixSdk.discoverAndGetLoginFlows.calledTimes() === 1);
- compare(item.matrixSdk.discoverAndGetLoginFlows.lastArgs()[1], '');
- item.matrixSdk.discoverSuccessful('https://mxs.example.org');
+ tryVerify(() => item.matrixSession.discoverAndGetLoginFlows.calledTimes() === 1);
+ compare(item.matrixSession.discoverAndGetLoginFlows.lastArgs()[1], '');
+ item.matrixSession.discoverSuccessful('https://mxs.example.org');
tryVerify(() => loginFlows.discoveredServerUrl === 'https://mxs.example.org');
- item.matrixSdk.getLoginFlowsSuccessful(allFlows());
+ item.matrixSession.getLoginFlowsSuccessful(allFlows());
tryVerify(() => findChild(loginPage, 'passwordRadio').enabled);
tryVerify(() => findChild(loginPage, 'passwordRadio').visible);
waitForRendering(loginFlows);
@@ -103,7 +103,7 @@
waitForRendering(loginFlows);
wait(500);
mouseClick(findChild(loginPage, 'passwordLoginButton'));
- tryVerify(() => item.matrixSdk.login.calledTimes() === 1);
+ tryVerify(() => item.matrixSession.login.calledTimes() === 1);
}
function test_noFlowSupported() {
@@ -111,11 +111,11 @@
const loginFlows = findChild(loginPage, 'loginFlows');
findChild(loginPage, 'serverUrlField').text = '';
mouseClick(findChild(loginPage, 'userIdNextButton'));
- tryVerify(() => item.matrixSdk.discoverAndGetLoginFlows.calledTimes() === 1);
- compare(item.matrixSdk.discoverAndGetLoginFlows.lastArgs()[1], '');
- item.matrixSdk.discoverSuccessful('https://mxs.example.org');
+ tryVerify(() => item.matrixSession.discoverAndGetLoginFlows.calledTimes() === 1);
+ compare(item.matrixSession.discoverAndGetLoginFlows.lastArgs()[1], '');
+ item.matrixSession.discoverSuccessful('https://mxs.example.org');
tryVerify(() => loginFlows.discoveredServerUrl === 'https://mxs.example.org');
- item.matrixSdk.getLoginFlowsSuccessful([{ type: 'm.login.xxx' }]);
+ item.matrixSession.getLoginFlowsSuccessful([{ type: 'm.login.xxx' }]);
tryVerify(() => !findChild(loginPage, 'passwordRadio').enabled);
tryVerify(() => !findChild(loginPage, 'ssoRadio').enabled);
tryVerify(() => findChild(loginPage, 'noFlowIndicator').visible);
diff --git a/src/tests/quick-tests/tst_MatrixLink.qml b/src/tests/quick-tests/tst_MatrixLink.qml
--- a/src/tests/quick-tests/tst_MatrixLink.qml
+++ b/src/tests/quick-tests/tst_MatrixLink.qml
@@ -17,7 +17,6 @@
id: item
property var mentionUserRequested: mockHelper.noop()
- property var matrixSdk: QmlHelpers.MatrixSdkMock {}
property var switchToRoomRequested: mockHelper.noop()
property var pushCreateRoomPage: mockHelper.noop()
property var pageStack: ({
@@ -119,18 +118,18 @@
function test_matrixSchemeRoomAlias() {
textEvent.openLink("matrix:r/joinedroomalias:example.org");
- compare(matrixSdk.getRoomIdByAlias.calledTimes(), 1);
- compare(matrixSdk.getRoomIdByAlias.lastArgs()["roomAlias"], "#joinedroomalias:example.org")
- matrixSdk.getRoomIdByAlias.lastRetVal().resolve(true, { "roomId": "!joinedroomid:example.org" });
+ compare(matrixSession.getRoomIdByAlias.calledTimes(), 1);
+ compare(matrixSession.getRoomIdByAlias.lastArgs()["roomAlias"], "#joinedroomalias:example.org")
+ matrixSession.getRoomIdByAlias.lastRetVal().resolve(true, { "roomId": "!joinedroomid:example.org" });
compare(switchToRoomRequested.calledTimes(), 1);
compare(switchToRoomRequested.lastArgs()[0], "!joinedroomid:example.org");
}
function test_matrixToRoomAlias() {
textEvent.openLink("https://matrix.to/#/#joinedroomalias:example.org");
- compare(matrixSdk.getRoomIdByAlias.calledTimes(), 1);
- compare(matrixSdk.getRoomIdByAlias.lastArgs()["roomAlias"], "#joinedroomalias:example.org")
- matrixSdk.getRoomIdByAlias.lastRetVal().resolve(true, { "roomId": "!joinedroomid:example.org" });
+ compare(matrixSession.getRoomIdByAlias.calledTimes(), 1);
+ compare(matrixSession.getRoomIdByAlias.lastArgs()["roomAlias"], "#joinedroomalias:example.org")
+ matrixSession.getRoomIdByAlias.lastRetVal().resolve(true, { "roomId": "!joinedroomid:example.org" });
compare(switchToRoomRequested.calledTimes(), 1);
compare(switchToRoomRequested.lastArgs()[0], "!joinedroomid:example.org");
}
@@ -152,9 +151,9 @@
function test_matrixSchemeRoomAliasUnjoined() {
textEvent.openLink("matrix:r/unjoinedroomalias:example.org?action=join&via=server1.ca&via=server2.ca");
- compare(matrixSdk.getRoomIdByAlias.calledTimes(), 1);
- compare(matrixSdk.getRoomIdByAlias.lastArgs()["roomAlias"], "#unjoinedroomalias:example.org")
- matrixSdk.getRoomIdByAlias.lastRetVal().resolve(true, { "roomId": "!unjoinedroomid:example.org" });
+ compare(matrixSession.getRoomIdByAlias.calledTimes(), 1);
+ compare(matrixSession.getRoomIdByAlias.lastArgs()["roomAlias"], "#unjoinedroomalias:example.org")
+ matrixSession.getRoomIdByAlias.lastRetVal().resolve(true, { "roomId": "!unjoinedroomid:example.org" });
compare(pushJoinRoomPage.calledTimes(), 1);
compare(pageStack.currentItem.presetPage.calledTimes(), 1);
compare(pageStack.currentItem.presetPage.lastArgs()[0], "#unjoinedroomalias:example.org");
@@ -163,9 +162,9 @@
function test_matrixToRoomAliasUnjoined() {
textEvent.openLink("https://matrix.to/#/#unjoinedroomalias:example.org?action=join&via=server1.ca&via=server2.ca");
- compare(matrixSdk.getRoomIdByAlias.calledTimes(), 1);
- compare(matrixSdk.getRoomIdByAlias.lastArgs()["roomAlias"], "#unjoinedroomalias:example.org")
- matrixSdk.getRoomIdByAlias.lastRetVal().resolve(true, { "roomId": "!unjoinedroomid:example.org" });
+ compare(matrixSession.getRoomIdByAlias.calledTimes(), 1);
+ compare(matrixSession.getRoomIdByAlias.lastArgs()["roomAlias"], "#unjoinedroomalias:example.org")
+ matrixSession.getRoomIdByAlias.lastRetVal().resolve(true, { "roomId": "!unjoinedroomid:example.org" });
compare(pushJoinRoomPage.calledTimes(), 1);
compare(pageStack.currentItem.presetPage.calledTimes(), 1);
compare(pageStack.currentItem.presetPage.lastArgs()[0], "#unjoinedroomalias:example.org");
@@ -206,9 +205,9 @@
function test_matrixSchemeRoomAliasFailed() {
textEvent.openLink("matrix:r/room:example.org");
- compare(matrixSdk.getRoomIdByAlias.calledTimes(), 1);
- compare(matrixSdk.getRoomIdByAlias.lastArgs()["roomAlias"], "#room:example.org")
- matrixSdk.getRoomIdByAlias.lastRetVal().resolve(false, { errorCode: 'M_NOT_FOUND', error: 'Room alias #room:example.org not found.' });
+ compare(matrixSession.getRoomIdByAlias.calledTimes(), 1);
+ compare(matrixSession.getRoomIdByAlias.lastArgs()["roomAlias"], "#room:example.org")
+ matrixSession.getRoomIdByAlias.lastRetVal().resolve(false, { errorCode: 'M_NOT_FOUND', error: 'Room alias #room:example.org not found.' });
compare(switchToRoomRequested.calledTimes(), 0);
compare(showPassiveNotification.calledTimes(), 1);
compare(showPassiveNotification.lastArgs()[0], l10n.get('get-room-id-by-alias-failed-prompt',
diff --git a/src/tests/quick-tests/tst_RoomListViewItemDelegate.qml b/src/tests/quick-tests/tst_RoomListViewItemDelegate.qml
--- a/src/tests/quick-tests/tst_RoomListViewItemDelegate.qml
+++ b/src/tests/quick-tests/tst_RoomListViewItemDelegate.qml
@@ -221,7 +221,7 @@
when: windowShown
function initTestCase() {
- item.matrixSdk.userId = '@foo:example.org';
+ item.matrixSession.userId = '@foo:example.org';
item.sdkVars.userGivenNicknameMap.map = {
'@foo:example.com': 'something',
};
diff --git a/src/tests/quick-tests/tst_RoomPage.qml b/src/tests/quick-tests/tst_RoomPage.qml
--- a/src/tests/quick-tests/tst_RoomPage.qml
+++ b/src/tests/quick-tests/tst_RoomPage.qml
@@ -120,7 +120,7 @@
when: windowShown
function init() {
- matrixSdk.userId = '@foo:example.org';
+ matrixSession.userId = '@foo:example.org';
mockHelper.clearAll();
}
diff --git a/src/tests/quick-tests/tst_RoomSettingsPage.qml b/src/tests/quick-tests/tst_RoomSettingsPage.qml
--- a/src/tests/quick-tests/tst_RoomSettingsPage.qml
+++ b/src/tests/quick-tests/tst_RoomSettingsPage.qml
@@ -112,7 +112,7 @@
pageJoined.contentItem.clip = false;
pageWithTopic.contentItem.clip = false;
pageWithMembers.contentItem.clip = false;
- item.matrixSdk.userId = '@foo:example.org';
+ item.matrixSession.userId = '@foo:example.org';
}
function init() {
diff --git a/src/tests/quick-tests/tst_RoomStickerPackItemDelegate.qml b/src/tests/quick-tests/tst_RoomStickerPackItemDelegate.qml
--- a/src/tests/quick-tests/tst_RoomStickerPackItemDelegate.qml
+++ b/src/tests/quick-tests/tst_RoomStickerPackItemDelegate.qml
@@ -45,9 +45,9 @@
const usePackAction = findChild(packItem, 'usePackAction');
verify(!usePackAction.checked);
usePackAction.trigger();
- tryVerify(() => matrixSdk.sendAccountData.calledTimes() === 1);
+ tryVerify(() => matrixSession.sendAccountData.calledTimes() === 1);
verify(JsHelpers.deepEqual(
- matrixSdk.sendAccountData.lastArgs()[1],
+ matrixSession.sendAccountData.lastArgs()[1],
{
rooms: {
'!foo:example.com': {
@@ -72,9 +72,9 @@
const usePackAction = findChild(packItem, 'usePackAction');
verify(usePackAction.checked);
usePackAction.trigger();
- tryVerify(() => matrixSdk.sendAccountData.calledTimes() === 1);
+ tryVerify(() => matrixSession.sendAccountData.calledTimes() === 1);
verify(JsHelpers.deepEqual(
- matrixSdk.sendAccountData.lastArgs()[1],
+ matrixSession.sendAccountData.lastArgs()[1],
{
rooms: {
'!foo:example.com': {
diff --git a/src/tests/quick-tests/tst_SecuritySettings.qml b/src/tests/quick-tests/tst_SecuritySettings.qml
--- a/src/tests/quick-tests/tst_SecuritySettings.qml
+++ b/src/tests/quick-tests/tst_SecuritySettings.qml
@@ -41,9 +41,9 @@
input.text = 'test';
securitySettings.passwordInputOverlay.accepted();
securitySettings.passwordInputOverlay.close();
- compare(item.matrixSdk.importFromKeyBackupFile.calledTimes(), 1);
- compare(item.matrixSdk.importFromKeyBackupFile.lastArgs().fileUrl, 'file:///tmp/test');
- compare(item.matrixSdk.importFromKeyBackupFile.lastArgs().password, 'test');
+ compare(item.matrixSession.importFromKeyBackupFile.calledTimes(), 1);
+ compare(item.matrixSession.importFromKeyBackupFile.lastArgs().fileUrl, 'file:///tmp/test');
+ compare(item.matrixSession.importFromKeyBackupFile.lastArgs().password, 'test');
}
}
}
diff --git a/src/tests/quick-tests/tst_SendMessageBox.qml b/src/tests/quick-tests/tst_SendMessageBox.qml
--- a/src/tests/quick-tests/tst_SendMessageBox.qml
+++ b/src/tests/quick-tests/tst_SendMessageBox.qml
@@ -231,9 +231,9 @@
compare(kazvIOManager.startNewUploadJob.calledTimes(), 1);
verify(JsHelpers.deepEqual(kazvIOManager.startNewUploadJob.lastArgs(), {
- serverUrl: matrixSdk.serverUrl,
+ serverUrl: matrixSession.serverUrl,
fileUrl: Qt.url(''),
- token: matrixSdk.token,
+ token: matrixSession.token,
roomId: room.roomId,
roomList: sdkVars.roomList,
encrypted: room.encrypted,
diff --git a/src/tests/quick-tests/tst_UserPage.qml b/src/tests/quick-tests/tst_UserPage.qml
--- a/src/tests/quick-tests/tst_UserPage.qml
+++ b/src/tests/quick-tests/tst_UserPage.qml
@@ -63,7 +63,7 @@
when: windowShown
function init() {
- upper.matrixSdk.userId = '@foo:example.com';
+ upper.matrixSession.userId = '@foo:example.com';
gnMap.map = {};
mockHelper.clearAll();
room.membership = MK.MatrixRoom.Join;
diff --git a/src/tests/test-model.hpp b/src/tests/test-model.hpp
--- a/src/tests/test-model.hpp
+++ b/src/tests/test-model.hpp
@@ -6,13 +6,53 @@
#pragma once
#include <kazv-defs.hpp>
-
+#include <db-store.hpp>
+#include <matrix-session.hpp>
+#include <matrix-session-controller-p.hpp>
+#include <qt-rand-adapter.hpp>
+#include <qt-job-handler.hpp>
#include <sdk-model.hpp>
class MatrixSdk;
Kazv::SdkModel makeTestModel();
-MatrixSdk *makeTestSdk(Kazv::SdkModel model);
+struct SessionSetup
+{
+ RandomInterface randomGenerator;
+ QObject obj;
+ // QObject objSecondary;
+ QtJobHandler jobHandler;
+ LagerStoreEventEmitter ee;
+ MatrixSessionSdkT sdk;
+ lager::state<VerificationTrackerModel> verificationTrackerState;
+ // SecondaryRootT secondaryRoot;
+ DbStore dbStore;
+ MatrixSession session;
+
+ inline SessionSetup(SdkModel m)
+ : randomGenerator(QtRandAdapter{})
+ , obj()
+ // , objSecondary()
+ , jobHandler(&obj)
+ , ee{lager::with_qt_event_loop{obj}}
+ , sdk(makeSdk(
+ m,
+ jobHandler,
+ ee,
+ QtPromiseHandler(obj),
+ zug::identity,
+ withRandomGenerator(randomGenerator)
+ ))
+ // , secondaryRoot(sdk.createSecondaryRoot(QtEventLoop{this}, std::move(m)))
+ , session(
+ sdk.context(),
+ sdk.client(),
+ ee.watchable(),
+ verificationTrackerState,
+ [this]() -> DbStore & { return dbStore; }
+ )
+ {}
+};
Kazv::Event makeRoomMember(std::string userId, std::string displayName = "", std::string avatarUrl = "");
diff --git a/src/tests/test-model.cpp b/src/tests/test-model.cpp
--- a/src/tests/test-model.cpp
+++ b/src/tests/test-model.cpp
@@ -55,11 +55,6 @@
return model;
}
-MatrixSdk *makeTestSdk(SdkModel model)
-{
- return new MatrixSdk(model, /* testing = */ true);
-}
-
Event makeRoomMember(std::string userId, std::string displayName, std::string avatarUrl)
{
auto content = json::object({{"membership", "join"}});

File Metadata

Mime Type
text/plain
Expires
Fri, Jul 10, 4:00 PM (4 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1676342
Default Alt Text
D311.1783724445.diff (202 KB)

Event Timeline