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
; 
  38 @interface OctagonStateMachine 
: NSObject 
<OctagonStateFlagHandler
, OctagonStateOnqueuePendingFlagHandler
> 
  39 @
property (readonly
) OctagonState
* currentState
; 
  41 // The state machine transition function is the only location which should remove flags. 
  42 // Adding flags should use -handleFlag on the state machine 
  43 @
property (readonly
) id
<OctagonFlagContainer
> flags
; 
  45 @property NSMutableDictionary
<OctagonState
*, CKKSCondition
*>* stateConditions
; 
  47 @
property (readonly
) CKKSCondition
* paused
; 
  49 @
property (readonly
) NSSet
* allowableStates
; 
  50 @
property (nonatomic
) uint64_t timeout
; 
  52 @
property (nullable
) CKKSLockStateTracker
* lockStateTracker
; 
  54 // If you don't pass a lock state tracker, then you cannot reasonably use OctagonPendingConditionsDeviceUnlocked 
  56 - (instancetype
)initWithName
:(NSString
*)name
 
  57                       states
:(NSSet
<OctagonState
*>*)possibleStates
 
  58                        flags
:(NSSet
<OctagonFlag
*>*)possibleFlags
 
  59                 initialState
:(OctagonState
*)initialState
 
  60                        queue
:(dispatch_queue_t
)queue
 
  61                  stateEngine
:(id
<OctagonStateMachineEngine
>)stateEngine
 
  62             lockStateTracker
:(CKKSLockStateTracker
*)lockStateTracker
; 
  64 - (void)startOperation
; 
  65 - (void)haltOperation
; 
  67 // If the state machine is paused, this will kick it to start up again. Otherwise, it is a no-op. 
  68 - (void)pokeStateMachine
; 
  69 - (void)_onqueuePokeStateMachine
; 
  71 // This will set the given flag, and ensure that the state machine spins to handle it. 
  72 - (void)handleFlag
:(OctagonFlag
*)flag
; 
  74 // This will schedule the flag for future addition 
  75 - (void)handlePendingFlag
:(OctagonPendingFlag 
*)pendingFlag
; 
  77 - (NSDictionary
<NSString
*, NSString
*>*)dumpPendingFlags
; 
  79 - (NSArray
<OctagonFlag
*>*)possiblePendingFlags
; 
  80 - (void)disablePendingFlags
; 
  82 - (void)handleExternalRequest
:(OctagonStateTransitionRequest
<CKKSResultOperation
<OctagonStateTransitionOperationProtocol
>*>*)request
; 
  83 - (void)registerStateTransitionWatcher
:(OctagonStateTransitionWatcher
*)watcher
; 
  85 - (void)doSimpleStateMachineRPC
:(NSString
*)name
 
  86                              op
:(CKKSResultOperation
<OctagonStateTransitionOperationProtocol
>*)op
 
  87                    sourceStates
:(NSSet
<OctagonState
*>*)sourceStates
 
  88                           reply
:(nonnull 
void (^)(NSError 
* _Nullable
))reply
; 
  90 - (void)doWatchedStateMachineRPC
:(NSString
*)name
 
  91                     sourceStates
:(NSSet
<OctagonState
*>*)sourceStates
 
  92                             path
:(OctagonStateTransitionPath
*)path
 
  93                            reply
:(nonnull 
void (^)(NSError 
*error
))reply
; 
  94 - (void)setWatcherTimeout
:(uint64_t)timeout
; 
  97 // Wait the state `wantedState' for `timeout' ns, if we transition though that state 
  98 // return that state, otherwise return a snapshot. No garantee that you still are in that state, 
  99 // if you want that, you need to run an RPC. 
 100 - (OctagonState
* _Nonnull
)waitForState
:(OctagonState
* _Nonnull
)wantedState wait
:(uint64_t)timeout
; 
 104 NS_ASSUME_NONNULL_END