summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Kinney <michaelakinney@comcast.net>2021-01-21 19:24:03 -0500
committerMichael Kinney <michaelakinney@comcast.net>2021-01-21 19:24:03 -0500
commitd81a887102fa0b948e8b4c057ed1e442a72d1bf2 (patch)
treec266e7093fb2a9531fd0a34c9d634522b9271677
parent5f8fd6a2d67050f856369039d4cfe72265b9a803 (diff)
downloadsdl_ios-d81a887102fa0b948e8b4c057ed1e442a72d1bf2.tar.gz
refactor sdliapcontrolsession
-rw-r--r--SmartDeviceLink/private/SDLIAPControlSession.h27
-rw-r--r--SmartDeviceLink/private/SDLIAPControlSession.m209
-rw-r--r--SmartDeviceLink/private/SDLIAPControlSessionDelegate.h2
3 files changed, 72 insertions, 166 deletions
diff --git a/SmartDeviceLink/private/SDLIAPControlSession.h b/SmartDeviceLink/private/SDLIAPControlSession.h
index 03940ef98..5e65fbe25 100644
--- a/SmartDeviceLink/private/SDLIAPControlSession.h
+++ b/SmartDeviceLink/private/SDLIAPControlSession.h
@@ -7,7 +7,6 @@
//
#import <Foundation/Foundation.h>
-
#import "SDLIAPSession.h"
@class EAAccessory;
@@ -21,19 +20,39 @@ NS_ASSUME_NONNULL_BEGIN
*
* When the protocol string is received from Core, the control session is closed as a new session with Core must be established with the received protocol string. Core has ~10 seconds to send the protocol string, otherwise the control session is closed and new attempt is made to establish a control session with Core.
*/
-@interface SDLIAPControlSession : SDLIAPSession
+@interface SDLIAPControlSession: NSObject <SDLIAPSessionDelegate>
- (instancetype)init NS_UNAVAILABLE;
/**
* Creates a new control session.
*
- * @param accessory The accessory to connect to.
+ * @param accessory The accessory to connect to.
* @param delegate The control session delegate
* @return A SDLIAPControlSession object
*/
-- (instancetype)initWithAccessory:(nullable EAAccessory *)accessory delegate:(id<SDLIAPControlSessionDelegate>)delegate;
+- (instancetype)initWithAccessory:(nullable EAAccessory *)accessory delegate:(id<SDLIAPControlSessionDelegate>)delegate forProtocol:(NSString *)protocol;
+
+// document
+- (void) closeSession;
+
+/**
+ * Returns whether the session has open I/O streams.
+ */
+@property (assign, nonatomic, readonly, getter=isSessionInProgress) BOOL sessionInProgress;
+
+/**
+ * The accessory with which to open a session.
+ */
+@property (nullable, strong, nonatomic, readonly) EAAccessory *accessory;
+
+/**
+ * The unique ID assigned to the session between the app and accessory. If no session exists the value will be 0.
+ */
+@property (assign, nonatomic, readonly) NSUInteger connectionID;
@end
NS_ASSUME_NONNULL_END
+
+
diff --git a/SmartDeviceLink/private/SDLIAPControlSession.m b/SmartDeviceLink/private/SDLIAPControlSession.m
index 50d7a98e4..c89cc2fb5 100644
--- a/SmartDeviceLink/private/SDLIAPControlSession.m
+++ b/SmartDeviceLink/private/SDLIAPControlSession.m
@@ -22,206 +22,94 @@ NS_ASSUME_NONNULL_BEGIN
int const ProtocolIndexTimeoutSeconds = 10;
@interface SDLIAPControlSession ()
-
@property (nullable, strong, nonatomic) SDLTimer *protocolIndexTimer;
@property (weak, nonatomic) id<SDLIAPControlSessionDelegate> delegate;
-
+@property (nullable, nonatomic, strong) SDLIAPSession *iapSession;
@end
@implementation SDLIAPControlSession
#pragma mark - Session lifecycle
-- (instancetype)initWithAccessory:(nullable EAAccessory *)accessory delegate:(id<SDLIAPControlSessionDelegate>)delegate {
- SDLLogV(@"SDLIAPControlSession init");
-
- self = [super initWithAccessory:accessory forProtocol:ControlProtocolString];
- if (!self) { return nil; }
-
+- (instancetype)initWithAccessory:(nullable EAAccessory *)accessory delegate:(id<SDLIAPControlSessionDelegate>)delegate forProtocol:(NSString *)protocol {
+ SDLLogD(@"SDLIAPControlSession init with protocol %@ and accessory %@", protocol, accessory);
+ self = [super init];
+ _iapSession = [[SDLIAPSession alloc] initWithAccessory:accessory forProtocol:protocol iAPSessionDelegate:self];
_protocolIndexTimer = nil;
_delegate = delegate;
+ SDLLogD(@"SDLIAPControlSession Wait for the protocol string from Core, setting timeout timer for %d seconds", ProtocolIndexTimeoutSeconds);
+ self.protocolIndexTimer = [self sdl_createControlSessionProtocolIndexStringDataTimeoutTimer];
return self;
}
-#pragma mark Start
-
-- (void)startSession {
- if (self.accessory == nil) {
- SDLLogW(@"There is no control session in progress, attempting to create a new control session.");
- [self.delegate controlSessionShouldRetry];
- } else {
- SDLLogD(@"Starting a control session with accessory (%@)", self.accessory.name);
- __weak typeof(self) weakSelf = self;
- [self sdl_startStreamsWithCompletionHandler:^(BOOL success) {
- __strong typeof(weakSelf) strongSelf = weakSelf;
- if (!success) {
- SDLLogW(@"Control session failed to setup with accessory: %@. Attempting to create a new control session", strongSelf.accessory);
- [strongSelf destroySessionWithCompletionHandler:^{
- __strong typeof(weakSelf) strongSelf = weakSelf;
- [strongSelf.delegate controlSessionShouldRetry];
- }];
- } else {
- SDLLogD(@"Waiting for the protocol string from Core, setting timeout timer for %d seconds", ProtocolIndexTimeoutSeconds);
- strongSelf.protocolIndexTimer = [strongSelf sdl_createControlSessionProtocolIndexStringDataTimeoutTimer];
- }
- }];
- }
+- (void) closeSession {
+ [self.iapSession closeSession];
}
-/// Opens the input and output streams for the session on the main thread.
-/// @discussion We must close the input/output streams from the same thread that owns the streams' run loop, otherwise if the streams are closed from another thread a random crash may occur. Since only a small amount of data will be transmitted on this stream before it is closed, we will open and close the streams on the main thread instead of creating a separate thread.
-- (void)sdl_startStreamsWithCompletionHandler:(void (^)(BOOL success))completionHandler {
- if (![super createSession]) {
- return completionHandler(NO);
- }
-
- __weak typeof(self) weakSelf = self;
- dispatch_async(dispatch_get_main_queue(), ^{
- __strong typeof(weakSelf) strongSelf = weakSelf;
-
- SDLLogD(@"Created the control session successfully");
- [super startStream:strongSelf.eaSession.outputStream];
- [super startStream:strongSelf.eaSession.inputStream];
-
- return completionHandler(YES);
- });
+- (nullable EAAccessory *) accessory {
+ return self.iapSession.accessory;
}
-
-#pragma mark Stop
-
-/// Makes sure the session is closed and destroyed on the main thread.
-/// @param disconnectCompletionHandler Handler called when the session has disconnected
-- (void)destroySessionWithCompletionHandler:(void (^)(void))disconnectCompletionHandler {
- SDLLogD(@"Destroying the control session");
- dispatch_async(dispatch_get_main_queue(), ^{
- [self sdl_stopAndDestroySession];
- return disconnectCompletionHandler();
- });
+- (NSUInteger)connectionID {
+ return self.iapSession.connectionID;
}
-/// Closes the session streams and then destroys the session.
-- (void)sdl_stopAndDestroySession {
- NSAssert(NSThread.isMainThread, @"%@ must only be called on the main thread", NSStringFromSelector(_cmd));
-
- [super stopStream:self.eaSession.outputStream];
- [super stopStream:self.eaSession.inputStream];
- [super cleanupClosedSession];
+- (BOOL)isSessionInProgress {
+ return [self.iapSession isSessionInProgress];
}
-
#pragma mark - NSStreamDelegate
-/**
- * Handles events on the input/output streams of the open session.
- *
- * @param stream The stream (either input or output) that the event occured on
- * @param eventCode The stream event code
- */
-- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
- switch (eventCode) {
- case NSStreamEventOpenCompleted: {
- [self sdl_streamDidOpen:stream];
- break;
- }
- case NSStreamEventHasBytesAvailable: {
- [self sdl_streamHasBytesAvailable:(NSInputStream *)stream];
- break;
- }
- case NSStreamEventErrorOccurred: {
- [self sdl_streamDidError:stream];
- break;
- }
- case NSStreamEventEndEncountered: {
- [self sdl_streamDidEnd:stream];
- break;
- }
- case NSStreamEventNone:
- case NSStreamEventHasSpaceAvailable:
- default: {
- break;
- }
- }
-}
-/**
- * Called when the session gets a `NSStreamEventOpenCompleted`. When both the input and output streams open, start a timer to get data from Core within a certain timeframe.
- *
- * @param stream The stream that got the event code.
- */
-- (void)sdl_streamDidOpen:(NSStream *)stream {
- if (stream == [self.eaSession outputStream]) {
- SDLLogD(@"Control session output stream opened");
- self.isOutputStreamOpen = YES;
- } else if (stream == [self.eaSession inputStream]) {
- SDLLogD(@"Control session input stream opened");
- self.isInputStreamOpen = YES;
- }
-
- // When both streams are open, session initialization is complete. Let the delegate know.
- if (self.isInputStreamOpen && self.isOutputStreamOpen) {
- SDLLogV(@"Control session I/O streams opened for protocol: %@", self.protocolString);
+- (void) streamsDidOpen {
+ SDLLogD(@"SDLIAPControlSession streams opened for control session instance %@", self);
+ if (self.delegate != nil) {
[self sdl_startControlSessionProtocolIndexStringDataTimeoutTimer];
}
}
-/**
- * Called when the session gets a `NSStreamEventEndEncountered` event code. The current session is closed and a new session is attempted.
- */
-- (void)sdl_streamDidEnd:(NSStream *)stream {
- SDLLogD(@"Control stream ended");
-
- // End events come in pairs, only perform this once per set.
- [self.protocolIndexTimer cancel];
-
- __weak typeof(self) weakSelf = self;
- [self destroySessionWithCompletionHandler:^{
- __strong typeof(weakSelf) strongSelf = weakSelf;
- [strongSelf.delegate controlSessionShouldRetry];
- }];
+- (void) streamsDidEnd {
+ SDLLogD(@"SDLIAPControlSession EASession stream ended");
+ if (self.delegate != nil) {
+ [self.delegate controlSessionDidEnd];
+ }
}
+- (void)streamHasSpaceToWrite {}
+
/**
* Called when the session gets a `NSStreamEventHasBytesAvailable` event code. A protocol string is created from the received data. Since a new session needs to be established with the protocol string, the current session is closed and a new session is created.
*/
-- (void)sdl_streamHasBytesAvailable:(NSInputStream *)inputStream {
- SDLLogV(@"Control stream received data");
-
+- (void)streamHasBytesAvailable:(NSInputStream *)inputStream {
+ SDLLogD(@"SDLIAPControlSession EASession stream received data");
+
// Read in the stream a single byte at a time
uint8_t buf[1];
NSInteger len = [inputStream read:buf maxLength:1];
if (len <= 0) {
- SDLLogV(@"No data in the control stream");
+ SDLLogD(@"No data in the control stream");
return;
}
-
- // If we have data from the control stream, use the data to create the protocol string needed to establish the data session.
+
+ // If we have data from the control stream, use the data to create the protocol string needed to establish a data session.
NSString *indexedProtocolString = [NSString stringWithFormat:@"%@%@", IndexedProtocolStringPrefix, @(buf[0])];
- SDLLogD(@"Control Stream will switch to protocol %@", indexedProtocolString);
-
- // Destroy the control session as it is no longer needed, and then create the data session.
- __weak typeof(self) weakSelf = self;
- [self destroySessionWithCompletionHandler:^{
- __strong typeof(weakSelf) strongSelf = weakSelf;
- if (strongSelf.accessory.isConnected) {
- [strongSelf.protocolIndexTimer cancel];
- [strongSelf.delegate controlSession:strongSelf didReceiveProtocolString:indexedProtocolString];
- }
- }];
+ SDLLogD(@"SDLIAPControlSession EASession Stream will switch to protocol %@", indexedProtocolString);
+
+ [self.protocolIndexTimer cancel];
+ if (self.delegate != nil) {
+ [self.delegate controlSession:self didReceiveProtocolString:indexedProtocolString];
+ }
}
/**
* Called when the session gets a `NSStreamEventErrorOccurred` event code. The current session is closed and a new session is attempted.
*/
-- (void)sdl_streamDidError:(NSStream *)stream {
- SDLLogE(@"Control stream error");
-
+- (void)streamDidError {
+ SDLLogE(@"SDLIAPControlSession stream error");
[self.protocolIndexTimer cancel];
- __weak typeof(self) weakSelf = self;
- [self destroySessionWithCompletionHandler:^{
- __strong typeof(weakSelf) strongSelf = weakSelf;
- [strongSelf.delegate controlSessionShouldRetry];
- }];
+ if (self.delegate != nil) {
+ [self.delegate controlSessionDidEnd];
+ }
}
#pragma mark - Timer
@@ -233,17 +121,14 @@ int const ProtocolIndexTimeoutSeconds = 10;
*/
- (SDLTimer *)sdl_createControlSessionProtocolIndexStringDataTimeoutTimer {
SDLTimer *protocolIndexTimer = [[SDLTimer alloc] initWithDuration:ProtocolIndexTimeoutSeconds repeat:NO];
-
__weak typeof(self) weakSelf = self;
void (^elapsedBlock)(void) = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
- SDLLogW(@"Control session failed to get the protocol string from Core after %d seconds, retrying.", ProtocolIndexTimeoutSeconds);
- [strongSelf destroySessionWithCompletionHandler:^{
- __strong typeof(weakSelf) strongSelf = weakSelf;
- [strongSelf.delegate controlSessionShouldRetry];
- }];
+ SDLLogW(@"SDLIAPControlSession failed to get the protocol string from Core after %d seconds, retrying.", ProtocolIndexTimeoutSeconds);
+ if (self.delegate != nil) {
+ [strongSelf.delegate controlSessionDidEnd];
+ }
};
-
protocolIndexTimer.elapsedBlock = elapsedBlock;
return protocolIndexTimer;
}
@@ -259,3 +144,5 @@ int const ProtocolIndexTimeoutSeconds = 10;
@end
NS_ASSUME_NONNULL_END
+
+
diff --git a/SmartDeviceLink/private/SDLIAPControlSessionDelegate.h b/SmartDeviceLink/private/SDLIAPControlSessionDelegate.h
index 67ba2b042..0b5946fdd 100644
--- a/SmartDeviceLink/private/SDLIAPControlSessionDelegate.h
+++ b/SmartDeviceLink/private/SDLIAPControlSessionDelegate.h
@@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
@protocol SDLIAPControlSessionDelegate <NSObject>
-- (void)controlSessionShouldRetry;
+- (void)controlSessionDidEnd;
- (void)controlSession:(SDLIAPControlSession *)controlSession didReceiveProtocolString:(NSString *)protocolString;
@end