4 #import <Foundation/Foundation.h>
5 #import "keychain/ckks/CKKSResultOperation.h"
6 #import "keychain/ckks/CKKSCondition.h"
7 #import "keychain/ckks/CKKSLockStateTracker.h"
9 #import "keychain/ot/OctagonStateMachineHelpers.h"
10 #import "keychain/ot/OctagonStateMachineObservers.h"
11 #import "keychain/ot/OctagonFlags.h"
12 #import "keychain/ot/OctagonPendingFlag.h"
14 NS_ASSUME_NONNULL_BEGIN
16 @protocol OctagonStateOnqueuePendingFlagHandler
17 - (void)_onqueueHandlePendingFlag
:(OctagonPendingFlag
*)pendingFlag
;
20 // A State Machine Engine provides the actual implementation of a state machine.
21 // Its sole callback will be called on the queue passed into the OctagonStateMachine.
22 // Its inputs are the current state, and any interrupt flags that have been set on the state machine.
24 // The returned operation should not yet be started; the state machine will run it.
25 // Return nil if there's nothing to be done yet; the state machine will remain in the currentState until poked.
26 // The engine will be held weakly, so, ensure you keep it around.
27 @protocol OctagonStateMachineEngine
28 - (CKKSResultOperation
<OctagonStateTransitionOperationProtocol
>* _Nullable
)_onqueueNextStateMachineTransition
:(OctagonState
*)currentState
29 flags
:(OctagonFlags
*)flags
30 pendingFlags
:(id
<OctagonStateOnqueuePendingFlagHandler
>)pendingFlagHandler
;
33 @protocol OctagonStateFlagHandler
34 - (void)handleFlag
:(OctagonFlag
*)flag
;
35 - (void)handlePendingFlag
:(OctagonPendingFlag
*)pendingFlag
;
37 // If you've truly broken your queue ordering, then call this from whatever queue your flag handler is using.
38 - (void)_onqueueHandleFlag
:(OctagonFlag
*)flag
;
41 @interface OctagonStateMachine
: NSObject
<OctagonStateFlagHandler
, OctagonStateOnqueuePendingFlagHandler
>
42 @
property (readonly
) OctagonState
* currentState
;
44 // The state machine transition function is the only location which should remove flags.
45 // Adding flags should use -handleFlag on the state machine
46 @
property (readonly
) id
<OctagonFlagContainer
> flags
;
48 @property NSMutableDictionary
<OctagonState
*, CKKSCondition
*>* stateConditions
;
50 @
property (readonly
) CKKSCondition
* paused
;
52 @
property (readonly
) NSSet
* allowableStates
;
53 @
property (nonatomic
) uint64_t timeout
;
55 @
property (nullable
) CKKSLockStateTracker
* lockStateTracker
;
57 // If you don't pass a lock state tracker, then you cannot reasonably use OctagonPendingConditionsDeviceUnlocked
59 - (instancetype
)initWithName
:(NSString
*)name
60 states
:(NSSet
<OctagonState
*>*)possibleStates
61 flags
:(NSSet
<OctagonFlag
*>*)possibleFlags
62 initialState
:(OctagonState
*)initialState
63 queue
:(dispatch_queue_t
)queue
64 stateEngine
:(id
<OctagonStateMachineEngine
>)stateEngine
65 lockStateTracker
:(CKKSLockStateTracker
*)lockStateTracker
;
67 - (void)startOperation
;
68 - (void)haltOperation
;
70 // If the state machine is paused, this will kick it to start up again. Otherwise, it is a no-op.
71 - (void)pokeStateMachine
;
72 - (void)_onqueuePokeStateMachine
;
74 // This will set the given flag, and ensure that the state machine spins to handle it.
75 - (void)handleFlag
:(OctagonFlag
*)flag
;
76 - (void)_onqueueHandleFlag
:(OctagonFlag
*)flag
;
78 // This will schedule the flag for future addition
79 - (void)handlePendingFlag
:(OctagonPendingFlag
*)pendingFlag
;
81 - (NSDictionary
<NSString
*, NSString
*>*)dumpPendingFlags
;
83 - (NSArray
<OctagonFlag
*>*)possiblePendingFlags
;
84 - (void)disablePendingFlags
;
86 - (void)handleExternalRequest
:(OctagonStateTransitionRequest
<CKKSResultOperation
<OctagonStateTransitionOperationProtocol
>*>*)request
;
88 - (void)registerStateTransitionWatcher
:(OctagonStateTransitionWatcher
*)watcher
;
89 - (void)registerMultiStateArrivalWatcher
:(OctagonStateMultiStateArrivalWatcher
*)watcher
;
91 - (void)doSimpleStateMachineRPC
:(NSString
*)name
92 op
:(CKKSResultOperation
<OctagonStateTransitionOperationProtocol
>*)op
93 sourceStates
:(NSSet
<OctagonState
*>*)sourceStates
94 reply
:(nonnull
void (^)(NSError
* _Nullable
))reply
;
96 - (CKKSResultOperation
*)doWatchedStateMachineRPC
:(NSString
*)name
97 sourceStates
:(NSSet
<OctagonState
*>*)sourceStates
98 path
:(OctagonStateTransitionPath
*)path
99 reply
:(nonnull
void (^)(NSError
*error
))reply
;
100 - (void)setWatcherTimeout
:(uint64_t)timeout
;
103 // Wait the state `wantedState' for `timeout' ns, if we transition though that state
104 // return that state, otherwise return a snapshot. No garantee that you still are in that state,
105 // if you want that, you need to run an RPC.
106 - (OctagonState
* _Nonnull
)waitForState
:(OctagonState
* _Nonnull
)wantedState wait
:(uint64_t)timeout
;
110 NS_ASSUME_NONNULL_END