RemoteKillSwitchController class

Emergency remote kill switch for a feature/event/shop/animation — built on top of RemoteConfigService (FEAT-39/ENH-58 already give it asset-fallback + partial-merge + last-known-good semantics at the config-value level; this controller adds the kill-switch-specific safety policy ON TOP: an invalid or missing remote value can never flip a feature from killed back to enabled — see KillSwitchSource for the exact resolution order).

Reactive: states is an RxMap, so any widget wrapped in Obx watching states[featureId] rebuilds the moment isKilled (or refreshAll) resolves a new decision for that feature — a screen already open when ops flips a switch remotely reacts without needing to be rebuilt/reopened, and without touching whatever it's currently doing (no crash, since it's just watching a value, not being torn down).

Inheritance
  • Object
  • GetLifeCycle
  • DisposableInterface
  • GetxService
  • RemoteKillSwitchController

Constructors

RemoteKillSwitchController({required RemoteConfigService remoteConfig, Map<String, bool> assetDefaults = const {}, String keyPrefix = 'kill_switch_', int nowMs()?})

Properties

assetDefaults → Map<String, bool>
Bundled fallback kill state per feature, used only when no valid remote value has EVER been seen for that feature (see KillSwitchSource.assetDefault) — a feature absent from this map defaults to false (not killed, normal operation).
final
auditLog → List<KillSwitchState>
Every decision ever made, oldest first, capped at _auditCapacity — "audit reason/version" over time, not just the current snapshot.
no setter
hashCode → int
The hash code for this object.
no setterinherited
initialized → bool
Checks whether the controller has already been initialized.
no setterinherited
isClosed → bool
Checks whether the controller has already been closed.
no setterinherited
keyPrefix → String
The remote config key for featureId is '$keyPrefix$featureId'.
final
onDelete → InternalFinalCallback<void>
Internal callback that starts the cycle of this controller.
finalinherited
onStart → InternalFinalCallback<void>
Called at the exact moment the widget is allocated in memory. It uses an internal "callable" type, to avoid any @overrides in subclases. This method should be internal and is required to define the lifetime cycle of the subclass.
finalinherited
remoteConfig → RemoteConfigService
final
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
states → RxMap<String, KillSwitchState>
Reactive last-resolved state per feature — read-through by isKilled/refreshAll, never written directly by a caller.
final

Methods

$configureLifeCycle() → void
inherited
clearLocalOverride(String featureId) → void
Removes a prior forceKillLocally override for featureId — the next isKilled/refreshAll call falls back through to the normal remote/cached/asset resolution order again.
forceKillLocally(String featureId, {required String reason}) → void
Force-kills featureId immediately, CLIENT-SIDE, without waiting for the next remoteConfig poll — see KillSwitchSource.localOverride. reason is required (unlike the remote/asset paths, where it's optional) since a local override always needs an audit trail explaining why THIS device decided to kill a feature on its own.
isKilled(String featureId) → bool
Resolves featureId's current kill state (updating states and auditLog as a side effect) and returns whether it's killed.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
onClose() → void
Called before onDelete method. onClose might be used to dispose resources used by the controller. Like closing events, or streams before the controller is destroyed. Or dispose objects that can potentially create some memory leaks, like TextEditingControllers, AnimationControllers. Might be useful as well to persist some data on disk.
inherited
onInit() → void
Called immediately after the widget is allocated in memory. You might use this to initialize something for the controller.
inherited
onReady() → void
Called 1 frame after onInit(). It is the perfect place to enter navigation events, like snackbar, dialogs, or a new route, or async request.
inherited
refreshAll(Iterable<String> featureIds) → void
Re-resolves every id in featureIds — for a periodic/lifecycle- resume hook that wants every tracked switch's states entry fresh even for features no widget has directly asked about yet.
runIfEnabled<T>(String featureId, T action()) → T?
Runs action and returns its result — but ONLY if featureId is not currently killed; returns null and never calls action otherwise. Makes "don't grant/execute a killed feature" the path of least resistance instead of relying on every call site remembering its own if (!isKilled(...)) guard.
toString() → String
A string representation of this object.
inherited

Operators

operator ==(Object other) → bool
The equality operator.
inherited

Static Properties

maybe → RemoteKillSwitchController?
no setter