Make IDB settings work sync with JSPI
IndexedDB version of QSettings will now use solely the sync versions of data access functions. Those will suspend with JSPI. This makes IDB settings conform to the QSettings contract - and also allows us to enable tests in tst_qsettings for the IDB version of QSettings. Also, do not treat the IndexedDB format as one defining read/write functions in QSettings - those are the same as for ini format, as IndexedDB settings backend uses a backing ini file. Change-Id: Iee3471cc79c0cea87378923cf9baac58e56d1272 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
parent
c1b287c531
commit
a6d40467de
@ -878,7 +878,13 @@ QStringList QSettingsPrivate::splitArgs(const QString &s, qsizetype idx)
|
||||
|
||||
void QConfFileSettingsPrivate::initFormat()
|
||||
{
|
||||
#if defined(Q_OS_WASM)
|
||||
extension = (format == QSettings::NativeFormat || format == QSettings::WebIndexedDBFormat)
|
||||
? ".conf"_L1
|
||||
: ".ini"_L1;
|
||||
#else
|
||||
extension = (format == QSettings::NativeFormat) ? ".conf"_L1 : ".ini"_L1;
|
||||
#endif
|
||||
readFunc = nullptr;
|
||||
writeFunc = nullptr;
|
||||
#if defined(Q_OS_DARWIN)
|
||||
@ -887,7 +893,11 @@ void QConfFileSettingsPrivate::initFormat()
|
||||
caseSensitivity = IniCaseSensitivity;
|
||||
#endif
|
||||
|
||||
#if defined Q_OS_WASM
|
||||
if (format > QSettings::IniFormat && format != QSettings::WebIndexedDBFormat) {
|
||||
#else
|
||||
if (format > QSettings::IniFormat) {
|
||||
#endif
|
||||
const auto locker = qt_scoped_lock(settingsGlobalMutex);
|
||||
const CustomFormatVector *customFormatVector = customFormatVectorFunc();
|
||||
|
||||
@ -905,7 +915,11 @@ void QConfFileSettingsPrivate::initFormat()
|
||||
void QConfFileSettingsPrivate::initAccess()
|
||||
{
|
||||
if (!confFiles.isEmpty()) {
|
||||
#if defined Q_OS_WASM
|
||||
if (format > QSettings::IniFormat && format != QSettings::WebIndexedDBFormat) {
|
||||
#else
|
||||
if (format > QSettings::IniFormat) {
|
||||
#endif
|
||||
if (!readFunc)
|
||||
setStatus(QSettings::AccessError);
|
||||
}
|
||||
@ -1307,7 +1321,11 @@ QString QConfFileSettingsPrivate::fileName() const
|
||||
|
||||
bool QConfFileSettingsPrivate::isWritable() const
|
||||
{
|
||||
#if defined(Q_OS_WASM)
|
||||
if (format > QSettings::IniFormat && format != QSettings::WebIndexedDBFormat && !writeFunc)
|
||||
#else
|
||||
if (format > QSettings::IniFormat && !writeFunc)
|
||||
#endif
|
||||
return false;
|
||||
|
||||
if (confFiles.isEmpty())
|
||||
@ -1386,6 +1404,13 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
|
||||
*/
|
||||
if (file.isReadable() && file.size() != 0) {
|
||||
bool ok = false;
|
||||
|
||||
#ifdef Q_OS_WASM
|
||||
if (format == QSettings::WebIndexedDBFormat) {
|
||||
QByteArray data = file.readAll();
|
||||
ok = readIniFile(data, &confFile->unparsedIniSections);
|
||||
} else
|
||||
#endif
|
||||
#ifdef Q_OS_DARWIN
|
||||
if (format == QSettings::NativeFormat) {
|
||||
QByteArray data = file.readAll();
|
||||
@ -1442,6 +1467,11 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WASM
|
||||
if (format == QSettings::WebIndexedDBFormat) {
|
||||
ok = writeIniFile(sf, mergedKeys);
|
||||
} else
|
||||
#endif
|
||||
#ifdef Q_OS_DARWIN
|
||||
if (format == QSettings::NativeFormat) {
|
||||
ok = writePlistFile(sf, mergedKeys);
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <QFile>
|
||||
#endif // QT_NO_QOBJECT
|
||||
#include <QDebug>
|
||||
#include <QtCore/private/qstdweb_p.h>
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
@ -216,7 +217,6 @@ public:
|
||||
QWasmIDBSettingsPrivate(QSettings::Scope scope, const QString &organization,
|
||||
const QString &application);
|
||||
~QWasmIDBSettingsPrivate();
|
||||
static QWasmIDBSettingsPrivate *get(void *userData);
|
||||
|
||||
std::optional<QVariant> get(const QString &key) const override;
|
||||
QStringList children(const QString &prefix, ChildSpec spec) const override;
|
||||
@ -224,91 +224,59 @@ public:
|
||||
void sync() override;
|
||||
void flush() override;
|
||||
bool isWritable() const override;
|
||||
|
||||
void syncToLocal(const char *data, int size);
|
||||
void loadLocal(const QByteArray &filename);
|
||||
void setReady();
|
||||
void initAccess() override;
|
||||
|
||||
void loadLocal();
|
||||
void setReady();
|
||||
|
||||
private:
|
||||
bool writeSettingsToTemporaryFile(void *dataPtr, int size);
|
||||
|
||||
QString databaseName;
|
||||
QString id;
|
||||
static QList<QWasmIDBSettingsPrivate *> liveSettings;
|
||||
};
|
||||
|
||||
QList<QWasmIDBSettingsPrivate *> QWasmIDBSettingsPrivate::liveSettings;
|
||||
static bool isReadReady = false;
|
||||
|
||||
static void QWasmIDBSettingsPrivate_onLoad(void *userData, void *dataPtr, int size)
|
||||
{
|
||||
QWasmIDBSettingsPrivate *settings = QWasmIDBSettingsPrivate::get(userData);
|
||||
if (!settings)
|
||||
return;
|
||||
|
||||
QFile file(settings->fileName());
|
||||
QFileInfo fileInfo(settings->fileName());
|
||||
QDir dir(fileInfo.path());
|
||||
if (!dir.exists())
|
||||
dir.mkpath(fileInfo.path());
|
||||
|
||||
if (file.open(QFile::WriteOnly)) {
|
||||
file.write(reinterpret_cast<char *>(dataPtr), size);
|
||||
file.close();
|
||||
settings->setReady();
|
||||
}
|
||||
}
|
||||
|
||||
static void QWasmIDBSettingsPrivate_onError(void *userData)
|
||||
{
|
||||
if (QWasmIDBSettingsPrivate *settings = QWasmIDBSettingsPrivate::get(userData))
|
||||
settings->setStatus(QSettings::AccessError);
|
||||
}
|
||||
|
||||
static void QWasmIDBSettingsPrivate_onStore(void *userData)
|
||||
{
|
||||
if (QWasmIDBSettingsPrivate *settings = QWasmIDBSettingsPrivate::get(userData))
|
||||
settings->setStatus(QSettings::NoError);
|
||||
}
|
||||
|
||||
static void QWasmIDBSettingsPrivate_onCheck(void *userData, int exists)
|
||||
{
|
||||
if (QWasmIDBSettingsPrivate *settings = QWasmIDBSettingsPrivate::get(userData)) {
|
||||
if (exists)
|
||||
settings->loadLocal(settings->fileName().toLocal8Bit());
|
||||
else
|
||||
settings->setReady();
|
||||
}
|
||||
}
|
||||
constexpr char DbName[] = "/home/web_user";
|
||||
|
||||
QWasmIDBSettingsPrivate::QWasmIDBSettingsPrivate(QSettings::Scope scope,
|
||||
const QString &organization,
|
||||
const QString &application)
|
||||
: QConfFileSettingsPrivate(QSettings::NativeFormat, scope, organization, application)
|
||||
: QConfFileSettingsPrivate(QSettings::WebIndexedDBFormat, scope, organization, application)
|
||||
{
|
||||
liveSettings.push_back(this);
|
||||
Q_ASSERT_X(qstdweb::haveJspi(), Q_FUNC_INFO, "QWasmIDBSettingsPrivate needs JSPI to work");
|
||||
|
||||
if (organization.isEmpty()) {
|
||||
setStatus(QSettings::AccessError);
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus(QSettings::AccessError); // access error until sandbox gets loaded
|
||||
databaseName = organization;
|
||||
id = application;
|
||||
|
||||
emscripten_idb_async_exists("/home/web_user",
|
||||
fileName().toLocal8Bit(),
|
||||
reinterpret_cast<void*>(this),
|
||||
QWasmIDBSettingsPrivate_onCheck,
|
||||
QWasmIDBSettingsPrivate_onError);
|
||||
int exists = 0;
|
||||
int error = 0;
|
||||
emscripten_idb_exists(DbName, fileName().toLocal8Bit(), &exists, &error);
|
||||
if (error) {
|
||||
setStatus(QSettings::AccessError);
|
||||
return;
|
||||
}
|
||||
if (exists) {
|
||||
void *contents;
|
||||
int size;
|
||||
emscripten_idb_load(DbName, fileName().toLocal8Bit(), &contents, &size, &error);
|
||||
if (error || !writeSettingsToTemporaryFile(contents, size)) {
|
||||
setStatus(QSettings::AccessError);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setReady();
|
||||
}
|
||||
|
||||
QWasmIDBSettingsPrivate::~QWasmIDBSettingsPrivate()
|
||||
{
|
||||
liveSettings.removeAll(this);
|
||||
}
|
||||
|
||||
QWasmIDBSettingsPrivate *QWasmIDBSettingsPrivate::get(void *userData)
|
||||
{
|
||||
if (QWasmIDBSettingsPrivate::liveSettings.contains(userData))
|
||||
return reinterpret_cast<QWasmIDBSettingsPrivate *>(userData);
|
||||
return nullptr;
|
||||
}
|
||||
QWasmIDBSettingsPrivate::~QWasmIDBSettingsPrivate() = default;
|
||||
|
||||
void QWasmIDBSettingsPrivate::initAccess()
|
||||
{
|
||||
@ -324,6 +292,20 @@ std::optional<QVariant> QWasmIDBSettingsPrivate::get(const QString &key) const
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool QWasmIDBSettingsPrivate::writeSettingsToTemporaryFile(void *dataPtr, int size)
|
||||
{
|
||||
QFile file(fileName());
|
||||
QFileInfo fileInfo(fileName());
|
||||
QDir dir(fileInfo.path());
|
||||
if (!dir.exists())
|
||||
dir.mkpath(fileInfo.path());
|
||||
|
||||
if (!file.open(QFile::WriteOnly))
|
||||
return false;
|
||||
|
||||
return size == file.write(reinterpret_cast<char *>(dataPtr), size);
|
||||
}
|
||||
|
||||
QStringList QWasmIDBSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
|
||||
{
|
||||
return QConfFileSettingsPrivate::children(prefix, spec);
|
||||
@ -332,11 +314,10 @@ QStringList QWasmIDBSettingsPrivate::children(const QString &prefix, ChildSpec s
|
||||
void QWasmIDBSettingsPrivate::clear()
|
||||
{
|
||||
QConfFileSettingsPrivate::clear();
|
||||
emscripten_idb_async_delete("/home/web_user",
|
||||
fileName().toLocal8Bit(),
|
||||
reinterpret_cast<void*>(this),
|
||||
QWasmIDBSettingsPrivate_onStore,
|
||||
QWasmIDBSettingsPrivate_onError);
|
||||
|
||||
int error = 0;
|
||||
emscripten_idb_delete(DbName, fileName().toLocal8Bit(), &error);
|
||||
setStatus(!!error ? QSettings::AccessError : QSettings::NoError);
|
||||
}
|
||||
|
||||
void QWasmIDBSettingsPrivate::sync()
|
||||
@ -347,13 +328,11 @@ void QWasmIDBSettingsPrivate::sync()
|
||||
if (file.open(QFile::ReadOnly)) {
|
||||
QByteArray dataPointer = file.readAll();
|
||||
|
||||
emscripten_idb_async_store("/home/web_user",
|
||||
fileName().toLocal8Bit(),
|
||||
reinterpret_cast<void *>(dataPointer.data()),
|
||||
dataPointer.length(),
|
||||
reinterpret_cast<void*>(this),
|
||||
QWasmIDBSettingsPrivate_onStore,
|
||||
QWasmIDBSettingsPrivate_onError);
|
||||
int error = 0;
|
||||
emscripten_idb_store(DbName, fileName().toLocal8Bit(),
|
||||
reinterpret_cast<void *>(dataPointer.data()), dataPointer.length(),
|
||||
&error);
|
||||
setStatus(!!error ? QSettings::AccessError : QSettings::NoError);
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,34 +346,6 @@ bool QWasmIDBSettingsPrivate::isWritable() const
|
||||
return isReadReady && QConfFileSettingsPrivate::isWritable();
|
||||
}
|
||||
|
||||
void QWasmIDBSettingsPrivate::syncToLocal(const char *data, int size)
|
||||
{
|
||||
QFile file(fileName());
|
||||
|
||||
if (file.open(QFile::WriteOnly)) {
|
||||
file.write(data, size + 1);
|
||||
QByteArray data = file.readAll();
|
||||
|
||||
emscripten_idb_async_store("/home/web_user",
|
||||
fileName().toLocal8Bit(),
|
||||
reinterpret_cast<void *>(data.data()),
|
||||
data.length(),
|
||||
reinterpret_cast<void*>(this),
|
||||
QWasmIDBSettingsPrivate_onStore,
|
||||
QWasmIDBSettingsPrivate_onError);
|
||||
setReady();
|
||||
}
|
||||
}
|
||||
|
||||
void QWasmIDBSettingsPrivate::loadLocal(const QByteArray &filename)
|
||||
{
|
||||
emscripten_idb_async_load("/home/web_user",
|
||||
filename.data(),
|
||||
reinterpret_cast<void*>(this),
|
||||
QWasmIDBSettingsPrivate_onLoad,
|
||||
QWasmIDBSettingsPrivate_onError);
|
||||
}
|
||||
|
||||
void QWasmIDBSettingsPrivate::setReady()
|
||||
{
|
||||
isReadReady = true;
|
||||
@ -422,6 +373,11 @@ QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::
|
||||
format = QSettings::IniFormat;
|
||||
}
|
||||
}
|
||||
if (format == QSettings::WebIndexedDBFormat && !qstdweb::haveJspi()) {
|
||||
qWarning() << "QSettings::WebIndexedDBFormat requires JSPI, falling back to IniFormat with "
|
||||
"temporary file";
|
||||
format = QSettings::IniFormat;
|
||||
}
|
||||
|
||||
// Create settings backend according to selected format
|
||||
switch (format) {
|
||||
|
@ -42,9 +42,9 @@
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WASM)
|
||||
# include <QtCore/private/qstdweb_p.h>
|
||||
#include <QtCore/private/qstdweb_p.h>
|
||||
|
||||
# include "emscripten/val.h"
|
||||
#include "emscripten/val.h"
|
||||
#endif
|
||||
|
||||
Q_DECLARE_METATYPE(QSettings::Format)
|
||||
@ -89,6 +89,10 @@ static void populateWithFormats()
|
||||
QTest::addColumn<QSettings::Format>("format");
|
||||
|
||||
QTest::newRow("native") << QSettings::NativeFormat;
|
||||
#if defined(Q_OS_WASM)
|
||||
if (qstdweb::haveJspi())
|
||||
QTest::newRow("idb") << QSettings::WebIndexedDBFormat;
|
||||
#endif // defined(Q_OS_WASM)
|
||||
QTest::newRow("ini") << QSettings::IniFormat;
|
||||
QTest::newRow("custom1") << QSettings::CustomFormat1;
|
||||
QTest::newRow("custom2") << QSettings::CustomFormat2;
|
||||
|
Loading…
x
Reference in New Issue
Block a user