Source/TNLGlobalConfiguration.h (81 lines of code) (raw):
//
// TNLGlobalConfiguration.h
// TwitterNetworkLayer
//
// Created on 11/21/14.
// Copyright © 2020 Twitter. All rights reserved.
//
#import <TwitterNetworkLayer/TNLPriority.h>
NS_ASSUME_NONNULL_BEGIN
@protocol TNLAuthenticationChallengeHandler;
@protocol TNLHTTPHeaderProvider;
@protocol TNLHostSanitizer;
@protocol TNLLogger;
@protocol TNLNetworkObserver;
@protocol TNLBackoffBehaviorProvider;
@protocol TNLBackoffSignaler;
@class TNLRequestConfiguration;
@class TNLRequestOperation;
#if !TARGET_OS_WATCH
@class TNLCommunicationAgent;
#endif
///! The default duration for the request operation callback timeout
FOUNDATION_EXTERN const NSTimeInterval TNLGlobalConfigurationRequestOperationCallbackTimeoutDefault;
/**
The mode for how idle timeouts are used in *TNL*
*/
typedef NS_ENUM(NSInteger, TNLGlobalConfigurationIdleTimeoutMode)
{
/** Don't use the idle timeout for request operations */
TNLGlobalConfigurationIdleTimeoutModeDisabled = 0,
/** Do use the idle timeout, but only after we get our first callback from NSURL stack */
TNLGlobalConfigurationIdleTimeoutModeEnabledExcludingInitialConnection = 1,
/**
Do use the idle timeout, including while we wait for the first callback from NSURL stack
WARNING: imposing an idle timeout that affects connection time is often a bad idea and will yield more failures with devices that have difficulty connecting
*/
TNLGlobalConfigurationIdleTimeoutModeEnabledIncludingInitialConnection = 2,
/** Default idle timeout mode */
TNLGlobalConfigurationIdleTimeoutModeDefault = TNLGlobalConfigurationIdleTimeoutModeEnabledExcludingInitialConnection,
};
/**
`TNLGlobalConfigurationBackoffMode` enumerates the modes for how to handle
responses that signal for backoff with a backoff behavior.
The backoff behavior is defined by a `TNLBackoffBehavior` which is provided
per backoff signaling response via a `TNLBackoffBehaviorProvider` set on the
`TNLGlobalConfiguration.backoffBehaviorProvider`.
*/
typedef NS_ENUM(NSInteger, TNLGlobalConfigurationBackoffMode)
{
/**
Don't automatically back off when 503s are encountered
*/
TNLGlobalConfigurationBackoffModeDisabled = 0,
/**
Automatically back off requests when the `host` matches prior requests that saw a 503.
*/
TNLGlobalConfigurationBackoffModeKeyOffHost = 1,
/**
Automatically back off requests when the `host` and `path` match prior requests that saw a 503.
*/
TNLGlobalConfigurationBackoffModeKeyOffHostAndPath = 2,
};
/**
Options for when to prune inactive underlying `NSURLSession` (does not apply to background sessions).
Pruning involves iterating over all internal `NSURLSession` instances and if there are `0` active
`TNLRequestOperation` instances associated with a session AND the session has not been used recently
(see `[TNLGlobalConfiguration URLSessionInactivityThreshold]`), that session will be invalidated with
`finishTasksAndInvalidate` and removed from __TNL__. Future requests that would need the same session
will end up spinning up a new `NSURLSession`.
Pruning does not apply to background `NSURLSession` instances. Background sessions are kept
persistent in case a background request ends up completing that would need to communicate
completion to the background request.
See `[TNLGlobalConfiguration URLSessionInactivityThreshold]`: it defines the duration that must elapse
before an unused `NSURLSession` is considered _inactive_.
@note __TNL__ will only maintain a limited number non-background `NSURLSession` instances. If that
number is exceeded, the least recently used `NSURLSession` will be pruned with `finishTasksAndInvalidate` and will
require another request to spin it up again. This number is about a dozen, but subject to change.
*/
typedef NS_OPTIONS(NSUInteger, TNLGlobalConfigurationURLSessionPruneOptions)
{
/**
No options. Do not prune inactive `NSURLSession` instances.
*/
TNLGlobalConfigurationURLSessionPruneOptionsNone = 0,
/**
Prune inactive `NSURLSession` instances when the app enters the background.
Only applies to _iOS_ & _tvOS_ based apps. Noop on _macOS_ etc.
*/
TNLGlobalConfigurationURLSessionPruneOptionOnApplicationBackground = 1 << 0,
/**
Prune inactive `NSURLSession` instances when the app encounters a memory warning.
Only applies to _iOS_ & _tvOS_ based apps. Noop on _macOS_ etc.
*/
TNLGlobalConfigurationURLSessionPruneOptionOnMemoryWarning = 1 << 1,
/**
Prune inactive `NSURLSession` instances whenever an underlying `NSURLSessionTask` completes.
This is extremely aggressive, but will keep `NSURLSession` overhead to a minimum.
*/
TNLGlobalConfigurationURLSessionPruneOptionAfterEveryTask = 1 << 2,
/**
Special case options mask to immediately prune inactive `NSURLSession` instances.
Whent this mask is set on `[TNLGlobalConfiguration URLSessionPruneOptions]`, it will
kick off a pruning but leave the options in the configuration unchanged.
*/
TNLGlobalConfigurationURLSessionPruneOptionNow = NSUIntegerMax,
};
//! The default duration for an unused `NSURLSession` to become considered _inactive_
FOUNDATION_EXTERN NSTimeInterval const TNLGlobalConfigurationURLSessionInactivityThresholdDefault;
/**
`TNLGlobalConfiguration` is where the settings that affect all of TNL are maintained.
Configure `[TNLGlobalConfiguration sharedInstance]` early on during app startup before networking
starts.
*/
@interface TNLGlobalConfiguration : NSObject
/**
The version of the Twitter Network Layer library.
Only returns the major and minor version: e.g. `@"1.0"`
@return a string representing the TNL version.
*/
+ (NSString *)version;
/**
Singleton accessor
*/
+ (instancetype)sharedInstance;
/** init is unavailable */
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
#pragma mark Delegates
/**
The `TNLHostSanitizer` that is globally applied to all `TNLRequestOperation`s.
__See Also:__ `TNLHostSanitizer`
*/
@property (atomic, strong, nullable) id<TNLHostSanitizer> hostSanitizer;
/**
Add a `TNLNetworkObserver` for getting callbacks for all `TNLRequestOperationQueue` instances.
Redundantly adding an _observer_ that is already observing will be a no-op.
__See Also:__ `removeNetworkObserver:`, `TNLNetworkObserver` and `[TNLRequestOperationQueue networkObserver]`
*/
- (void)addNetworkObserver:(id<TNLNetworkObserver>)observer;
/**
Remove a `TNLNetworkObserver` that was getting callbacks for all `TNLRequestOperationQueue` instances.
Removing an _observing_ that is not observing will be a no-op.
__See Also:__ `addNetworkObserver:`, `TNLNetworkObserver` and `[TNLRequestOperationQueue networkObserver]`
*/
- (void)removeNetworkObserver:(id<TNLNetworkObserver>)observer;
/**
Return all the registered network observers
*/
- (NSArray<id<TNLNetworkObserver>> *)allNetworkObservers;
/**
Add a `TNLHTTPHeaderProvider` that is globally applied to all `TNLRequestOperation`s.
Last added provider will win in case of a conflict in header field.
__See Also:__ `TNLHTTPHeaderProvider`
*/
- (void)addHeaderProvider:(id<TNLHTTPHeaderProvider>)provider;
/**
Remove a `TNLHTTPHeaderProvider` that is globally applied to all `TNLRequestOperation`s.
__See Also:__ `TNLHTTPHeaderProvider`
*/
- (void)removeHeaderProvider:(id<TNLHTTPHeaderProvider>)provider;
/**
Return all the registered HTTP header providers
*/
- (NSArray<id<TNLHTTPHeaderProvider>> *)allHeaderProviders;
#if !TARGET_OS_WATCH
/**
The specified `TNLCommunicationAgent` will be used for all `TNLAttemptMetrics` to capture the best
guess network state at attempt completion.
Ideally, network state would be provided in task transaction metrics by Apple.
*/
@property (atomic, nullable) TNLCommunicationAgent *metricProvidingCommunicationAgent;
#endif
#pragma mark Settings
/**
The threshold where operations above the threshold will be considered "dependencies" for all
operations that enqueue below the threshold.
Default == `NSIntegerMax`, which disables the feature.
`TNLPriorityVeryHigh` is a good choice as it would require explicitely setting the operation to a
higher value (which is out of the enum range) to enable the automatic dependency
(such as `(NSInteger)(TNLPriorityVeryHigh + 1)`).
*/
@property (nonatomic) TNLPriority operationAutomaticDependencyPriorityThreshold;
/**
The backoff mode when a backoff signal is encountered.
Default == `TNLGlobalConfigurationBackoffModeDisabled`
*/
@property (atomic) TNLGlobalConfigurationBackoffMode backoffMode;
/**
The backoff behavior provider when a backoff signal is encountered and `backoffMode` is not `Disabled`.
Setting to `nil` will reset to an instance of `TNLSimpleBackoffBehaviorProvider`.
Default == an instance of `TNLSimpleBackoffBehaviorProvider`.
*/
@property (atomic, null_resettable) id<TNLBackoffBehaviorProvider> backoffBehaviorProvider;
/**
The backoff signaler for when an HTTP response should trigger a backoff signal.
Setting to `nil` will reset to an instance of `TNLSimpleBackoffSignaler`.
Default == an instance of `TNLSimpleBackoffSignaler`
*/
@property (atomic, null_resettable) id<TNLBackoffSignaler> backoffSignaler;
/**
Whether the backoff behavior should use the original request's host or the hydrated request's host.
Default == `NO` (don't use original request's host, use the hydrated request's host)
*/
@property (atomic) BOOL shouldBackoffUseOriginalRequestHost;
#pragma mark Pruning inactive NSURLSession instances
/**
The options for when to prune inactive `NSURLSession` instances in __TNL__.
Does not apply to background `NSURLSession` instances.
See `[TNLGlobalConfiguration URLSessionInactivityThreshold]`.
Default == `TNLGlobalConfigurationURLSessionPruneOptionsNone`
*/
@property (atomic) TNLGlobalConfigurationURLSessionPruneOptions URLSessionPruneOptions;
/**
The duration before an unused `NSURLSession` becomes inactive.
See `[TNLGlobalConfiguration URLSessionPruneOptions]`
Default == `TNLGlobalConfigurationURLSessionInactivityThresholdDefault`
*/
@property (atomic) NSTimeInterval URLSessionInactivityThreshold;
/**
Method to explicitely prune an `NSURLSession` if it has no active operations.
@param config The `TNLRequestConfiguration` to match with an underlying `NSURLSession`
@param operationQueueId the identifier for the related `TNLRequestOperationQueue` if the request configuration is for background execution mode.
*/
- (void)pruneURLSessionMatchingRequestConfiguration:(TNLRequestConfiguration *)config
operationQueueId:(nullable NSString *)operationQueueId;
#pragma mark Authentication Challenges
/**
Register a `TNLAuthenticationChallengerHandler`.
Callbacks to the _handler_ are made on the socket thread and will be thread safe.
Handlers are called in the order they were registered.
When a handler provides `NSURLSessionAuthChallengePerformDefaultHandling` as the _disposition_,
the next handler will be tried until all handlers are exhausted and then the default behavior will
take effect.
*/
- (void)addAuthenticationChallengeHandler:(id<TNLAuthenticationChallengeHandler>)handler;
/**
Unregister a `TNLAuthenticationChallengerHandler`
*/
- (void)removeAuthenticationChallengeHandler:(id<TNLAuthenticationChallengeHandler>)handler;
#pragma mark Clogged Callbacks
/**
The timeout for `TNLRequestOperation` callbacks to execute within
(includes all `TNLRequestDelegate` callbacks and `TNLRequestRetryPolicyProvider` callbacks)
Set to `0` or negative value to disable callback clog detection.
Default == 10 seconds
*/
@property (nonatomic, readwrite) NSTimeInterval requestOperationCallbackTimeout;
/**
For debugging purposes it can be useful to identify when a callback from TNL is taking too long
(clogging execution of a `TNLRequestOperation`).
"Clogged" callbacks will trigger an idle timeout and can be easily be missed as the actual network
causing the timeout.
Enable this setting to force a crash with some contextual information that indicates where the clog
happened.
Default == `NO`
*/
@property (atomic, readwrite) BOOL shouldForceCrashOnCloggedCallback;
#pragma mark Timeouts
/**
Configure the how idle timeouts behave within *TNL*.
Default == `TNLGlobalConfigurationIdleTimeoutModeDefault`
*/
@property (nonatomic, readwrite) TNLGlobalConfigurationIdleTimeoutMode idleTimeoutMode;
/**
Configure the how "data" timeouts behave within *TNL*. Zero or negative disables the timeout.
Default == `0.0`
TODO: have this be on the request configuration!
*/
@property (nonatomic, readwrite) NSTimeInterval timeoutIntervalBetweenDataTransfer;
#pragma mark Runtime Config
/**
Configure the delegate for log messages within the *TwitterNetworkLayer*
Default == `nil`
*/
@property (atomic, readwrite, nullable) id<TNLLogger> logger;
/**
Configure whether or not to execute asserts within the *TwitterNetworkLayer*
Default == `YES`
*/
@property (nonatomic, readwrite, getter=areAssertsEnabled) BOOL assertsEnabled;
@end
/**
Methods to help with debugging TNL
*/
@interface TNLGlobalConfiguration (Debugging)
/**
All enqueued and/or running `TNLRequestOperation` operations.
Very expensive, just use for debugging.
*/
- (NSArray<TNLRequestOperation *> *)allRequestOperations;
@end
NS_ASSUME_NONNULL_END