module LaunchDarkly.Server.Store.Internal
( isInitialized
, getAllFlags
, getFlag
, getSegment
, upsertFlag
, upsertSegment
, initialize
, StoreResult
, StoreResultM
, StoreInterface(..)
, RawFeature(..)
, StoreHandle(..)
, LaunchDarklyStoreRead(..)
, LaunchDarklyStoreWrite(..)
, Versioned(..)
, makeStoreIO
, insertFlag
, deleteFlag
, insertSegment
, deleteSegment
, initializeStore
, versionedToRaw
, FeatureKey
, FeatureNamespace
) where
import Control.Monad (void)
import Control.Lens (Lens', (%~), (^.))
import Data.Aeson (ToJSON, FromJSON, encode, decode)
import Data.IORef (IORef, readIORef, atomicModifyIORef', newIORef)
import Data.ByteString (ByteString)
import Data.ByteString.Lazy (toStrict, fromStrict)
import Data.Text (Text)
import Data.Function ((&))
import Data.Maybe (isJust)
import Data.Generics.Product (setField, getField, field)
import System.Clock (TimeSpec, Clock(Monotonic), getTime)
import GHC.Generics (Generic)
import GHC.Natural (Natural)
import LaunchDarkly.Server.Features (Segment, Flag)
import LaunchDarkly.AesonCompat (KeyMap, mapValues, emptyObject, insertKey, lookupKey, insertKey, deleteKey, mapMaybeValues)
type StoreResultM m a = m (Either Text a)
type StoreResult a = IO (Either Text a)
class LaunchDarklyStoreRead store m where
getFlagC :: store -> Text -> StoreResultM m (Maybe Flag)
getSegmentC :: store -> Text -> StoreResultM m (Maybe Segment)
getAllFlagsC :: store -> StoreResultM m (KeyMap Flag)
getInitializedC :: store -> StoreResultM m Bool
class LaunchDarklyStoreWrite store m where
storeInitializeC :: store -> KeyMap (Versioned Flag) -> KeyMap (Versioned Segment) -> StoreResultM m ()
upsertSegmentC :: store -> Text -> Versioned (Maybe Segment) -> StoreResultM m ()
upsertFlagC :: store -> Text -> Versioned (Maybe Flag) -> StoreResultM m ()
data StoreHandle m = StoreHandle
{ forall (m :: * -> *).
StoreHandle m -> Text -> StoreResultM m (Maybe Flag)
storeHandleGetFlag :: !(Text -> StoreResultM m (Maybe Flag))
, forall (m :: * -> *).
StoreHandle m -> Text -> StoreResultM m (Maybe Segment)
storeHandleGetSegment :: !(Text -> StoreResultM m (Maybe Segment))
, forall (m :: * -> *). StoreHandle m -> StoreResultM m (KeyMap Flag)
storeHandleAllFlags :: !(StoreResultM m (KeyMap Flag))
, forall (m :: * -> *). StoreHandle m -> StoreResultM m Bool
storeHandleInitialized :: !(StoreResultM m Bool)
, forall (m :: * -> *).
StoreHandle m
-> KeyMap (Versioned Flag)
-> KeyMap (Versioned Segment)
-> StoreResultM m ()
storeHandleInitialize :: !(KeyMap (Versioned Flag) -> KeyMap (Versioned Segment) -> StoreResultM m ())
, forall (m :: * -> *).
StoreHandle m
-> Text -> Versioned (Maybe Segment) -> StoreResultM m ()
storeHandleUpsertSegment :: !(Text -> Versioned (Maybe Segment) -> StoreResultM m ())
, forall (m :: * -> *).
StoreHandle m
-> Text -> Versioned (Maybe Flag) -> StoreResultM m ()
storeHandleUpsertFlag :: !(Text -> Versioned (Maybe Flag) -> StoreResultM m ())
, forall (m :: * -> *). StoreHandle m -> StoreResultM m ()
storeHandleExpireAll :: !(StoreResultM m ())
} deriving (forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (m :: * -> *) x. Rep (StoreHandle m) x -> StoreHandle m
forall (m :: * -> *) x. StoreHandle m -> Rep (StoreHandle m) x
$cto :: forall (m :: * -> *) x. Rep (StoreHandle m) x -> StoreHandle m
$cfrom :: forall (m :: * -> *) x. StoreHandle m -> Rep (StoreHandle m) x
Generic)
instance Monad m => LaunchDarklyStoreRead (StoreHandle m) m where
getFlagC :: StoreHandle m -> Text -> StoreResultM m (Maybe Flag)
getFlagC = forall (m :: * -> *).
StoreHandle m -> Text -> StoreResultM m (Maybe Flag)
storeHandleGetFlag
getSegmentC :: StoreHandle m -> Text -> StoreResultM m (Maybe Segment)
getSegmentC = forall (m :: * -> *).
StoreHandle m -> Text -> StoreResultM m (Maybe Segment)
storeHandleGetSegment
getAllFlagsC :: StoreHandle m -> StoreResultM m (KeyMap Flag)
getAllFlagsC = forall (m :: * -> *). StoreHandle m -> StoreResultM m (KeyMap Flag)
storeHandleAllFlags
getInitializedC :: StoreHandle m -> StoreResultM m Bool
getInitializedC = forall (m :: * -> *). StoreHandle m -> StoreResultM m Bool
storeHandleInitialized
instance Monad m => LaunchDarklyStoreWrite (StoreHandle m) m where
storeInitializeC :: StoreHandle m
-> KeyMap (Versioned Flag)
-> KeyMap (Versioned Segment)
-> StoreResultM m ()
storeInitializeC = forall (m :: * -> *).
StoreHandle m
-> KeyMap (Versioned Flag)
-> KeyMap (Versioned Segment)
-> StoreResultM m ()
storeHandleInitialize
upsertSegmentC :: StoreHandle m
-> Text -> Versioned (Maybe Segment) -> StoreResultM m ()
upsertSegmentC = forall (m :: * -> *).
StoreHandle m
-> Text -> Versioned (Maybe Segment) -> StoreResultM m ()
storeHandleUpsertSegment
upsertFlagC :: StoreHandle m
-> Text -> Versioned (Maybe Flag) -> StoreResultM m ()
upsertFlagC = forall (m :: * -> *).
StoreHandle m
-> Text -> Versioned (Maybe Flag) -> StoreResultM m ()
storeHandleUpsertFlag
initializeStore :: (LaunchDarklyStoreWrite store m, Monad m) => store
-> KeyMap Flag -> KeyMap Segment -> StoreResultM m ()
initializeStore :: forall store (m :: * -> *).
(LaunchDarklyStoreWrite store m, Monad m) =>
store -> KeyMap Flag -> KeyMap Segment -> StoreResultM m ()
initializeStore store
store KeyMap Flag
flags KeyMap Segment
segments = forall store (m :: * -> *).
LaunchDarklyStoreWrite store m =>
store
-> KeyMap (Versioned Flag)
-> KeyMap (Versioned Segment)
-> StoreResultM m ()
storeInitializeC store
store (forall {s}.
HasField' "version" s Natural =>
KeyMap s -> KeyMap (Versioned s)
makeVersioned KeyMap Flag
flags) (forall {s}.
HasField' "version" s Natural =>
KeyMap s -> KeyMap (Versioned s)
makeVersioned KeyMap Segment
segments)
where makeVersioned :: KeyMap s -> KeyMap (Versioned s)
makeVersioned = forall v1 v2. (v1 -> v2) -> KeyMap v1 -> KeyMap v2
mapValues (\s
f -> forall a. a -> Natural -> Versioned a
Versioned s
f (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"version" s
f))
insertFlag :: (LaunchDarklyStoreWrite store m, Monad m) => store -> Flag -> StoreResultM m ()
insertFlag :: forall store (m :: * -> *).
(LaunchDarklyStoreWrite store m, Monad m) =>
store -> Flag -> StoreResultM m ()
insertFlag store
store Flag
flag = forall store (m :: * -> *).
LaunchDarklyStoreWrite store m =>
store -> Text -> Versioned (Maybe Flag) -> StoreResultM m ()
upsertFlagC store
store (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"key" Flag
flag) forall a b. (a -> b) -> a -> b
$ forall a. a -> Natural -> Versioned a
Versioned (forall (f :: * -> *) a. Applicative f => a -> f a
pure Flag
flag) (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"version" Flag
flag)
deleteFlag :: (LaunchDarklyStoreWrite store m, Monad m) => store -> Text -> Natural -> StoreResultM m ()
deleteFlag :: forall store (m :: * -> *).
(LaunchDarklyStoreWrite store m, Monad m) =>
store -> Text -> Natural -> StoreResultM m ()
deleteFlag store
store Text
key Natural
version = forall store (m :: * -> *).
LaunchDarklyStoreWrite store m =>
store -> Text -> Versioned (Maybe Flag) -> StoreResultM m ()
upsertFlagC store
store Text
key forall a b. (a -> b) -> a -> b
$ forall a. a -> Natural -> Versioned a
Versioned forall a. Maybe a
Nothing Natural
version
insertSegment :: (LaunchDarklyStoreWrite store m, Monad m) => store -> Segment -> StoreResultM m ()
insertSegment :: forall store (m :: * -> *).
(LaunchDarklyStoreWrite store m, Monad m) =>
store -> Segment -> StoreResultM m ()
insertSegment store
store Segment
segment = forall store (m :: * -> *).
LaunchDarklyStoreWrite store m =>
store -> Text -> Versioned (Maybe Segment) -> StoreResultM m ()
upsertSegmentC store
store (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"key" Segment
segment) forall a b. (a -> b) -> a -> b
$ forall a. a -> Natural -> Versioned a
Versioned (forall (f :: * -> *) a. Applicative f => a -> f a
pure Segment
segment) (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"version" Segment
segment)
deleteSegment :: (LaunchDarklyStoreWrite store m, Monad m) => store -> Text -> Natural -> StoreResultM m ()
deleteSegment :: forall store (m :: * -> *).
(LaunchDarklyStoreWrite store m, Monad m) =>
store -> Text -> Natural -> StoreResultM m ()
deleteSegment store
store Text
key Natural
version = forall store (m :: * -> *).
LaunchDarklyStoreWrite store m =>
store -> Text -> Versioned (Maybe Segment) -> StoreResultM m ()
upsertSegmentC store
store Text
key forall a b. (a -> b) -> a -> b
$ forall a. a -> Natural -> Versioned a
Versioned forall a. Maybe a
Nothing Natural
version
makeStoreIO :: Maybe StoreInterface -> TimeSpec -> IO (StoreHandle IO)
makeStoreIO :: Maybe StoreInterface -> TimeSpec -> IO (StoreHandle IO)
makeStoreIO Maybe StoreInterface
backend TimeSpec
ttl = do
IORef State
state <- forall a. a -> IO (IORef a)
newIORef State
{ $sel:allFlags:State :: Expirable (KeyMap Flag)
allFlags = forall a. a -> Bool -> TimeSpec -> Expirable a
Expirable forall v. KeyMap v
emptyObject Bool
True TimeSpec
0
, $sel:flags:State :: KeyMap (Expirable (Versioned (Maybe Flag)))
flags = forall v. KeyMap v
emptyObject
, $sel:segments:State :: KeyMap (Expirable (Versioned (Maybe Segment)))
segments = forall v. KeyMap v
emptyObject
, $sel:initialized:State :: Expirable Bool
initialized = forall a. a -> Bool -> TimeSpec -> Expirable a
Expirable Bool
False Bool
True TimeSpec
0
}
let store :: Store
store = IORef State -> Maybe StoreInterface -> TimeSpec -> Store
Store IORef State
state Maybe StoreInterface
backend TimeSpec
ttl
forall (f :: * -> *) a. Applicative f => a -> f a
pure StoreHandle
{ $sel:storeHandleGetFlag:StoreHandle :: Text -> StoreResultM IO (Maybe Flag)
storeHandleGetFlag = Store -> Text -> StoreResultM IO (Maybe Flag)
getFlag Store
store
, $sel:storeHandleGetSegment:StoreHandle :: Text -> StoreResultM IO (Maybe Segment)
storeHandleGetSegment = Store -> Text -> StoreResultM IO (Maybe Segment)
getSegment Store
store
, $sel:storeHandleAllFlags:StoreHandle :: StoreResultM IO (KeyMap Flag)
storeHandleAllFlags = Store -> StoreResultM IO (KeyMap Flag)
getAllFlags Store
store
, $sel:storeHandleInitialized:StoreHandle :: StoreResultM IO Bool
storeHandleInitialized = Store -> StoreResultM IO Bool
isInitialized Store
store
, $sel:storeHandleInitialize:StoreHandle :: KeyMap (Versioned Flag)
-> KeyMap (Versioned Segment) -> StoreResultM IO ()
storeHandleInitialize = Store
-> KeyMap (Versioned Flag)
-> KeyMap (Versioned Segment)
-> StoreResultM IO ()
initialize Store
store
, $sel:storeHandleUpsertSegment:StoreHandle :: Text -> Versioned (Maybe Segment) -> StoreResultM IO ()
storeHandleUpsertSegment = Store -> Text -> Versioned (Maybe Segment) -> StoreResultM IO ()
upsertSegment Store
store
, $sel:storeHandleUpsertFlag:StoreHandle :: Text -> Versioned (Maybe Flag) -> StoreResultM IO ()
storeHandleUpsertFlag = Store -> Text -> Versioned (Maybe Flag) -> StoreResultM IO ()
upsertFlag Store
store
, $sel:storeHandleExpireAll:StoreHandle :: StoreResultM IO ()
storeHandleExpireAll = Store -> IO ()
expireAllItems Store
store forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right ())
}
data Expirable a = Expirable
{ forall a. Expirable a -> a
value :: !a
, forall a. Expirable a -> Bool
forceExpire :: !Bool
, forall a. Expirable a -> TimeSpec
updatedOn :: !TimeSpec
} deriving (forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (Expirable a) x -> Expirable a
forall a x. Expirable a -> Rep (Expirable a) x
$cto :: forall a x. Rep (Expirable a) x -> Expirable a
$cfrom :: forall a x. Expirable a -> Rep (Expirable a) x
Generic)
data Versioned a = Versioned
{ forall a. Versioned a -> a
value :: !a
, forall a. Versioned a -> Natural
version :: !Natural
} deriving (forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (Versioned a) x -> Versioned a
forall a x. Versioned a -> Rep (Versioned a) x
$cto :: forall a x. Rep (Versioned a) x -> Versioned a
$cfrom :: forall a x. Versioned a -> Rep (Versioned a) x
Generic)
data State = State
{ State -> Expirable (KeyMap Flag)
allFlags :: !(Expirable (KeyMap Flag))
, State -> KeyMap (Expirable (Versioned (Maybe Flag)))
flags :: !(KeyMap (Expirable (Versioned (Maybe Flag))))
, State -> KeyMap (Expirable (Versioned (Maybe Segment)))
segments :: !(KeyMap (Expirable (Versioned (Maybe Segment))))
, State -> Expirable Bool
initialized :: !(Expirable Bool)
} deriving (forall x. Rep State x -> State
forall x. State -> Rep State x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep State x -> State
$cfrom :: forall x. State -> Rep State x
Generic)
type FeatureKey = Text
type FeatureNamespace = Text
data StoreInterface = StoreInterface
{ StoreInterface -> Text -> StoreResult (KeyMap RawFeature)
storeInterfaceAllFeatures :: !(FeatureNamespace -> StoreResult (KeyMap RawFeature))
, StoreInterface -> Text -> Text -> StoreResult RawFeature
storeInterfaceGetFeature :: !(FeatureNamespace -> FeatureKey -> StoreResult RawFeature)
, StoreInterface
-> Text -> Text -> RawFeature -> StoreResultM IO Bool
storeInterfaceUpsertFeature :: !(FeatureNamespace -> FeatureKey -> RawFeature -> StoreResult Bool)
, StoreInterface -> StoreResultM IO Bool
storeInterfaceIsInitialized :: !(StoreResult Bool)
, StoreInterface -> KeyMap (KeyMap RawFeature) -> StoreResultM IO ()
storeInterfaceInitialize :: !(KeyMap (KeyMap RawFeature) -> StoreResult ())
}
data RawFeature = RawFeature
{ RawFeature -> Maybe ByteString
rawFeatureBuffer :: !(Maybe ByteString)
, RawFeature -> Natural
rawFeatureVersion :: !Natural
}
data Store = Store
{ Store -> IORef State
state :: !(IORef State)
, Store -> Maybe StoreInterface
backend :: !(Maybe StoreInterface)
, Store -> TimeSpec
timeToLive :: !TimeSpec
} deriving (forall x. Rep Store x -> Store
forall x. Store -> Rep Store x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Store x -> Store
$cfrom :: forall x. Store -> Rep Store x
Generic)
expireAllItems :: Store -> IO ()
expireAllItems :: Store -> IO ()
expireAllItems Store
store = forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"state" Store
store) forall a b. (a -> b) -> a -> b
$ \State
state -> (, ()) forall a b. (a -> b) -> a -> b
$ State
state
forall a b. a -> (a -> b) -> b
& forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"allFlags" forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ forall {s}. HasField' "forceExpire" s Bool => s -> s
expire
forall a b. a -> (a -> b) -> b
& forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"initialized" forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ forall {s}. HasField' "forceExpire" s Bool => s -> s
expire
forall a b. a -> (a -> b) -> b
& forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"flags" forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ forall v1 v2. (v1 -> v2) -> KeyMap v1 -> KeyMap v2
mapValues forall {s}. HasField' "forceExpire" s Bool => s -> s
expire
forall a b. a -> (a -> b) -> b
& forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"segments" forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ forall v1 v2. (v1 -> v2) -> KeyMap v1 -> KeyMap v2
mapValues forall {s}. HasField' "forceExpire" s Bool => s -> s
expire
where expire :: s -> s
expire = forall (f :: Symbol) s a. HasField' f s a => a -> s -> s
setField @"forceExpire" Bool
True
isExpired :: Store -> TimeSpec -> Expirable a -> Bool
isExpired :: forall a. Store -> TimeSpec -> Expirable a -> Bool
isExpired Store
store TimeSpec
now Expirable a
item = (forall a. Maybe a -> Bool
isJust forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"backend" Store
store) Bool -> Bool -> Bool
&& ((forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"forceExpire" Expirable a
item)
Bool -> Bool -> Bool
|| (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"timeToLive" Store
store) forall a. Num a => a -> a -> a
+ (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"updatedOn" Expirable a
item) forall a. Ord a => a -> a -> Bool
< TimeSpec
now)
getMonotonicTime :: IO TimeSpec
getMonotonicTime :: IO TimeSpec
getMonotonicTime = Clock -> IO TimeSpec
getTime Clock
Monotonic
initialize :: Store -> KeyMap (Versioned Flag) -> KeyMap (Versioned Segment) -> StoreResult ()
initialize :: Store
-> KeyMap (Versioned Flag)
-> KeyMap (Versioned Segment)
-> StoreResultM IO ()
initialize Store
store KeyMap (Versioned Flag)
flags KeyMap (Versioned Segment)
segments = case forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"backend" Store
store of
Maybe StoreInterface
Nothing -> do
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"state" Store
store) forall a b. (a -> b) -> a -> b
$ \State
state -> (, ()) forall a b. (a -> b) -> a -> b
$ State
state
forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) s a. HasField' f s a => a -> s -> s
setField @"flags" (forall v1 v2. (v1 -> v2) -> KeyMap v1 -> KeyMap v2
mapValues (\Versioned (Maybe Flag)
f -> forall a. a -> Bool -> TimeSpec -> Expirable a
Expirable Versioned (Maybe Flag)
f Bool
True TimeSpec
0) forall a b. (a -> b) -> a -> b
$ forall {a} {v2} {a}.
HasField "value" a v2 a (Maybe a) =>
KeyMap a -> KeyMap v2
c KeyMap (Versioned Flag)
flags)
forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) s a. HasField' f s a => a -> s -> s
setField @"segments" (forall v1 v2. (v1 -> v2) -> KeyMap v1 -> KeyMap v2
mapValues (\Versioned (Maybe Segment)
f -> forall a. a -> Bool -> TimeSpec -> Expirable a
Expirable Versioned (Maybe Segment)
f Bool
True TimeSpec
0) forall a b. (a -> b) -> a -> b
$ forall {a} {v2} {a}.
HasField "value" a v2 a (Maybe a) =>
KeyMap a -> KeyMap v2
c KeyMap (Versioned Segment)
segments)
forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) s a. HasField' f s a => a -> s -> s
setField @"allFlags" (forall a. a -> Bool -> TimeSpec -> Expirable a
Expirable (forall v1 v2. (v1 -> v2) -> KeyMap v1 -> KeyMap v2
mapValues (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"value") KeyMap (Versioned Flag)
flags) Bool
True TimeSpec
0)
forall a b. a -> (a -> b) -> b
& forall (f :: Symbol) s a. HasField' f s a => a -> s -> s
setField @"initialized" (forall a. a -> Bool -> TimeSpec -> Expirable a
Expirable Bool
True Bool
False TimeSpec
0)
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right ()
Just StoreInterface
backend -> (StoreInterface -> KeyMap (KeyMap RawFeature) -> StoreResultM IO ()
storeInterfaceInitialize StoreInterface
backend) KeyMap (KeyMap RawFeature)
raw forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Left Text
err -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left Text
err
Right () -> Store -> IO ()
expireAllItems Store
store forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall a b. b -> Either a b
Right ())
where
raw :: KeyMap (KeyMap RawFeature)
raw = forall v. KeyMap v
emptyObject
forall a b. a -> (a -> b) -> b
& forall v. Text -> v -> KeyMap v -> KeyMap v
insertKey Text
"flags" (forall v1 v2. (v1 -> v2) -> KeyMap v1 -> KeyMap v2
mapValues forall a. ToJSON a => Versioned (Maybe a) -> RawFeature
versionedToRaw forall a b. (a -> b) -> a -> b
$ forall {a} {v2} {a}.
HasField "value" a v2 a (Maybe a) =>
KeyMap a -> KeyMap v2
c KeyMap (Versioned Flag)
flags)
forall a b. a -> (a -> b) -> b
& forall v. Text -> v -> KeyMap v -> KeyMap v
insertKey Text
"segments" (forall v1 v2. (v1 -> v2) -> KeyMap v1 -> KeyMap v2
mapValues forall a. ToJSON a => Versioned (Maybe a) -> RawFeature
versionedToRaw forall a b. (a -> b) -> a -> b
$ forall {a} {v2} {a}.
HasField "value" a v2 a (Maybe a) =>
KeyMap a -> KeyMap v2
c KeyMap (Versioned Segment)
segments)
c :: KeyMap a -> KeyMap v2
c KeyMap a
x = forall v1 v2. (v1 -> v2) -> KeyMap v1 -> KeyMap v2
mapValues (\a
f -> a
f forall a b. a -> (a -> b) -> b
& forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"value" forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ forall a. a -> Maybe a
Just) KeyMap a
x
rawToVersioned :: (FromJSON a) => RawFeature -> Maybe (Versioned (Maybe a))
rawToVersioned :: forall a. FromJSON a => RawFeature -> Maybe (Versioned (Maybe a))
rawToVersioned RawFeature
raw = case RawFeature -> Maybe ByteString
rawFeatureBuffer RawFeature
raw of
Maybe ByteString
Nothing -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a. a -> Natural -> Versioned a
Versioned forall a. Maybe a
Nothing (RawFeature -> Natural
rawFeatureVersion RawFeature
raw)
Just ByteString
buffer -> case forall a. FromJSON a => ByteString -> Maybe a
decode forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
fromStrict ByteString
buffer of
Maybe (Maybe a)
Nothing -> forall a. Maybe a
Nothing
Just Maybe a
decoded -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a. a -> Natural -> Versioned a
Versioned Maybe a
decoded (RawFeature -> Natural
rawFeatureVersion RawFeature
raw)
versionedToRaw :: (ToJSON a) => Versioned (Maybe a) -> RawFeature
versionedToRaw :: forall a. ToJSON a => Versioned (Maybe a) -> RawFeature
versionedToRaw Versioned (Maybe a)
versioned = case forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"value" Versioned (Maybe a)
versioned of
Maybe a
Nothing -> Maybe ByteString -> Natural -> RawFeature
RawFeature forall a. Maybe a
Nothing forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"version" Versioned (Maybe a)
versioned
Just a
x -> Maybe ByteString -> Natural -> RawFeature
RawFeature (forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
toStrict forall a b. (a -> b) -> a -> b
$ forall a. ToJSON a => a -> ByteString
encode a
x) forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"version" Versioned (Maybe a)
versioned
tryGetBackend :: (FromJSON a) => StoreInterface -> Text -> Text -> StoreResult (Versioned (Maybe a))
tryGetBackend :: forall a.
FromJSON a =>
StoreInterface -> Text -> Text -> StoreResult (Versioned (Maybe a))
tryGetBackend StoreInterface
backend Text
namespace Text
key =
((StoreInterface -> Text -> Text -> StoreResult RawFeature
storeInterfaceGetFeature StoreInterface
backend) Text
namespace Text
key) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Left Text
err -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left Text
err
Right RawFeature
raw -> case forall a. FromJSON a => RawFeature -> Maybe (Versioned (Maybe a))
rawToVersioned RawFeature
raw of
Maybe (Versioned (Maybe a))
Nothing -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left Text
"failed to decode from external store"
Just Versioned (Maybe a)
versioned -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right Versioned (Maybe a)
versioned
getGeneric :: FromJSON a => Store -> Text -> Text
-> Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
-> StoreResult (Maybe a)
getGeneric :: forall a.
FromJSON a =>
Store
-> Text
-> Text
-> Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
-> StoreResult (Maybe a)
getGeneric Store
store Text
namespace Text
key Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
lens = do
State
state <- forall a. IORef a -> IO a
readIORef forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"state" Store
store
case forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"backend" Store
store of
Maybe StoreInterface
Nothing -> case forall v. Text -> KeyMap v -> Maybe v
lookupKey Text
key (State
state forall s a. s -> Getting a s a -> a
^. Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
lens) of
Maybe (Expirable (Versioned (Maybe a)))
Nothing -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right forall a. Maybe a
Nothing
Just Expirable (Versioned (Maybe a))
x -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"value" forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"value" Expirable (Versioned (Maybe a))
x
Just StoreInterface
backend -> do
TimeSpec
now <- IO TimeSpec
getMonotonicTime
case forall v. Text -> KeyMap v -> Maybe v
lookupKey Text
key (State
state forall s a. s -> Getting a s a -> a
^. Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
lens) of
Maybe (Expirable (Versioned (Maybe a)))
Nothing -> StoreInterface -> TimeSpec -> StoreResult (Maybe a)
updateFromBackend StoreInterface
backend TimeSpec
now
Just Expirable (Versioned (Maybe a))
x -> if forall a. Store -> TimeSpec -> Expirable a -> Bool
isExpired Store
store TimeSpec
now Expirable (Versioned (Maybe a))
x
then StoreInterface -> TimeSpec -> StoreResult (Maybe a)
updateFromBackend StoreInterface
backend TimeSpec
now
else forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"value" forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"value" Expirable (Versioned (Maybe a))
x
where
updateFromBackend :: StoreInterface -> TimeSpec -> StoreResult (Maybe a)
updateFromBackend StoreInterface
backend TimeSpec
now = forall a.
FromJSON a =>
StoreInterface -> Text -> Text -> StoreResult (Versioned (Maybe a))
tryGetBackend StoreInterface
backend Text
namespace Text
key forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Left Text
err -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left Text
err
Right Versioned (Maybe a)
v -> do
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"state" Store
store) forall a b. (a -> b) -> a -> b
$ \State
stateRef -> (, ()) forall a b. (a -> b) -> a -> b
$ State
stateRef forall a b. a -> (a -> b) -> b
& Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
lens forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~
(forall v. Text -> v -> KeyMap v -> KeyMap v
insertKey Text
key (forall a. a -> Bool -> TimeSpec -> Expirable a
Expirable Versioned (Maybe a)
v Bool
False TimeSpec
now))
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"value" Versioned (Maybe a)
v
getFlag :: Store -> Text -> StoreResult (Maybe Flag)
getFlag :: Store -> Text -> StoreResultM IO (Maybe Flag)
getFlag Store
store Text
key = forall a.
FromJSON a =>
Store
-> Text
-> Text
-> Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
-> StoreResult (Maybe a)
getGeneric Store
store Text
"flags" Text
key (forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"flags")
getSegment :: Store -> Text -> StoreResult (Maybe Segment)
getSegment :: Store -> Text -> StoreResultM IO (Maybe Segment)
getSegment Store
store Text
key = forall a.
FromJSON a =>
Store
-> Text
-> Text
-> Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
-> StoreResult (Maybe a)
getGeneric Store
store Text
"segments" Text
key (forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"segments")
upsertGeneric :: (ToJSON a) => Store -> Text -> Text -> Versioned (Maybe a)
-> Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
-> (Bool -> State -> State)
-> StoreResult ()
upsertGeneric :: forall a.
ToJSON a =>
Store
-> Text
-> Text
-> Versioned (Maybe a)
-> Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
-> (Bool -> State -> State)
-> StoreResultM IO ()
upsertGeneric Store
store Text
namespace Text
key Versioned (Maybe a)
versioned Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
lens Bool -> State -> State
action = do
case forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"backend" Store
store of
Maybe StoreInterface
Nothing -> do
forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"state" Store
store) forall a b. (a -> b) -> a -> b
$ \State
stateRef -> (, ()) forall a b. (a -> b) -> a -> b
$ State -> State
upsertMemory State
stateRef
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right ()
Just StoreInterface
backend -> do
Either Text Bool
result <- (StoreInterface
-> Text -> Text -> RawFeature -> StoreResultM IO Bool
storeInterfaceUpsertFeature StoreInterface
backend) Text
namespace Text
key (forall a. ToJSON a => Versioned (Maybe a) -> RawFeature
versionedToRaw Versioned (Maybe a)
versioned)
case Either Text Bool
result of
Left Text
err -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left Text
err
Right Bool
updated -> if Bool -> Bool
not Bool
updated then forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall a b. b -> Either a b
Right ()) else do
TimeSpec
now <- IO TimeSpec
getMonotonicTime
forall (f :: * -> *) a. Functor f => f a -> f ()
void forall a b. (a -> b) -> a -> b
$ forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"state" Store
store) forall a b. (a -> b) -> a -> b
$ \State
stateRef -> (, ()) forall a b. (a -> b) -> a -> b
$ State
stateRef
forall a b. a -> (a -> b) -> b
& Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
lens forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ (forall v. Text -> v -> KeyMap v -> KeyMap v
insertKey Text
key (forall a. a -> Bool -> TimeSpec -> Expirable a
Expirable Versioned (Maybe a)
versioned Bool
False TimeSpec
now))
forall a b. a -> (a -> b) -> b
& Bool -> State -> State
action Bool
True
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right ()
where
upsertMemory :: State -> State
upsertMemory State
state = case forall v. Text -> KeyMap v -> Maybe v
lookupKey Text
key (State
state forall s a. s -> Getting a s a -> a
^. Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
lens) of
Maybe (Expirable (Versioned (Maybe a)))
Nothing -> State -> State
updateMemory State
state
Just Expirable (Versioned (Maybe a))
existing -> if (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"version" forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"value" Expirable (Versioned (Maybe a))
existing) forall a. Ord a => a -> a -> Bool
< forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"version" Versioned (Maybe a)
versioned
then State -> State
updateMemory State
state else State
state
updateMemory :: State -> State
updateMemory State
state = State
state
forall a b. a -> (a -> b) -> b
& Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
lens forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ (forall v. Text -> v -> KeyMap v -> KeyMap v
insertKey Text
key (forall a. a -> Bool -> TimeSpec -> Expirable a
Expirable Versioned (Maybe a)
versioned Bool
False TimeSpec
0))
forall a b. a -> (a -> b) -> b
& Bool -> State -> State
action Bool
False
upsertFlag :: Store -> Text -> Versioned (Maybe Flag) -> StoreResult ()
upsertFlag :: Store -> Text -> Versioned (Maybe Flag) -> StoreResultM IO ()
upsertFlag Store
store Text
key Versioned (Maybe Flag)
versioned = forall a.
ToJSON a =>
Store
-> Text
-> Text
-> Versioned (Maybe a)
-> Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
-> (Bool -> State -> State)
-> StoreResultM IO ()
upsertGeneric Store
store Text
"flags" Text
key Versioned (Maybe Flag)
versioned (forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"flags") Bool -> State -> State
postAction where
postAction :: Bool -> State -> State
postAction Bool
external State
state = if Bool
external
then State
state forall a b. a -> (a -> b) -> b
& forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"allFlags" forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ (forall (f :: Symbol) s a. HasField' f s a => a -> s -> s
setField @"forceExpire" Bool
True)
else State
state forall a b. a -> (a -> b) -> b
& (forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"allFlags" forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"value") forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ KeyMap Flag -> KeyMap Flag
updateAllFlags
updateAllFlags :: KeyMap Flag -> KeyMap Flag
updateAllFlags KeyMap Flag
allFlags = case forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"value" Versioned (Maybe Flag)
versioned of
Maybe Flag
Nothing -> forall v. Text -> KeyMap v -> KeyMap v
deleteKey Text
key KeyMap Flag
allFlags
Just Flag
flag -> forall v. Text -> v -> KeyMap v -> KeyMap v
insertKey Text
key Flag
flag KeyMap Flag
allFlags
upsertSegment :: Store -> Text -> Versioned (Maybe Segment) -> StoreResult ()
upsertSegment :: Store -> Text -> Versioned (Maybe Segment) -> StoreResultM IO ()
upsertSegment Store
store Text
key Versioned (Maybe Segment)
versioned = forall a.
ToJSON a =>
Store
-> Text
-> Text
-> Versioned (Maybe a)
-> Lens' State (KeyMap (Expirable (Versioned (Maybe a))))
-> (Bool -> State -> State)
-> StoreResultM IO ()
upsertGeneric Store
store Text
"segments" Text
key Versioned (Maybe Segment)
versioned (forall (field :: Symbol) s t a b.
HasField field s t a b =>
Lens s t a b
field @"segments") forall {p} {p}. p -> p -> p
postAction where
postAction :: p -> p -> p
postAction p
_ p
state = p
state
filterAndCacheFlags :: Store -> TimeSpec -> KeyMap RawFeature -> IO (KeyMap Flag)
filterAndCacheFlags :: Store -> TimeSpec -> KeyMap RawFeature -> IO (KeyMap Flag)
filterAndCacheFlags Store
store TimeSpec
now KeyMap RawFeature
raw = do
let decoded :: KeyMap (Versioned (Maybe Flag))
decoded = forall v1 v2. (v1 -> Maybe v2) -> KeyMap v1 -> KeyMap v2
mapMaybeValues forall a. FromJSON a => RawFeature -> Maybe (Versioned (Maybe a))
rawToVersioned KeyMap RawFeature
raw
allFlags :: KeyMap Flag
allFlags = forall v1 v2. (v1 -> Maybe v2) -> KeyMap v1 -> KeyMap v2
mapMaybeValues (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"value") KeyMap (Versioned (Maybe Flag))
decoded
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"state" Store
store) forall a b. (a -> b) -> a -> b
$ \State
state -> (, ()) forall a b. (a -> b) -> a -> b
$
forall (f :: Symbol) s a. HasField' f s a => a -> s -> s
setField @"allFlags" (forall a. a -> Bool -> TimeSpec -> Expirable a
Expirable KeyMap Flag
allFlags Bool
False TimeSpec
now) forall a b. (a -> b) -> a -> b
$
forall (f :: Symbol) s a. HasField' f s a => a -> s -> s
setField @"flags" (forall v1 v2. (v1 -> v2) -> KeyMap v1 -> KeyMap v2
mapValues (\Versioned (Maybe Flag)
x -> forall a. a -> Bool -> TimeSpec -> Expirable a
Expirable Versioned (Maybe Flag)
x Bool
False TimeSpec
now) KeyMap (Versioned (Maybe Flag))
decoded) State
state
forall (f :: * -> *) a. Applicative f => a -> f a
pure KeyMap Flag
allFlags
getAllFlags :: Store -> StoreResult (KeyMap Flag)
getAllFlags :: Store -> StoreResultM IO (KeyMap Flag)
getAllFlags Store
store = do
State
state <- forall a. IORef a -> IO a
readIORef forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"state" Store
store
let memoryFlags :: StoreResultM IO (KeyMap Flag)
memoryFlags = forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"value" forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"allFlags" State
state
case forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"backend" Store
store of
Maybe StoreInterface
Nothing -> StoreResultM IO (KeyMap Flag)
memoryFlags
Just StoreInterface
backend -> do
TimeSpec
now <- IO TimeSpec
getMonotonicTime
if Bool -> Bool
not (forall a. Store -> TimeSpec -> Expirable a -> Bool
isExpired Store
store TimeSpec
now forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"allFlags" State
state)
then StoreResultM IO (KeyMap Flag)
memoryFlags
else do
Either Text (KeyMap RawFeature)
result <- (StoreInterface -> Text -> StoreResult (KeyMap RawFeature)
storeInterfaceAllFeatures StoreInterface
backend) Text
"flags"
case Either Text (KeyMap RawFeature)
result of
Left Text
err -> forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall a b. a -> Either a b
Left Text
err)
Right KeyMap RawFeature
raw -> do
KeyMap Flag
filtered <- Store -> TimeSpec -> KeyMap RawFeature -> IO (KeyMap Flag)
filterAndCacheFlags Store
store TimeSpec
now KeyMap RawFeature
raw
forall (f :: * -> *) a. Applicative f => a -> f a
pure (forall a b. b -> Either a b
Right KeyMap Flag
filtered)
isInitialized :: Store -> StoreResult Bool
isInitialized :: Store -> StoreResultM IO Bool
isInitialized Store
store = do
State
state <- forall a. IORef a -> IO a
readIORef forall a b. (a -> b) -> a -> b
$ forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"state" Store
store
let initialized :: Expirable Bool
initialized = forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"initialized" State
state
if forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"value" Expirable Bool
initialized
then forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right Bool
True
else case forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"backend" Store
store of
Maybe StoreInterface
Nothing -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right Bool
False
Just StoreInterface
backend -> do
TimeSpec
now <- IO TimeSpec
getMonotonicTime
if forall a. Store -> TimeSpec -> Expirable a -> Bool
isExpired Store
store TimeSpec
now Expirable Bool
initialized
then do
Either Text Bool
result <- StoreInterface -> StoreResultM IO Bool
storeInterfaceIsInitialized StoreInterface
backend
case Either Text Bool
result of
Left Text
err -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left Text
err
Right Bool
i -> do
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' (forall (f :: Symbol) a s. HasField' f s a => s -> a
getField @"state" Store
store) forall a b. (a -> b) -> a -> b
$ \State
stateRef -> (, ()) forall a b. (a -> b) -> a -> b
$
forall (f :: Symbol) s a. HasField' f s a => a -> s -> s
setField @"initialized" (forall a. a -> Bool -> TimeSpec -> Expirable a
Expirable Bool
i Bool
False TimeSpec
now) State
stateRef
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right Bool
i
else forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right Bool
False