Page MenuHomePhorge

No OneTemporary

Size
31 KB
Referenced Files
None
Subscribers
None
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9f7595b..baede60 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,66 +1,68 @@
# This file is part of libkazv.
# SPDX-FileCopyrightText: 2022-2023 tusooa <tusooa@kazv.moe>
# SPDX-License-Identifier: AGPL-3.0-or-later
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
- if: $CI_COMMIT_BRANCH
stages:
- check-changelog
- lint
- build
'check-changelog':
stage: check-changelog
image: alpine
dependencies: []
script:
- sh ./tools/check-changelog
rules:
+ - if: $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^release\//
+ when: never
- if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "servant"
'lint:no-tabs':
stage: lint
script: |
echo 'Verify that no source file contains tabs'
! egrep -R --exclude-dir=transformed-libs --exclude-dir=Intl.js --exclude-dir=node_modules $'\t' src
rules: &build-rules
- changes: &src-chg
- Dockerfile.deps
- '**/*.cpp'
- '**/*.hpp'
- '**/CMakeLists.txt'
- '**/*.in'
- '**/*.qml'
- 'src/js/*.js'
- 'src/js/transformed-libs/*.js'
- 'packaging/**'
- 'icons/**'
'build:GNU/Linux-amd64-debug':
stage: build
image:
name: 'reg.lily.kazv.moe/kazv/libkazv/libkazv:servant-debug'
script: |
env JOBS=2 ./packaging/GNU-Linux/appimage/build.sh
artifacts:
paths:
- kazv-Debug.AppImage
expire_in: 1 week
rules: *build-rules
'build:GNU/Linux-amd64-prod':
stage: build
image:
name: 'reg.lily.kazv.moe/kazv/libkazv/libkazv:servant-prod'
script: |
env JOBS=2 ./packaging/GNU-Linux/appimage/build-prod.sh
artifacts:
paths:
- kazv-Release.AppImage
expire_in: 1 week
rules: *build-rules
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f4761e1..2728c97 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,32 +1,56 @@
# Change log
-## Unreleased
+## 0.1.0
+### Added
- Use fluent for translations. https://lily.kazv.moe/kazv/kazv/-/tree/tusooa/3-fluent
- Support read and save client state. https://lily.kazv.moe/kazv/kazv/-/merge_requests/2
- Support common event types. https://lily.kazv.moe/kazv/kazv/-/merge_requests/3
- Add send message shortcut. https://lily.kazv.moe/kazv/kazv/-/merge_requests/7
- Support auto-discovery and provide better login error messages. https://lily.kazv.moe/kazv/kazv/-/merge_requests/9
- Add translations for Hindi(hi) https://lily-is.land/kazv/kazv/-/merge_requests/11
- Use room heroes when there is no explicit room name. https://lily-is.land/kazv/kazv/-/merge_requests/15
- Add media file menu for download. https://lily-is.land/kazv/kazv/-/merge_requests/14
- Add a shortcut editor. https://lily-is.land/kazv/kazv/-/merge_requests/17
- Add UI for sending media files, controlling pause and cancel, and display the progress in real time. https://lily-is.land/kazv/kazv/-/merge_requests/18
- Use QtNetwork for job handling instead of libkazvjob. https://lily-is.land/kazv/kazv/-/merge_requests/21
- Implement creating and joining rooms. https://lily-is.land/kazv/kazv/-/merge_requests/19
- Add the ability to see users' devices and manage trust level. https://lily-is.land/kazv/kazv/-/merge_requests/23
-- Fix scroll-to-top when receiving new events. https://lily-is.land/kazv/kazv/-/merge_requests/26
- Support local echo. https://lily-is.land/kazv/kazv/-/merge_requests/25
- Support redaction. https://lily-is.land/kazv/kazv/-/merge_requests/28
- Implement profile settings. https://lily-is.land/kazv/kazv/-/merge_requests/30
- Support viewing event source. https://lily-is.land/kazv/kazv/-/merge_requests/32
-- Remove useless use of tabs on main page. https://lily-is.land/kazv/kazv/-/merge_requests/34
- Display hero avatar if it is a two-person room. https://lily-is.land/kazv/kazv/-/merge_requests/34
- Support typing status. https://lily-is.land/kazv/kazv/-/merge_requests/33
- Support room tagging. https://lily-is.land/kazv/kazv/-/merge_requests/35
-- Fix timeline efficiency. https://lily-is.land/kazv/kazv/-/merge_requests/37
- Allow paginate back in the timeline. https://lily-is.land/kazv/kazv/-/merge_requests/38
- Handle incoming invites. https://lily-is.land/kazv/kazv/-/merge_requests/39
- Support displaying notifications for incoming messages. https://lily-is.land/kazv/kazv/-/merge_requests/40
- Support leaving room. https://lily-is.land/kazv/kazv/-/merge_requests/41
+- Support sending and receiving encrypted media files. https://lily-is.land/kazv/kazv/-/merge_requests/20
+- Allow selecting message content. https://lily-is.land/kazv/kazv/-/merge_requests/44
+- Implement room member list view. https://lily-is.land/kazv/kazv/-/merge_requests/45
+- Handle message replies. https://lily-is.land/kazv/kazv/-/merge_requests/48
+- Implement reactions. https://lily-is.land/kazv/kazv/-/merge_requests/50
+- Use libkazv push rules to determine whether to notify for an event. https://lily-is.land/kazv/kazv/-/merge_requests/51
+- Implement displaying and changing users' power levels. https://lily-is.land/kazv/kazv/-/merge_requests/52
+- Add the ability to ban and unban user. https://lily-is.land/kazv/kazv/-/merge_requests/54
+- Sort rooms by descending order of latest event timestamp. https://lily-is.land/kazv/kazv/-/merge_requests/57
+- Implement kicking user. https://lily-is.land/kazv/kazv/-/merge_requests/58
+- Improve event view layout. https://lily-is.land/kazv/kazv/-/merge_requests/62
+- Install kazv logo to icon directory. https://lily-is.land/kazv/kazv/-/merge_requests/63
+- Implement inviting user. https://lily-is.land/kazv/kazv/-/merge_requests/65
+- Support inviting users when creating a room. https://lily-is.land/kazv/kazv/-/merge_requests/66
+
+### Fixed
+- Fix scroll-to-top when receiving new events. https://lily-is.land/kazv/kazv/-/merge_requests/26
+- Fix timeline efficiency. https://lily-is.land/kazv/kazv/-/merge_requests/37
+- Use proper style and l10n for event fallback. https://lily-is.land/kazv/kazv/-/merge_requests/55
+- Use debounce when setting local draft. https://lily-is.land/kazv/kazv/-/merge_requests/56
+- Fix AppImage build due to missing KNotification qml modules. https://lily-is.land/kazv/kazv/-/merge_requests/59
+- Put primary event loop back to separate thread. https://lily-is.land/kazv/kazv/-/merge_requests/60
+- Fix crash when timeline of a room is empty. https://lily-is.land/kazv/kazv/-/merge_requests/61
+
+### Removed
+- Remove useless use of tabs on main page. https://lily-is.land/kazv/kazv/-/merge_requests/34
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0dbe025..35fe1b9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,52 +1,52 @@
cmake_minimum_required(VERSION 3.13)
project(kazv)
include(FeatureSummary)
set(kazv_VERSION_MAJOR 0)
-set(kazv_VERSION_MINOR 0)
-set(kazv_VERSION_PATCH 1)
+set(kazv_VERSION_MINOR 1)
+set(kazv_VERSION_PATCH 0)
set(kazv_VERSION_STRING ${kazv_VERSION_MAJOR}.${kazv_VERSION_MINOR}.${kazv_VERSION_PATCH})
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
set(CMAKE_CXX_STANDARD 17)
set(QT5_MIN_VERSION 5.15)
set(KF5_MIN_VERSION 5.78)
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH})
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(ECMSetupVersion)
include(ECMGenerateHeaders)
include(ECMPoQmTools)
include(ECMAddTests)
include(ECMQtDeclareLoggingCategory)
find_package(Qt5 ${QT5_MIN_VERSION} REQUIRED COMPONENTS
Core Gui Qml QuickControls2 Svg Concurrent Widgets
Multimedia Test Network QuickTest
)
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Kirigami2 Config KIO Notifications)
find_package(Threads REQUIRED)
find_package(nlohmann_json REQUIRED)
find_package(libkazv REQUIRED)
kde_enable_exceptions()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -foperator-names -DQT_NO_EMIT")
add_subdirectory(src)
install(PROGRAMS moe.kazv.mxc.kazv.desktop DESTINATION ${KDE_INSTALL_APPDIR})
install(FILES moe.kazv.mxc.kazv.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
install(FILES kazv.notifyrc DESTINATION ${KDE_INSTALL_KNOTIFYRCDIR})
install(FILES icons/kazvlogo-256.png DESTINATION ${KDE_INSTALL_ICONDIR}/hicolor/256x256/apps)
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/changelogs/20.add b/changelogs/20.add
deleted file mode 100644
index 6b07ab9..0000000
--- a/changelogs/20.add
+++ /dev/null
@@ -1 +0,0 @@
-Support sending and receiving encrypted media files
diff --git a/changelogs/42.skip b/changelogs/42.skip
deleted file mode 100644
index e69de29..0000000
diff --git a/changelogs/44.add b/changelogs/44.add
deleted file mode 100644
index a730e22..0000000
--- a/changelogs/44.add
+++ /dev/null
@@ -1 +0,0 @@
-Allow selecting message content
diff --git a/changelogs/45.add b/changelogs/45.add
deleted file mode 100644
index fcc97b1..0000000
--- a/changelogs/45.add
+++ /dev/null
@@ -1 +0,0 @@
-Implement room member list view
diff --git a/changelogs/46.skip b/changelogs/46.skip
deleted file mode 100644
index e69de29..0000000
diff --git a/changelogs/47.skip b/changelogs/47.skip
deleted file mode 100644
index e69de29..0000000
diff --git a/changelogs/48.add b/changelogs/48.add
deleted file mode 100644
index 5539736..0000000
--- a/changelogs/48.add
+++ /dev/null
@@ -1 +0,0 @@
-Handle message replies
diff --git a/changelogs/50.add b/changelogs/50.add
deleted file mode 100644
index 14a190a..0000000
--- a/changelogs/50.add
+++ /dev/null
@@ -1 +0,0 @@
-Implement reactions
diff --git a/changelogs/51.add b/changelogs/51.add
deleted file mode 100644
index 576bda7..0000000
--- a/changelogs/51.add
+++ /dev/null
@@ -1 +0,0 @@
-Use libkazv push rules to determine whether to notify for an event
diff --git a/changelogs/52.add b/changelogs/52.add
deleted file mode 100644
index d00732d..0000000
--- a/changelogs/52.add
+++ /dev/null
@@ -1 +0,0 @@
-Implement displaying and changing users' power levels
diff --git a/changelogs/53.skip b/changelogs/53.skip
deleted file mode 100644
index e69de29..0000000
diff --git a/changelogs/54.add b/changelogs/54.add
deleted file mode 100644
index 37c1733..0000000
--- a/changelogs/54.add
+++ /dev/null
@@ -1 +0,0 @@
-Add the ability to ban and unban user.
diff --git a/changelogs/55.fix b/changelogs/55.fix
deleted file mode 100644
index ad04d28..0000000
--- a/changelogs/55.fix
+++ /dev/null
@@ -1 +0,0 @@
-Use proper style and l10n for event fallback
diff --git a/changelogs/56.fix b/changelogs/56.fix
deleted file mode 100644
index 80d417e..0000000
--- a/changelogs/56.fix
+++ /dev/null
@@ -1 +0,0 @@
-Use debounce when setting local draft
diff --git a/changelogs/57.add b/changelogs/57.add
deleted file mode 100644
index cedea31..0000000
--- a/changelogs/57.add
+++ /dev/null
@@ -1 +0,0 @@
-Sort rooms by descending order of latest event timestamp
diff --git a/changelogs/58.add b/changelogs/58.add
deleted file mode 100644
index ce390b0..0000000
--- a/changelogs/58.add
+++ /dev/null
@@ -1 +0,0 @@
-Implement kicking user
diff --git a/changelogs/59.fix b/changelogs/59.fix
deleted file mode 100644
index 8658b37..0000000
--- a/changelogs/59.fix
+++ /dev/null
@@ -1 +0,0 @@
-Fix AppImage build due to missing KNotification qml modules
diff --git a/changelogs/60.fix b/changelogs/60.fix
deleted file mode 100644
index fe51a95..0000000
--- a/changelogs/60.fix
+++ /dev/null
@@ -1 +0,0 @@
-Put primary event loop back to separate thread
diff --git a/changelogs/61.fix b/changelogs/61.fix
deleted file mode 100644
index 267afc9..0000000
--- a/changelogs/61.fix
+++ /dev/null
@@ -1 +0,0 @@
-Fix crash when timeline of a room is empty
diff --git a/changelogs/62.add b/changelogs/62.add
deleted file mode 100644
index fe8231e..0000000
--- a/changelogs/62.add
+++ /dev/null
@@ -1 +0,0 @@
-Improve event view layout
diff --git a/changelogs/63.add b/changelogs/63.add
deleted file mode 100644
index b4d1ef0..0000000
--- a/changelogs/63.add
+++ /dev/null
@@ -1 +0,0 @@
-Install kazv logo to icon directory
diff --git a/changelogs/64.skip b/changelogs/64.skip
deleted file mode 100644
index e69de29..0000000
diff --git a/changelogs/65.add b/changelogs/65.add
deleted file mode 100644
index 013bef6..0000000
--- a/changelogs/65.add
+++ /dev/null
@@ -1 +0,0 @@
-Implement inviting user
diff --git a/changelogs/66.add b/changelogs/66.add
deleted file mode 100644
index c529e13..0000000
--- a/changelogs/66.add
+++ /dev/null
@@ -1 +0,0 @@
-Support inviting users when creating a room
diff --git a/src/matrix-sdk.cpp b/src/matrix-sdk.cpp
index 5cbd742..7f4ad7d 100644
--- a/src/matrix-sdk.cpp
+++ b/src/matrix-sdk.cpp
@@ -1,594 +1,594 @@
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2020-2024 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <libkazv-config.hpp>
#include <immer/config.hpp> // https://github.com/arximboldi/immer/issues/168
#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 <eventemitter/lagerstoreeventemitter.hpp>
#include <client/sdk.hpp>
#include <client/notification-handler.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 "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"
using namespace 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>())));
static void serializeClientToFile(Client c);
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!"}; }
};
struct MatrixSdkPrivate
{
MatrixSdkPrivate(MatrixSdk *q, bool testing);
MatrixSdkPrivate(MatrixSdk *q, bool testing, SdkModel model);
bool testing;
RandomInterface randomGenerator;
QThread *thread;
QObject *obj;
QtJobHandler *jobHandler;
LagerStoreEventEmitter ee;
LagerStoreEventEmitter::Watchable watchable;
SdkT sdk;
QTimer saveTimer;
using SecondaryRootT = decltype(sdk.createSecondaryRoot(std::declval<lager::with_qt_event_loop>()));
SecondaryRootT secondaryRoot;
Client clientOnSecondaryRoot;
NotificationHandler notificationHandler;
void runIoContext() {
thread->start();
}
void maybeSerialize()
{
if (!testing) {
serializeClientToFile(clientOnSecondaryRoot);
}
}
};
// 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))
{
// After the thread's event loop is finished, we can delete the root object
connect(oldD->thread, &QThread::finished, oldD->obj, &QObject::deleteLater);
connect(oldD->obj, &QObject::destroyed, this, &QObject::deleteLater);
}
std::shared_ptr<MatrixSdkPrivate> oldD;
void cleanup()
{
qCInfo(kazvLog) << "start to clean up everything";
oldD->clientOnSecondaryRoot.stopSyncing()
.then([oldD=oldD](auto &&) {
qCDebug(kazvLog) << "stopped syncing";
QMetaObject::invokeMethod(oldD->obj, [thread=oldD->thread]() {
thread->quit();
});
});
oldD->thread->wait();
oldD->thread->deleteLater();
qCInfo(kazvLog) << "thread is done";
}
};
static void 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(kazvUserDataDir().toStdString());
auto sessionDir = userDataDir / "sessions"
/ userId / deviceId;
auto storeFile = sessionDir / "store";
auto metadataFile = sessionDir / "metadata";
qDebug() << "storeFile=" << QString::fromStdString(storeFile.native());
std::error_code err;
if ((! std::filesystem::create_directories(sessionDir, err))
&& err) {
qDebug() << "Unable to create sessionDir";
return;
}
{
auto storeStream = std::ofstream(storeFile);
if (! storeStream) {
qDebug() << "Unable to open storeFile";
return;
}
using OAr = boost::archive::text_oarchive;
auto archive = OAr{storeStream};
c.serializeTo(archive);
qDebug() << "Serialization done";
}
// store metadata
{
KConfig metadata(QString::fromStdString(metadataFile.native()));
KConfigGroup mdGroup(&metadata, "Metadata");
mdGroup.writeEntry("kazvVersion", QString::fromStdString(kazvVersionString()));
mdGroup.writeEntry("archiveFormat", "text");
}
}
MatrixSdkPrivate::MatrixSdkPrivate(MatrixSdk *q, bool testing)
: testing(testing)
, randomGenerator(QtRandAdapter{})
, 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())
{
obj->moveToThread(thread);
}
MatrixSdkPrivate::MatrixSdkPrivate(MatrixSdk *q, bool testing, SdkModel model)
: testing(testing)
, randomGenerator(QtRandAdapter{})
, 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())
{
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, [](KazvEvent e) {
qDebug() << "receiving trigger:";
if (std::holds_alternative<LoginSuccessful>(e)) {
qDebug() << "Login successful";
}
});
}
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());
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())
);
});
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), parent)
{
}
MatrixSdk::MatrixSdk(SdkModel model, bool testing, QObject *parent)
: MatrixSdk(std::make_unique<MatrixSdkPrivate>(this, testing, std::move(model)), 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()));
}
MatrixDeviceList *MatrixSdk::devicesOfUser(QString userId) const
{
return new MatrixDeviceList(m_d->clientOnSecondaryRoot.devicesOfUser(userId.toStdString()));
}
void MatrixSdk::login(const QString &userId, const QString &password)
{
m_d->clientOnSecondaryRoot
.autoDiscover(userId.toStdString())
.then([
this,
client=m_d->clientOnSecondaryRoot.toEventLoop(),
userId,
password
](auto res) {
if (!res.success()) {
// FIXME use real error codes and msgs when available in libkazv
Q_EMIT this->discoverFailed("", "");
return res;
}
auto serverUrl = res.dataStr("homeserverUrl");
client.passwordLogin(
serverUrl,
userId.toStdString(),
password.toStdString(),
- "kazv 0.0.0"
+ "kazv"
);
return res;
});
m_d->runIoContext();
}
MatrixRoomList *MatrixSdk::roomList() const
{
return new MatrixRoomList(m_d->clientOnSecondaryRoot);
}
void MatrixSdk::emplace(std::optional<SdkModel> model)
{
auto testing = m_d->testing;
if (m_d) {
cleanupDPointer(std::move(m_d));
}
m_d = (model.has_value()
? std::make_unique<MatrixSdkPrivate>(this, testing, std::move(model.value()))
: std::make_unique<MatrixSdkPrivate>(this, testing));
// Re-initialize lager-qt cursors and watchable connections
init();
m_d->runIoContext();
m_d->clientOnSecondaryRoot.startSyncing();
Q_EMIT sessionChanged();
}
QStringList MatrixSdk::allSessions() const
{
using StdPath = std::filesystem::path;
auto userDataDir = StdPath(kazvUserDataDir().toStdString());
auto allSessionsDir = userDataDir / "sessions";
QStringList sessionNames;
try {
for (const auto &p : std::filesystem::directory_iterator(allSessionsDir)) {
if (p.is_directory()) {
auto userId = p.path().filename().native();
for (const auto &q : std::filesystem::directory_iterator(p.path())) {
auto path = q.path();
auto deviceId = path.filename().native();
std::error_code err;
if (std::filesystem::exists(path / "store", err)) {
sessionNames.append(QString::fromStdString(userId + "/" + deviceId));
}
}
}
}
} catch (const std::filesystem::filesystem_error &) {
qDebug() << "sessionDir not available, ignoring";
}
return sessionNames;
}
void MatrixSdk::serializeToFile() const
{
m_d->maybeSerialize();
}
bool MatrixSdk::loadSession(QString sessionName)
{
qDebug() << "in loadSession(), sessionName=" << sessionName;
using StdPath = std::filesystem::path;
auto userDataDir = StdPath(kazvUserDataDir().toStdString());
auto sessionDir = userDataDir / "sessions" / sessionName.toStdString();
auto storeFile = sessionDir / "store";
auto metadataFile = sessionDir / "metadata";
if (! std::filesystem::exists(storeFile)) {
qDebug() << "storeFile does not exist, skip loading session " << sessionName;
return false;
}
if (std::filesystem::exists(metadataFile)) {
KConfig metadata(QString::fromStdString(metadataFile.native()));
KConfigGroup mdGroup(&metadata, "Metadata");
auto format = mdGroup.readEntry("archiveFormat");
if (format != QStringLiteral("text")) {
qDebug() << "Unknown archive format:" << format;
return false;
}
auto version = mdGroup.readEntry("kazvVersion");
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";
return false;
}
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";
return false;
}
using IAr = boost::archive::text_iarchive;
auto archive = IAr{storeStream};
archive >> model;
qDebug() << "Finished loading session";
} catch (const std::exception &e) {
qDebug() << "Error when loading session:" << QString::fromStdString(e.what());
return false;
}
emplace(std::move(model));
return true;
}
bool MatrixSdk::startNewSession()
{
emplace(std::nullopt);
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
)
{
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)
));
}
MatrixPromise *MatrixSdk::joinRoom(const QString &idOrAlias, const QStringList &servers)
{
return new MatrixPromise(m_d->clientOnSecondaryRoot.joinRoom(
idOrAlias.toStdString(),
qStringListToStdF(servers)
)
.then([this, idOrAlias, client=m_d->clientOnSecondaryRoot.toEventLoop()](auto stat) {
if (stat.success()) {
Q_EMIT joinRoomSuccessful(idOrAlias);
} else {
Q_EMIT joinRoomFailed(idOrAlias, "", "");
}
}));
}
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
{
return m_d->randomGenerator;
}
bool MatrixSdk::shouldNotify(MatrixEvent *event) const
{
// Do not notify own event
if (event->sender() == userId()) {
return false;
}
return m_d->notificationHandler.handleNotification(event->underlyingEvent()).shouldNotify;
}
#include "matrix-sdk.moc"
diff --git a/tools/collect-changelog b/tools/collect-changelog
new file mode 100755
index 0000000..a8e4a36
--- /dev/null
+++ b/tools/collect-changelog
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+url() {
+ local mrId="$1"
+ echo "https://lily-is.land/kazv/kazv/-/merge_requests/$mrId"
+}
+
+collectType() {
+ local suffix="$1"
+ local header="$2"
+ local printed=0
+ local mrId=
+ for file in changelogs/*."$suffix"; do
+ if [ '!' -f "$file" ]; then
+ continue
+ fi
+ if [ "$printed" = 0 ]; then
+ echo
+ echo "### $header"
+ printed=1
+ fi
+ # Normalize any trailing newlines/spaces, etc.
+ mrId="$(basename "$file" ".$suffix")"
+ echo "- $(cat "$file"). $(url "$mrId")"
+ done
+}
+
+collectType security Security
+collectType add Added
+collectType fix Fixed
+collectType remove Removed
+
+rm changelogs/*

File Metadata

Mime Type
text/x-diff
Expires
Sat, Sep 19, 12:45 PM (1 d, 21 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1769489
Default Alt Text
(31 KB)

Event Timeline