Phosphor
Qt6 / Wayland library suite for window-management tools
 
Loading...
Searching...
No Matches
PhosphorConfig::JsonBackend Class Reference

Atomic-write JSON configuration backend. More...

#include <phosphor-config/include/PhosphorConfig/JsonBackend.h>

Inheritance diagram for PhosphorConfig::JsonBackend:
[legend]

Public Types

enum class  SyncPolicy { Synchronous , Deferred }
 Sync timing policy. See setSyncPolicy for the full contract. More...
 

Public Member Functions

 JsonBackend (QString filePath)
 Construct a backend backed by filePath.
 
 ~JsonBackend () override
 
std::unique_ptr< IGroupgroup (const QString &name) override
 Return a scoped view into the named group.
 
void reparseConfiguration () override
 Re-read configuration from disk, discarding any pending in-memory changes.
 
bool sync () override
 Flush pending writes to disk.
 
void deleteGroup (const QString &name) override
 Delete an entire group and everything inside it.
 
QString readRootString (const QString &key, const QString &defaultValue={}) const override
 Read/write ungrouped (root-level) keys.
 
void writeRootString (const QString &key, const QString &value) override
 
void removeRootKey (const QString &key) override
 
QStringList groupList () const override
 Enumerate every top-level group name.
 
void setPathResolver (std::shared_ptr< IGroupPathResolver > resolver) override
 Attach a custom path resolver.
 
std::shared_ptr< IGroupPathResolverpathResolver () const override
 Currently-installed resolver, or nullptr when none is set (also the default for backends that ignore setPathResolver).
 
void setRootGroupName (const QString &name)
 Change the JSON object that receives ungrouped writeRootString calls.
 
QString rootGroupName () const
 
void setVersionStamp (const QString &key, int version) override
 Stamp-on-sync: if non-empty, every sync() that writes the file will insert key = version when the key is absent from the root.
 
std::pair< QString, int > versionStamp () const override
 Currently-installed version stamp as {key, version}.
 
bool applyMigration (const Schema &schema) override
 Run schema's migration chain against the in-memory root, and if any step bumps the version stamp, atomically rewrite the backing file and refresh the in-memory state.
 
QJsonObject jsonRootSnapshot () const
 Read-only access to the in-memory document.
 
QString filePath () const
 Backing file path (useful for migration-chain callers that need to rewrite via writeJsonAtomically during schema upgrades).
 
void clearDirty ()
 Clear the dirty flag without writing.
 
void replaceRoot (QJsonObject root)
 Replace the in-memory document with root.
 
void setSyncPolicy (SyncPolicy policy, int debounceMs=500)
 Configure when sync() commits to disk.
 
SyncPolicy syncPolicy () const
 
bool flushPending ()
 Flush any pending deferred-sync write to disk now.
 
- Public Member Functions inherited from PhosphorConfig::IBackend
virtual ~IBackend ()=default
 
 IBackend (const IBackend &)=delete
 
IBackendoperator= (const IBackend &)=delete
 

Static Public Member Functions

static bool writeJsonAtomically (const QString &filePath, const QJsonObject &root)
 Atomically write root to filePath (temp file + rename via QSaveFile).
 

Additional Inherited Members

- Protected Member Functions inherited from PhosphorConfig::IBackend
 IBackend ()=default
 

Detailed Description

Atomic-write JSON configuration backend.

Reads and writes a single JSON document. Writes are deferred until sync() is called and then committed via QSaveFile (temp file + rename, safe against crashes and power loss).

Group resolution order:

  1. If an IGroupPathResolver is installed and returns a path, use it.
  2. If the group name contains a dot, treat as a dot-path hierarchy.
  3. Otherwise treat it as a flat top-level object name.

The "root group" (see rootGroupName) holds ungrouped keys written via writeRootString. Defaults to "General" for compatibility with QSettings INI behaviour.

Member Enumeration Documentation

◆ SyncPolicy

