Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85568803
D311.1783724445.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
202 KB
Referenced Files
None
Subscribers
None
D311.1783724445.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D311: Split MatrixSdk
Attached
Detach File
Event Timeline
Log In to Comment