Files
HellionChat/HellionChat/Privacy/StorageRule.cs
T
JonKazama-Hellion 1ab7ba8377 feat(privacy): reconnect the retroactive cleanup
The privacy filter only decides what gets written from now on. Whatever
was stored before the user narrowed their channels stays there until
something removes it, and that something has had no button since May.

Two rules shape the section, both because this deletes history and
cannot be undone:

- Without a preview the apply button does not exist. Not greyed out,
  absent. A disabled button is something a user waits for; a missing one
  is something they have to go and earn.
- A preview that no longer matches the settings counts as no preview.
  The old version only recoloured the number and left the button live,
  so a changed whitelist could be applied against counts computed for
  the previous one.

The mapping from the live rule to CleanupRetainOnly is the part worth
reading twice. CleanupRetainOnly takes one set and deletes everything
else, so it can only stand in for the live rule where that rule narrows
something: filter off means nothing is filtered, and an empty list means
a full wipe, which has its own button and its own confirmation. Both
cases now say so instead of offering a destructive action that does not
mean what it looks like.

Inside that, the allowlist is the whitelist itself plus any stored
channel this build does not recognise while the unknown-channel failsafe
is on. Deriving it from the counts instead would delete messages that
arrive on a whitelisted but currently empty channel between the preview
and the apply, and dropping the unrecognised ones would defeat the
failsafe, which exists to hold on to a new patch's channel until the
user has decided about it.

The preview runs on a worker over its own connection. It is a GROUP BY
across every stored row, the old version ran it inline on the draw
thread, and holding the read lock for it would stall UpsertMessage on
the framework thread for the length of the scan.

Cleanup_Help_SavedNote stays unused: it tells the reader to press Save
first, and the window it was written for had a Save button.
2026-08-18 21:38:34 +02:00

52 lines
2.4 KiB
C#

namespace HellionChat.Privacy;
// The rule that decides whether a message is written to disk, as plain logic.
//
// It lives apart from Configuration because Configuration implements a Dalamud
// interface, and the build suite cannot load Dalamud.dll -- the runtime resolves
// the declaring type before it ever reaches the method body, so even a static
// call on it fails. This is the single most consequential branch in the plugin,
// and it belongs where it can be pinned.
internal static class StorageRule
{
// v1.12.0 corrected the last term. A known channel the user had unticked
// used to fall through to the unknown-type failsafe, so the channel grid did
// nothing at all whenever that failsafe was on. It is on by default, so the
// filter stored everything while its own description promised "only messages
// from allowed channels are written to the database".
internal static bool Allows(bool listed, bool knownType, bool persistUnknownTypes) =>
listed || (!knownType && persistUnknownTypes);
// Carry-over for configs written before that correction. Where the failsafe
// made the list irrelevant and no channel was ever picked, the old rule
// stored everything; the corrected rule would store nothing. Switching the
// filter off keeps the behaviour and states it where the user can see it.
//
// A config that does have picks keeps them and starts honouring them, which
// is the point of the change.
internal static bool ShouldDisableFilterOnV24(
bool filterEnabled,
bool persistUnknownTypes,
int listedCount
) => filterEnabled && persistUnknownTypes && listedCount == 0;
// Why a retroactive cleanup cannot be offered, or that it can.
internal enum CleanupAvailability
{
Available,
// Nothing is filtered, so nothing in the database contradicts the rule.
FilterDisabled,
// The rule keeps no channel at all. CleanupRetainOnly refuses an empty
// allowlist on purpose -- that request is a full wipe, and a full wipe
// has its own button with its own confirmation.
NothingListed,
}
internal static CleanupAvailability CleanupState(bool filterEnabled, int listedCount) =>
!filterEnabled ? CleanupAvailability.FilterDisabled
: listedCount == 0 ? CleanupAvailability.NothingListed
: CleanupAvailability.Available;
}