Sync timing policy. See setSyncPolicy for the full contract.

Enumerator
Synchronous 

sync() flushes the dirty root to disk synchronously and returns the commit result.

Default — matches the pre-policy behaviour so switching an existing consumer requires no change.

Deferred 

sync() restarts a single-shot debounce timer and returns true without touching disk.

The actual flush happens on the timer's timeout, on the same thread that owns the backend (i.e. whichever thread is pumping the event loop that owns the timer). Callers that need a guaranteed-committed state before proceeding (e.g. closing a save dialog, shutting down a daemon) call flushPending() to force an immediate flush. The backend's destructor also flushes pending writes.

Requires a running event loop to actually fire. Tests that exercise this path must call QTest::qWait() or QCoreApplication::processEvents() after sync() to let the timer elapse, or call flushPending() directly.

Constructor & Destructor Documentation

◆ JsonBackend()

PhosphorConfig::JsonBackend::JsonBackend ( QString  filePath)
explicit

Construct a backend backed by filePath.

The file is loaded immediately; missing or malformed files start with an empty root object (a warning is logged for malformed content).

◆ ~JsonBackend()

PhosphorConfig::JsonBackend::~JsonBackend ( )
override

Member Function Documentation

◆ applyMigration()

bool PhosphorConfig::JsonBackend::applyMigration ( const Schema schema)
overridevirtual

Run schema's migration chain against the in-memory root, and if any step bumps the version stamp, atomically rewrite the backing file and refresh the in-memory state.

Returns true unless the atomic disk rewrite fails — in which case the backend stays at the unmigrated state and the next successful sync() retries. Consumers that need the "did migrations actually apply" bit should check versionStamp() before and after, not this return value.

Reimplemented from PhosphorConfig::IBackend.

◆ clearDirty()

void PhosphorConfig::JsonBackend::clearDirty ( )

Clear the dirty flag without writing.

Used by tests + async I/O that commits snapshots off-thread.

◆ deleteGroup()

void PhosphorConfig::JsonBackend::deleteGroup ( const QString &  name)
overridevirtual

Delete an entire group and everything inside it.

Intermediate parents are pruned if they become empty (dot-path groups only).

Implements PhosphorConfig::IBackend.

◆ filePath()

QString PhosphorConfig::JsonBackend::filePath ( ) const

Backing file path (useful for migration-chain callers that need to rewrite via writeJsonAtomically during schema upgrades).

◆ flushPending()

bool PhosphorConfig::JsonBackend::flushPending ( )

Flush any pending deferred-sync write to disk now.

No-op when the policy is Synchronous or when the backend is not dirty. Returns the commit result (or true when there was nothing to flush). Safe to call from any context that would otherwise be able to call sync().

◆ group()

std::unique_ptr< IGroup > PhosphorConfig::JsonBackend::group ( const QString &  name)
overridevirtual

Return a scoped view into the named group.

Caller owns the pointer; destroy it before asking for another group on this backend.

Implements PhosphorConfig::IBackend.

◆ groupList()

QStringList PhosphorConfig::JsonBackend::groupList ( ) const
overridevirtual

Enumerate every top-level group name.

Dot-path groups are returned with their full path ("Snapping", "Snapping.Behavior", ...). Groups produced by a plugged-in IGroupPathResolver appear in the resolver's preferred external form.

Implements PhosphorConfig::IBackend.

◆ jsonRootSnapshot()

QJsonObject PhosphorConfig::JsonBackend::jsonRootSnapshot ( ) const

Read-only access to the in-memory document.

Implicitly shared (COW), so the copy is cheap and isolated from future mutations.

◆ pathResolver()

std::shared_ptr< IGroupPathResolver > PhosphorConfig::JsonBackend::pathResolver ( ) const
overridevirtual

Currently-installed resolver, or nullptr when none is set (also the default for backends that ignore setPathResolver).

Reimplemented from PhosphorConfig::IBackend.

◆ readRootString()

QString PhosphorConfig::JsonBackend::readRootString ( const QString &  key,
const QString &  defaultValue = {} 
) const
overridevirtual

Read/write ungrouped (root-level) keys.

Implements PhosphorConfig::IBackend.

◆ removeRootKey()

void PhosphorConfig::JsonBackend::removeRootKey ( const QString &  key)
overridevirtual

◆ reparseConfiguration()

void PhosphorConfig::JsonBackend::reparseConfiguration ( )
overridevirtual

Re-read configuration from disk, discarding any pending in-memory changes.

Must not be called while a group view is live.

Implements PhosphorConfig::IBackend.

◆ replaceRoot()

void PhosphorConfig::JsonBackend::replaceRoot ( QJsonObject  root)

Replace the in-memory document with root.

Marks the backend dirty — callers who paired this with a successful writeJsonAtomically may call clearDirty() immediately after to restore the "in-memory matches disk" invariant. Must not be called while any JsonGroup views are alive.

◆ rootGroupName()

QString PhosphorConfig::JsonBackend::rootGroupName ( ) const

◆ setPathResolver()

void PhosphorConfig::JsonBackend::setPathResolver ( std::shared_ptr< IGroupPathResolver resolver)
overridevirtual

Attach a custom path resolver.

Passing nullptr removes it. Safe to call at any time; the resolver is consulted on every group access, so it should be cheap.

Reimplemented from PhosphorConfig::IBackend.

◆ setRootGroupName()

void PhosphorConfig::JsonBackend::setRootGroupName ( const QString &  name)

Change the JSON object that receives ungrouped writeRootString calls.

Defaults to "General". Call before the first write.

◆ setSyncPolicy()

void PhosphorConfig::JsonBackend::setSyncPolicy ( SyncPolicy  policy,
int  debounceMs = 500 
)

Configure when sync() commits to disk.

debounceMs is only consulted for Deferred policy; it sets the coalescing window during which repeated sync() calls restart the same timer. Values <= 0 are clamped to 1 ms.

Safe to call at any time. Switching from Deferred back to Synchronous also flushes any pending deferred write so the in-memory and on-disk state agree on return.

◆ setVersionStamp()

void PhosphorConfig::JsonBackend::setVersionStamp ( const QString &  key,
int  version 
)
overridevirtual

Stamp-on-sync: if non-empty, every sync() that writes the file will insert key = version when the key is absent from the root.

Used by consumers who pair a JsonBackend with a Schema so fresh stores carry the current version from day one. Default disables the behaviour (empty key).

Reimplemented from PhosphorConfig::IBackend.

◆ sync()

bool PhosphorConfig::JsonBackend::sync ( )
overridevirtual

Flush pending writes to disk.

No-op when nothing is dirty. Returns true on success (or when there was nothing to flush), false on an I/O error — backends log the reason before returning.

Implements PhosphorConfig::IBackend.

◆ syncPolicy()

SyncPolicy PhosphorConfig::JsonBackend::syncPolicy ( ) const

◆ versionStamp()

std::pair< QString, int > PhosphorConfig::JsonBackend::versionStamp ( ) const
overridevirtual

Currently-installed version stamp as {key, version}.

Returns an empty key when no stamp is installed. Used by shared-backend safety checks (see Store::Store) to detect a clobber.

Reimplemented from PhosphorConfig::IBackend.

◆ writeJsonAtomically()

static bool PhosphorConfig::JsonBackend::writeJsonAtomically ( const QString &  filePath,
const QJsonObject &  root 
)
static

Atomically write root to filePath (temp file + rename via QSaveFile).

Exposed for use by MigrationRunner and other external callers that already have a QJsonObject in hand. Returns true on success.

◆ writeRootString()

void PhosphorConfig::JsonBackend::writeRootString ( const QString &  key,
const QString &  value 
)
overridevirtual

The documentation for this class was generated from the following file: