diff --git a/.gitignore b/.gitignore
index d5796ae..abca1e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,4 +6,5 @@ xcuserdata/
/.idea
build
QueueITLibSwift.xcframework.zip
-.DS_Store
\ No newline at end of file
+.DS_Store
+.index-build
diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/Package.swift b/Package.swift
index db710e0..0a4b44b 100644
--- a/Package.swift
+++ b/Package.swift
@@ -6,18 +6,18 @@ import PackageDescription
let package = Package(
name: "QueueITLibrary",
platforms: [
- .iOS(.v11)
+ .iOS(.v11),
],
products: [
.library(
name: "QueueITLibrary",
- targets: ["QueueITLibrary"]),
+ targets: ["QueueITLibrary"]
+ ),
],
targets: [
.target(
name: "QueueITLibrary",
- path: "QueueItLib/",
- publicHeadersPath: ""
- )
+ path: "Sources/QueueITLib"
+ ),
]
)
diff --git a/QueueITLib/IOSUtils.h b/QueueITLib/IOSUtils.h
deleted file mode 100644
index 758480b..0000000
--- a/QueueITLib/IOSUtils.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#import
-#import "QueueConsts.h"
-
-@interface IOSUtils : NSObject
-
-+(NSString*)getUserId;
-+(void)getUserAgent:(void (^)(NSString*))completionHandler;
-+(NSString*)getLibraryVersion;
-+(NSString*)getSdkVersion;
-+(NSString*)convertTtlMinutesToSecondsString:(int)ttlMinutes;
-
-@end
diff --git a/QueueITLib/IOSUtils.m b/QueueITLib/IOSUtils.m
deleted file mode 100644
index b2266cf..0000000
--- a/QueueITLib/IOSUtils.m
+++ /dev/null
@@ -1,55 +0,0 @@
-#import
-#import "IOSUtils.h"
-
-@implementation IOSUtils
-
-WKWebView* webView;
-
-+(NSString*)getUserId{
- UIDevice* device = [[UIDevice alloc]init];
- NSUUID* deviceid = [device identifierForVendor];
- NSString* uuid = [deviceid UUIDString];
- return uuid;
-}
-
-+(void)getUserAgent:(void (^)(NSString*))completionHandler{
- dispatch_async(dispatch_get_main_queue(), ^{
- WKWebView* view = [[WKWebView alloc] initWithFrame:CGRectZero];
- [view evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id _Nullable userAgent, NSError * _Nullable error) {
- if (error == nil) {
- completionHandler(userAgent);
- }
- else {
- completionHandler(@"");
- }
- webView = nil;
- }];
- webView = view;
- });
-}
-
-+(NSString*)getLibraryVersion{
- NSDictionary *infoDictionary = [[NSBundle mainBundle]infoDictionary];
-
- NSString *libName = infoDictionary[(NSString *)kCFBundleNameKey];
- NSString * major = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
- NSString *minor = infoDictionary[(NSString*)kCFBundleVersionKey];
- NSString* libversion = [NSString stringWithFormat:@"%@-%@.%@", libName, major, minor];
-
- return libversion;
-}
-
-+(NSString*)getSdkVersion{
- return SDKVersion;
-}
-
-+(NSString*)convertTtlMinutesToSecondsString:(int)ttlMinutes
-{
- long currentTime = (long)(NSTimeInterval)([[NSDate date] timeIntervalSince1970]);
- int secondsToAdd = ttlMinutes * 60.0;
- long timeStamp = currentTime + secondsToAdd;
- NSString* urlTtlString = [NSString stringWithFormat:@"%li", timeStamp];
- return urlTtlString;
-}
-
-@end
diff --git a/QueueITLib/PrivacyInfo.xcprivacy b/QueueITLib/PrivacyInfo.xcprivacy
deleted file mode 100644
index 5139ebc..0000000
--- a/QueueITLib/PrivacyInfo.xcprivacy
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
- NSPrivacyCollectedDataTypes
-
-
- NSPrivacyCollectedDataType
- NSPrivacyCollectedDataTypeOtherDataTypes
- NSPrivacyCollectedDataTypeLinked
-
- NSPrivacyCollectedDataTypeTracking
-
- NSPrivacyCollectedDataTypePurposes
-
- NSPrivacyCollectedDataTypePurposeAppFunctionality
-
-
-
- NSPrivacyCollectedDataType
- NSPrivacyCollectedDataTypeDeviceID
- NSPrivacyCollectedDataTypeLinked
-
- NSPrivacyCollectedDataTypeTracking
-
- NSPrivacyCollectedDataTypePurposes
-
- NSPrivacyCollectedDataTypePurposeAppFunctionality
-
-
-
- NSPrivacyTracking
-
-
-
diff --git a/QueueITLib/QueueConsts.h b/QueueITLib/QueueConsts.h
deleted file mode 100644
index eeee409..0000000
--- a/QueueITLib/QueueConsts.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef QueueConsts_h
-#define QueueConsts_h
-
-#define QueueCloseUrl @"queueit://close"
-#define QueueRestartSessionUrl @"queueit://restartSession"
-#define SDKVersion @"iOS-3.4.4";
-
-#endif
diff --git a/QueueITLib/QueueDisabledInfo.h b/QueueITLib/QueueDisabledInfo.h
deleted file mode 100644
index 428f707..0000000
--- a/QueueITLib/QueueDisabledInfo.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#import
-
-@interface QueueDisabledInfo : NSObject
-
-@property (nonatomic, strong) NSString* _Nullable queueitToken;
-
--(instancetype _Nonnull )initWithQueueitToken:(NSString* _Nullable) queueitToken;
-
-@end
diff --git a/QueueITLib/QueueDisabledInfo.m b/QueueITLib/QueueDisabledInfo.m
deleted file mode 100644
index f0c4935..0000000
--- a/QueueITLib/QueueDisabledInfo.m
+++ /dev/null
@@ -1,14 +0,0 @@
-#import "QueueDisabledInfo.h"
-
-@implementation QueueDisabledInfo
-
--(instancetype)initWithQueueitToken:(NSString *)queueitToken
-{
- if(self = [super init]) {
- self.queueitToken = queueitToken;
- }
-
- return self;
-}
-
-@end
diff --git a/QueueITLib/QueueITApiClient.h b/QueueITLib/QueueITApiClient.h
deleted file mode 100644
index 37448d2..0000000
--- a/QueueITLib/QueueITApiClient.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#import
-#import "QueueStatus.h"
-
-typedef void (^QueueServiceSuccess)(NSData *data);
-typedef void (^QueueServiceFailure)(NSError *error, NSString* errorMessage);
-
-@interface QueueITApiClient: NSObject
-
-+ (QueueITApiClient *)getInstance;
-+ (void) setTesting:(bool)enabled;
-
--(NSString*)enqueue:(NSString*)customerId
- eventOrAliasId:(NSString*)eventorAliasId
- userId:(NSString*)userId
- userAgent:(NSString*)userAgent
- sdkVersion:(NSString*)sdkVersion
- layoutName:(NSString*)layoutName
- language:(NSString*)language
- enqueueToken:(NSString*)enqueueToken
- enqueueKey:(NSString*)enqueueKey
- success:(void(^)(QueueStatus* queueStatus))success
- failure:(QueueServiceFailure)failure;
-
-@end
diff --git a/QueueITLib/QueueITApiClient.m b/QueueITLib/QueueITApiClient.m
deleted file mode 100644
index f40752e..0000000
--- a/QueueITLib/QueueITApiClient.m
+++ /dev/null
@@ -1,118 +0,0 @@
-#import "QueueITApiClient.h"
-#import "QueueITApiClient_NSURLConnection.h"
-
-static QueueITApiClient *SharedInstance;
-
-static NSString * const API_ROOT = @"https://%@.queue-it.net/api/mobileapp/queue";
-static NSString * const TESTING_API_ROOT = @"https://%@.test.queue-it.net/api/mobileapp/queue";
-static bool testingIsEnabled = NO;
-
-@implementation QueueITApiClient
-
-+ (QueueITApiClient *)getInstance
-{
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- SharedInstance = [[QueueITApiClient_NSURLConnection alloc] init];
- });
-
- return SharedInstance;
-}
-
-+ (void) setTesting:(bool)enabled
-{
- testingIsEnabled = enabled;
-}
-
--(NSString*)enqueue:(NSString *)customerId
- eventOrAliasId:(NSString *)eventorAliasId
- userId:(NSString *)userId
- userAgent:(NSString *)userAgent
- sdkVersion:(NSString*)sdkVersion
- layoutName:(NSString*)layoutName
- language:(NSString*)language
- enqueueToken:(NSString*)enqueueToken
- enqueueKey:(NSString*)enqueueKey
- success:(void (^)(QueueStatus *))success
- failure:(QueueServiceFailure)failure
-{
- NSMutableDictionary* bodyDict = [[NSMutableDictionary alloc] init];
- [bodyDict setObject:userId forKey:@"userId"];
- [bodyDict setObject:userAgent forKey:@"userAgent"];
- [bodyDict setObject:sdkVersion forKey:@"sdkVersion"];
-
- if(layoutName){
- [bodyDict setObject:layoutName forKey:@"layoutName"];
- }
-
- if(language){
- [bodyDict setObject:language forKey:@"language"];
- }
-
- if(enqueueToken){
- [bodyDict setObject:enqueueToken forKey:@"enqueueToken"];
- }
-
- if(enqueueKey){
- [bodyDict setObject:enqueueKey forKey:@"enqueueKey"];
- }
-
- NSString* urlAsString;
- if(testingIsEnabled){
- urlAsString = [NSString stringWithFormat:TESTING_API_ROOT, customerId];
- }else{
- urlAsString = [NSString stringWithFormat:API_ROOT, customerId];
- }
- urlAsString = [urlAsString stringByAppendingString:[NSString stringWithFormat:@"/%@", customerId]];
- urlAsString = [urlAsString stringByAppendingString:[NSString stringWithFormat:@"/%@", eventorAliasId]];
- urlAsString = [urlAsString stringByAppendingString:[NSString stringWithFormat:@"/enqueue"]];
-
- return [self submitPOSTPath:urlAsString body:bodyDict
- success:^(NSData *data)
- {
- NSError *error = nil;
- NSDictionary *userDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
- if (userDict && [userDict isKindOfClass:[NSDictionary class]])
- {
- QueueStatus* queueStatus = [[QueueStatus alloc] initWithDictionary:userDict];
-
- if (success != NULL) {
- success(queueStatus);
- }
- } else if (success != NULL) {
- success(NULL);
- }
- }
- failure:^(NSError *error, NSString* errorMessage)
- {
- failure(error, errorMessage);
- }
- ];
-}
-
-- (NSString *)submitPOSTPath:(NSString *)path
- body:(NSDictionary *)bodyDict
- success:(QueueServiceSuccess)success
- failure:(QueueServiceFailure)failure
-{
- NSURL *url = [NSURL URLWithString:path];
- return [self submitRequestWithURL:url
- method:@"POST"
- body:bodyDict
- expectedStatus:200
- success:success
- failure:failure];
-}
-
-#pragma mark - Abstract methods
-- (NSString *)submitRequestWithURL:(NSURL *)URL
- method:(NSString *)httpMethod
- body:(NSDictionary *)bodyDict
- expectedStatus:(NSInteger)expectedStatus
- success:(QueueServiceSuccess)success
- failure:(QueueServiceFailure)failure
-{
- return nil;
-}
-
-@end
diff --git a/QueueITLib/QueueITApiClient_NSURLConnection.h b/QueueITLib/QueueITApiClient_NSURLConnection.h
deleted file mode 100644
index 01071bf..0000000
--- a/QueueITLib/QueueITApiClient_NSURLConnection.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#import
-#import "QueueITApiClient.h"
-
-@interface QueueITApiClient_NSURLConnection : QueueITApiClient
-
-@end
diff --git a/QueueITLib/QueueITApiClient_NSURLConnection.m b/QueueITLib/QueueITApiClient_NSURLConnection.m
deleted file mode 100644
index 21edb11..0000000
--- a/QueueITLib/QueueITApiClient_NSURLConnection.m
+++ /dev/null
@@ -1,46 +0,0 @@
-#import "QueueITApiClient_NSURLConnection.h"
-#import "QueueITApiClient_NSURLConnectionRequest.h"
-
-@interface QueueITApiClient_NSURLConnection()
-@end
-
-
-@implementation QueueITApiClient_NSURLConnection
-
-- (NSString *)submitRequestWithURL:(NSURL *)URL
- method:(NSString *)httpMethod
- body:(NSDictionary *)bodyDict
- expectedStatus:(NSInteger)expectedStatus
- success:(QueueServiceSuccess)success
- failure:(QueueServiceFailure)failure
-{
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
- [request setHTTPMethod:httpMethod];
-
- NSError *error;
- NSData *jsonData = [NSJSONSerialization dataWithJSONObject:bodyDict
- options:0
- error:&error];
- [request setHTTPBody: jsonData];
- [request addValue:@"application/json" forHTTPHeaderField:@"Accept"];
- [request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
-
- QueueITApiClient_NSURLConnectionRequest *connectionRequest;
- connectionRequest = [[QueueITApiClient_NSURLConnectionRequest alloc] initWithRequest:request
- expectedStatusCode:expectedStatus
- success:success
- failure:failure
- delegate:self];
-
- NSString *connectionID = [connectionRequest uniqueIdentifier];
-
- return connectionID;
-}
-
-#pragma mark - NSURLConnectionRequestDelegate
-
-- (void)requestDidComplete:(QueueITApiClient_NSURLConnectionRequest *)request
-{
-}
-
-@end
diff --git a/QueueITLib/QueueITApiClient_NSURLConnectionRequest.h b/QueueITLib/QueueITApiClient_NSURLConnectionRequest.h
deleted file mode 100644
index 6b5013d..0000000
--- a/QueueITLib/QueueITApiClient_NSURLConnectionRequest.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#import
-#import "QueueITApiClient.h"
-
-@protocol QueueService_NSURLConnectionRequestDelegate;
-
-@interface QueueITApiClient_NSURLConnectionRequest : NSObject
-
-- (NSString *)uniqueIdentifier;
-
-- (instancetype)initWithRequest:(NSURLRequest *)request
- expectedStatusCode:(NSInteger)statusCode
- success:(QueueServiceSuccess)success
- failure:(QueueServiceFailure)failure
- delegate:(id)delegate;
-
-@end
-
-@protocol QueueService_NSURLConnectionRequestDelegate
-- (void)requestDidComplete:(QueueITApiClient_NSURLConnectionRequest *)request;
-@end
diff --git a/QueueITLib/QueueITApiClient_NSURLConnectionRequest.m b/QueueITLib/QueueITApiClient_NSURLConnectionRequest.m
deleted file mode 100644
index 13cdcc5..0000000
--- a/QueueITLib/QueueITApiClient_NSURLConnectionRequest.m
+++ /dev/null
@@ -1,133 +0,0 @@
-#import "QueueITApiClient_NSURLConnectionRequest.h"
-
-
-@interface QueueITApiClient_NSURLConnectionRequest()
-
-@property (nonatomic, strong) NSURLConnection *connection;
-@property (nonatomic, strong) NSURLRequest *request;
-@property (nonatomic, strong) NSURLResponse *response;
-@property (nonatomic, strong) NSMutableData *data;
-@property (nonatomic, copy) QueueServiceSuccess successCallback;
-@property (nonatomic, copy) QueueServiceFailure failureCallback;
-@property (nonatomic, weak) id delegate;
-@property (nonatomic, strong) NSString *uniqueIdentifier;
-@property (nonatomic, assign) NSInteger expectedStatusCode;
-@property (nonatomic, assign) NSInteger actualStatusCode;
-
-@end
-
-@implementation QueueITApiClient_NSURLConnectionRequest
-
-- (instancetype)initWithRequest:(NSURLRequest *)request
- expectedStatusCode:(NSInteger)statusCode
- success:(QueueServiceSuccess)success
- failure:(QueueServiceFailure)failure
- delegate:(id)delegate
-{
- if ((self = [super init])) {
- self.request = request;
- self.expectedStatusCode = statusCode;
- self.successCallback = success;
- self.failureCallback = failure;
- self.uniqueIdentifier = [[NSUUID UUID] UUIDString];
- self.delegate = delegate;
-
- [self initiateRequest];
- }
-
- return self;
-}
-
-- (void)initiateRequest
-{
- self.response = nil;
- self.data = [NSMutableData data];
- self.actualStatusCode = NSNotFound;
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self];
-#pragma GCC diagnostic pop
-}
-
-#pragma mark - NSURLConnectionDelegate
-
-- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
-{
- dispatch_async(dispatch_get_main_queue(), ^{
- self.failureCallback(error, @"Unexpected failure occured.");
- });
-
- [self.delegate requestDidComplete:self];
-}
-
-#pragma mark - NSURLConnectionDataDelegate
-
-- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
-{
- self.response = response;
- NSInteger responseCode = [(NSHTTPURLResponse *)response statusCode];
- self.actualStatusCode = responseCode;
-}
-
-- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
-{
- [self appendData:data];
-}
-
-- (void)connectionDidFinishLoading:(NSURLConnection *)connection
-{
- if ([self hasExpectedStatusCode]) {
- dispatch_async(dispatch_get_main_queue(), ^{
- self.successCallback(self.data);
- });
- }
- else {
- NSString *message = [NSString stringWithFormat:@"Unexpected response code: %li", (long)self.actualStatusCode];
-
- if (self.actualStatusCode >= 400 && self.actualStatusCode < 500)
- {
- message = [NSString stringWithCString:[self.data bytes] encoding:NSASCIIStringEncoding];
- }
- else
- {
- if (self.data) {
- NSError *jsonError = nil;
- id json = [NSJSONSerialization JSONObjectWithData:self.data options:0 error:&jsonError];
- if (json && [json isKindOfClass:[NSDictionary class]]) {
- NSString *errorMessage = [(NSDictionary *)json valueForKey:@"error"];
- if (errorMessage) {
- message = errorMessage;
- }
- }
- }
- }
-
- NSError *error = [NSError errorWithDomain:@"QueueService"
- code:self.actualStatusCode
- userInfo:@{ NSLocalizedDescriptionKey: message }];
-
- dispatch_async(dispatch_get_main_queue(), ^{
- self.failureCallback(error, message);
- });
- }
-
- [self.delegate requestDidComplete:self];
-}
-
-#pragma mark - Private helpers
-
-- (void)appendData:(NSData *)data
-{
- [self.data appendData:data];
-}
-
-- (BOOL)hasExpectedStatusCode
-{
- if (self.actualStatusCode != NSNotFound) {
- return self.expectedStatusCode == self.actualStatusCode;
- }
-
- return NO;
-}
-
-@end
diff --git a/QueueITLib/QueueITEngine.h b/QueueITLib/QueueITEngine.h
deleted file mode 100644
index 8931119..0000000
--- a/QueueITLib/QueueITEngine.h
+++ /dev/null
@@ -1,98 +0,0 @@
-#import
-#import "QueuePassedInfo.h"
-#import "QueueDisabledInfo.h"
-#import "QueueTryPassResult.h"
-#import "QueueConsts.h"
-#import "QueueITWaitingRoomView.h"
-#import "QueueITWaitingRoomProvider.h"
-
-@protocol QueuePassedDelegate;
-@protocol QueueViewWillOpenDelegate;
-@protocol QueueDisabledDelegate;
-@protocol QueueITUnavailableDelegate;
-@protocol QueueUserExitedDelegate;
-@protocol QueueITErrorDelegate;
-@protocol QueueViewClosedDelegate;
-@protocol QueueSessionRestartDelegate;
-@protocol QueueUrlChangedDelegate;
-
-@protocol QueueViewDidAppearDelegate;
-
-@interface QueueITEngine : NSObject
-
-@property (nonatomic, weak)id _Nullable queuePassedDelegate;
-@property (nonatomic, weak)id _Nullable queueViewWillOpenDelegate;
-@property (nonatomic, weak)id _Nullable queueDisabledDelegate;
-@property (nonatomic, weak)id _Nullable queueITUnavailableDelegate;
-@property (nonatomic, weak)id _Nullable queueErrorDelegate;
-@property (nonatomic, weak)id _Nullable queueViewClosedDelegate;
-@property (nonatomic, weak)id _Nullable queueUserExitedDelegate;
-@property (nonatomic, weak)id _Nullable queueSessionRestartDelegate;
-@property (nonatomic, weak)id _Nullable queueUrlChangedDelegate;
-
-@property (nonatomic, weak)id _Nullable queueViewDidAppearDelegate;
-
-@property (nonatomic, strong)NSString* _Nullable errorMessage;
-@property (nonatomic, copy)NSString* _Nonnull customerId;
-@property (nonatomic, copy)NSString* _Nonnull eventId;
-@property (nonatomic, copy)NSString* _Nullable layoutName;
-@property (nonatomic, copy)NSString* _Nullable language;
-
--(instancetype _Nonnull )initWithHost:(UIViewController* _Nonnull)host
- customerId:(NSString* _Nonnull)customerId
- eventOrAliasId:(NSString* _Nonnull)eventOrAliasId
- layoutName:(NSString* _Nullable)layoutName
- language:(NSString* _Nullable)language;
-
--(void)setViewDelay:(int)delayInterval;
-
--(BOOL)run:(NSError* _Nullable* _Nullable)error;
--(BOOL)runWithEnqueueToken:(NSString* _Nonnull) enqueueToken
- error:(NSError* _Nullable*_Nullable) error;
--(BOOL)runWithEnqueueKey:(NSString* _Nonnull) enqueueKey
- error:(NSError* _Nullable*_Nullable) error;
--(BOOL)isRequestInProgress;
-
-@end
-
-@protocol QueuePassedDelegate
--(void)notifyYourTurn:(QueuePassedInfo* _Nullable) queuePassedInfo;
-@end
-
-
-@protocol QueueViewWillOpenDelegate
--(void)notifyQueueViewWillOpen;
-@end
-
-@protocol QueueDisabledDelegate
--(void)notifyQueueDisabled:(QueueDisabledInfo* _Nullable) queueDisabledInfo;
-@end
-
-@protocol QueueITUnavailableDelegate
--(void)notifyQueueITUnavailable:(NSString* _Nonnull) errorMessage;
-@end
-
-@protocol QueueITErrorDelegate
--(void)notifyQueueError:(NSString* _Nonnull) errorMessage errorCode:(long)errorCode;
-@end
-
-@protocol QueueViewClosedDelegate
--(void)notifyViewClosed;
-@end
-
-@protocol QueueUserExitedDelegate
--(void)notifyUserExited;
-@end
-
-@protocol QueueSessionRestartDelegate
--(void)notifySessionRestart;
-@end
-
-@protocol QueueUrlChangedDelegate
--(void)notifyQueueUrlChanged:(NSString* _Nonnull) url;
-@end
-
-
-@protocol QueueViewDidAppearDelegate
--(void)notifyQueueViewDidAppear;
-@end
diff --git a/QueueITLib/QueueITEngine.m b/QueueITLib/QueueITEngine.m
deleted file mode 100644
index 6778bf7..0000000
--- a/QueueITLib/QueueITEngine.m
+++ /dev/null
@@ -1,125 +0,0 @@
-#import "QueueITEngine.h"
-#import "QueueITApiClient.h"
-#import "QueueStatus.h"
-#import "IOSUtils.h"
-#import "QueueITWaitingRoomView.h"
-#import "QueueITWaitingRoomProvider.h"
-
-@interface QueueITEngine()
-@property (nonatomic, weak)UIViewController* host;
-
-@property QueueITWaitingRoomProvider* waitingRoomProvider;
-@property QueueITWaitingRoomView* waitingRoomView;
-@end
-
-@implementation QueueITEngine
-
--(instancetype)initWithHost:(UIViewController *)host customerId:(NSString*)customerId eventOrAliasId:(NSString*)eventOrAliasId layoutName:(NSString*)layoutName language:(NSString*)language
-{
- self = [super init];
- if(self) {
- self.waitingRoomProvider = [[QueueITWaitingRoomProvider alloc] initWithCustomerId:customerId
- eventOrAliasId:eventOrAliasId
- layoutName:layoutName
- language:language];
-
- self.waitingRoomView = [[QueueITWaitingRoomView alloc] initWithHost: host customerId: customerId eventId: eventOrAliasId];
- self.host = host;
- self.customerId = customerId;
- self.eventId = eventOrAliasId;
- self.layoutName = layoutName;
- self.language = language;
-
- self.waitingRoomView.delegate = self;
- self.waitingRoomProvider.delegate = self;
- }
- return self;
-}
-
--(void)setViewDelay:(int)delayInterval {
- [self.waitingRoomView setViewDelay:delayInterval];
-}
-
--(BOOL)isRequestInProgress {
- return [self.waitingRoomProvider IsRequestInProgress];
-}
-
--(BOOL)runWithEnqueueKey:(NSString *)enqueueKey
- error:(NSError *__autoreleasing *)error
-{
- return [self.waitingRoomProvider TryPassWithEnqueueKey:enqueueKey error:error];
-}
-
--(BOOL)runWithEnqueueToken:(NSString *)enqueueToken
- error:(NSError *__autoreleasing *)error
-{
- return [self.waitingRoomProvider TryPassWithEnqueueToken:enqueueToken error:error];
-}
-
--(BOOL)run:(NSError **)error
-{
- return [self.waitingRoomProvider TryPass:error];
-}
-
-
-
--(void)showQueue:(NSString*)queueUrl targetUrl:(NSString*)targetUrl
-{
- [self.waitingRoomView show:queueUrl targetUrl:targetUrl];
-}
-
-
-- (void)waitingRoomView:(nonnull QueueITWaitingRoomView *)view notifyViewPassedQueue:(QueuePassedInfo * _Nullable)queuePassedInfo {
- [self.queuePassedDelegate notifyYourTurn:queuePassedInfo];
-}
-
-- (void)notifyViewQueueWillOpen:(nonnull QueueITWaitingRoomView *)view {
- [self.queueViewWillOpenDelegate notifyQueueViewWillOpen];
-}
-
-- (void)waitingRoomProvider:(nonnull QueueITWaitingRoomProvider *)provider notifyProviderFailure:(NSString * _Nullable)errorMessage errorCode:(long)errorCode {
- if(errorCode == 3) {
- [self.queueITUnavailableDelegate notifyQueueITUnavailable:errorMessage];
- }
-
- [self.queueErrorDelegate notifyQueueError:errorMessage errorCode:errorCode];
-}
-
-- (void)notifyViewSessionRestart:(nonnull QueueITWaitingRoomView *)view {
- [self.queueSessionRestartDelegate notifySessionRestart];
-}
-
-- (void)notifyViewUserExited:(nonnull QueueITWaitingRoomView *)view {
- [self.queueUserExitedDelegate notifyUserExited];
-}
-
-- (void)notifyViewUserClosed:(nonnull QueueITWaitingRoomView *)view {
- [self.queueViewClosedDelegate notifyViewClosed];
-}
-
-- (void)waitingRoomView:(nonnull QueueITWaitingRoomView *)view notifyViewUpdatePageUrl:(NSString * _Nullable)urlString {
- [self.queueUrlChangedDelegate notifyQueueUrlChanged:urlString];
-}
-
--(void)notifyViewQueueDidAppear:(nonnull QueueITWaitingRoomView *)view {
- [self.queueViewDidAppearDelegate notifyQueueViewDidAppear];
-}
-
-- (void)waitingRoomProvider:(nonnull QueueITWaitingRoomProvider *)provider notifyProviderSuccess:(QueueTryPassResult * _Nonnull)queuePassResult {
- if([[queuePassResult redirectType] isEqual: @"safetynet"])
- {
- QueuePassedInfo* queuePassedInfo = [[QueuePassedInfo alloc] initWithQueueitToken:queuePassResult.queueToken];
- [self.queuePassedDelegate notifyYourTurn:queuePassedInfo];
- return;
- }
- else if([[queuePassResult redirectType] isEqual: @"disabled"] || [[queuePassResult redirectType] isEqual: @"idle"] || [[queuePassResult redirectType] isEqual: @"afterevent"])
- {
- QueueDisabledInfo* queueDisabledInfo = [[QueueDisabledInfo alloc]initWithQueueitToken:queuePassResult.queueToken];
- [self.queueDisabledDelegate notifyQueueDisabled:queueDisabledInfo];
- return;
- }
-
- [self showQueue:queuePassResult.queueUrl targetUrl:queuePassResult.targetUrl];
-
-}
-@end
diff --git a/QueueITLib/QueueITReachability.h b/QueueITLib/QueueITReachability.h
deleted file mode 100644
index d9c8fbb..0000000
--- a/QueueITLib/QueueITReachability.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- File: Reachability.h
- Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
- Version: 3.5
-
- Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
- Inc. ("Apple") in consideration of your agreement to the following
- terms, and your use, installation, modification or redistribution of
- this Apple software constitutes acceptance of these terms. If you do
- not agree with these terms, please do not use, install, modify or
- redistribute this Apple software.
-
- In consideration of your agreement to abide by the following terms, and
- subject to these terms, Apple grants you a personal, non-exclusive
- license, under Apple's copyrights in this original Apple software (the
- "Apple Software"), to use, reproduce, modify and redistribute the Apple
- Software, with or without modifications, in source and/or binary forms;
- provided that if you redistribute the Apple Software in its entirety and
- without modifications, you must retain this notice and the following
- text and disclaimers in all such redistributions of the Apple Software.
- Neither the name, trademarks, service marks or logos of Apple Inc. may
- be used to endorse or promote products derived from the Apple Software
- without specific prior written permission from Apple. Except as
- expressly stated in this notice, no other rights or licenses, express or
- implied, are granted by Apple herein, including but not limited to any
- patent rights that may be infringed by your derivative works or by other
- works in which the Apple Software may be incorporated.
-
- The Apple Software is provided by Apple on an "AS IS" basis. APPLE
- MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
- THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
- FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
- OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
-
- IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
- MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
- AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
- STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-
- Copyright (C) 2014 Apple Inc. All Rights Reserved.
-
- */
-
-#import
-#import
-#import
-
-
-typedef enum : NSInteger {
- NotReachable = 0,
- ReachableViaWiFi,
- ReachableViaWWAN
-} NetworkStatus;
-
-
-extern NSString *kReachabilityChangedNotification;
-
-
-@interface QueueITReachability : NSObject
-
-/*!
- * Use to check the reachability of a given host name.
- */
-+ (instancetype)reachabilityWithHostName:(NSString *)hostName;
-
-/*!
- * Use to check the reachability of a given IP address.
- */
-+ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress;
-
-/*!
- * Checks whether the default route is available. Should be used by applications that do not connect to a particular host.
- */
-+ (instancetype)reachabilityForInternetConnection;
-
-/*!
- * Checks whether a local WiFi connection is available.
- */
-+ (instancetype)reachabilityForLocalWiFi;
-
-/*!
- * Start listening for reachability notifications on the current run loop.
- */
-- (BOOL)startNotifier;
-- (void)stopNotifier;
-
-- (NetworkStatus)currentReachabilityStatus;
-
-/*!
- * WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand.
- */
-- (BOOL)connectionRequired;
-
-@end
-
-
diff --git a/QueueITLib/QueueITReachability.m b/QueueITLib/QueueITReachability.m
deleted file mode 100644
index 0bf7155..0000000
--- a/QueueITLib/QueueITReachability.m
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- File: Reachability.m
- Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
- Version: 3.5
-
- Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
- Inc. ("Apple") in consideration of your agreement to the following
- terms, and your use, installation, modification or redistribution of
- this Apple software constitutes acceptance of these terms. If you do
- not agree with these terms, please do not use, install, modify or
- redistribute this Apple software.
-
- In consideration of your agreement to abide by the following terms, and
- subject to these terms, Apple grants you a personal, non-exclusive
- license, under Apple's copyrights in this original Apple software (the
- "Apple Software"), to use, reproduce, modify and redistribute the Apple
- Software, with or without modifications, in source and/or binary forms;
- provided that if you redistribute the Apple Software in its entirety and
- without modifications, you must retain this notice and the following
- text and disclaimers in all such redistributions of the Apple Software.
- Neither the name, trademarks, service marks or logos of Apple Inc. may
- be used to endorse or promote products derived from the Apple Software
- without specific prior written permission from Apple. Except as
- expressly stated in this notice, no other rights or licenses, express or
- implied, are granted by Apple herein, including but not limited to any
- patent rights that may be infringed by your derivative works or by other
- works in which the Apple Software may be incorporated.
-
- The Apple Software is provided by Apple on an "AS IS" basis. APPLE
- MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
- THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
- FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
- OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
-
- IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
- MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
- AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
- STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-
- Copyright (C) 2014 Apple Inc. All Rights Reserved.
-
- */
-
-#import
-#import
-#import
-#import
-
-#import
-
-#import "QueueITReachability.h"
-
-
-NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification";
-
-
-#pragma mark - Supporting functions
-
-#define kShouldPrintReachabilityFlags 1
-
-static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
-{
-#if kShouldPrintReachabilityFlags
-#endif
-}
-
-
-static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
-{
-#pragma unused (target, flags)
- NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
- NSCAssert([(__bridge NSObject*) info isKindOfClass: [QueueITReachability class]], @"info was wrong class in ReachabilityCallback");
-
- QueueITReachability* noteObject = (__bridge QueueITReachability *)info;
- // Post a notification to notify the client that the network reachability changed.
- [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
-}
-
-
-#pragma mark - Reachability implementation
-
-@implementation QueueITReachability
-{
- BOOL _alwaysReturnLocalWiFiStatus; //default is NO
- SCNetworkReachabilityRef _reachabilityRef;
-}
-
-+ (instancetype)reachabilityWithHostName:(NSString *)hostName
-{
- QueueITReachability* returnValue = NULL;
- SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
- if (reachability != NULL)
- {
- returnValue= [[self alloc] init];
- if (returnValue != NULL)
- {
- returnValue->_reachabilityRef = reachability;
- returnValue->_alwaysReturnLocalWiFiStatus = NO;
- }
- }
- return returnValue;
-}
-
-
-+ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress
-{
- SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)hostAddress);
-
- QueueITReachability* returnValue = NULL;
-
- if (reachability != NULL)
- {
- returnValue = [[self alloc] init];
- if (returnValue != NULL)
- {
- returnValue->_reachabilityRef = reachability;
- returnValue->_alwaysReturnLocalWiFiStatus = NO;
- }
- }
- return returnValue;
-}
-
-
-
-+ (instancetype)reachabilityForInternetConnection
-{
- struct sockaddr_in zeroAddress;
- bzero(&zeroAddress, sizeof(zeroAddress));
- zeroAddress.sin_len = sizeof(zeroAddress);
- zeroAddress.sin_family = AF_INET;
-
- return [self reachabilityWithAddress:&zeroAddress];
-}
-
-
-+ (instancetype)reachabilityForLocalWiFi
-{
- struct sockaddr_in localWifiAddress;
- bzero(&localWifiAddress, sizeof(localWifiAddress));
- localWifiAddress.sin_len = sizeof(localWifiAddress);
- localWifiAddress.sin_family = AF_INET;
-
- // IN_LINKLOCALNETNUM is defined in as 169.254.0.0.
- localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
-
- QueueITReachability* returnValue = [self reachabilityWithAddress: &localWifiAddress];
- if (returnValue != NULL)
- {
- returnValue->_alwaysReturnLocalWiFiStatus = YES;
- }
-
- return returnValue;
-}
-
-
-#pragma mark - Start and stop notifier
-
-- (BOOL)startNotifier
-{
- BOOL returnValue = NO;
- SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
-
- if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context))
- {
- if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
- {
- returnValue = YES;
- }
- }
-
- return returnValue;
-}
-
-
-- (void)stopNotifier
-{
- if (_reachabilityRef != NULL)
- {
- SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
- }
-}
-
-
-- (void)dealloc
-{
- [self stopNotifier];
- if (_reachabilityRef != NULL)
- {
- CFRelease(_reachabilityRef);
- }
-}
-
-
-#pragma mark - Network Flag Handling
-
-- (NetworkStatus)localWiFiStatusForFlags:(SCNetworkReachabilityFlags)flags
-{
- PrintReachabilityFlags(flags, "localWiFiStatusForFlags");
- NetworkStatus returnValue = NotReachable;
-
- if ((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))
- {
- returnValue = ReachableViaWiFi;
- }
-
- return returnValue;
-}
-
-
-- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
-{
- PrintReachabilityFlags(flags, "networkStatusForFlags");
- if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
- {
- // The target host is not reachable.
- return NotReachable;
- }
-
- NetworkStatus returnValue = NotReachable;
-
- if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
- {
- /*
- If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
- */
- returnValue = ReachableViaWiFi;
- }
-
- if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
- (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
- {
- /*
- ... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
- */
-
- if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
- {
- /*
- ... and no [user] intervention is needed...
- */
- returnValue = ReachableViaWiFi;
- }
- }
-
- if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
- {
- /*
- ... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
- */
- returnValue = ReachableViaWWAN;
- }
-
- return returnValue;
-}
-
-
-- (BOOL)connectionRequired
-{
- NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
- SCNetworkReachabilityFlags flags;
-
- if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
- {
- return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
- }
-
- return NO;
-}
-
-
-- (NetworkStatus)currentReachabilityStatus
-{
- NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
- NetworkStatus returnValue = NotReachable;
- SCNetworkReachabilityFlags flags;
-
- if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
- {
- if (_alwaysReturnLocalWiFiStatus)
- {
- returnValue = [self localWiFiStatusForFlags:flags];
- }
- else
- {
- returnValue = [self networkStatusForFlags:flags];
- }
- }
-
- return returnValue;
-}
-
-
-@end
diff --git a/QueueITLib/QueueITWKViewController.h b/QueueITLib/QueueITWKViewController.h
deleted file mode 100644
index b84d5ce..0000000
--- a/QueueITLib/QueueITWKViewController.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#import
-
-@protocol QueueITViewControllerDelegate;
-
-@interface QueueITWKViewController : UIViewController
-
-@property (nonatomic, weak)id _Nullable delegate;
-
--(instancetype _Nullable )initWithHost:(nonnull UIViewController *)host
- queueUrl:(nonnull NSString*)queueUrl
- eventTargetUrl:(nonnull NSString*)eventTargetUrl
- customerId:(nonnull NSString*)customerId
- eventId:(nonnull NSString*)eventId;
-
-- (void) close:(void (^ __nullable)(void))completion;
-- (BOOL) handleSpecialUrls:(nonnull NSURL*) url
- decisionHandler:(nonnull void (^)(WKNavigationActionPolicy))decisionHandler;
-- (BOOL) isTargetUrl:(nonnull NSURL*) targetUrl
- destinationUrl:(nonnull NSURL*) destinationUrl;
-- (BOOL) isBlockedUrl:(nonnull NSURL*) destinationUrl;
-
-@end
-
-@protocol QueueITViewControllerDelegate
--(void)notifyViewControllerClosed;
--(void)notifyViewControllerUserExited;
--(void)notifyViewControllerSessionRestart;
--(void)notifyViewControllerQueuePassed:(NSString* _Nullable) queueToken;
--(void)notifyViewControllerPageUrlChanged:(NSString* _Nullable) urlString;
-@end
diff --git a/QueueITLib/QueueITWKViewController.m b/QueueITLib/QueueITWKViewController.m
deleted file mode 100644
index 0c0220b..0000000
--- a/QueueITLib/QueueITWKViewController.m
+++ /dev/null
@@ -1,235 +0,0 @@
-#import "QueueITWKViewController.h"
-#import "QueueConsts.h"
-
-@interface QueueITWKViewController ()
-@property (nonatomic) WKWebView* webView;
-@property (nonatomic, strong) UIViewController* host;
-
-@property (nonatomic, strong)NSString* queueUrl;
-@property (nonatomic, strong)NSString* eventTargetUrl;
-@property (nonatomic, strong)UIActivityIndicatorView* spinner;
-@property (nonatomic, strong)NSString* customerId;
-@property (nonatomic, strong)NSString* eventId;
-@property BOOL isQueuePassed;
-@end
-
-static NSString * const JAVASCRIPT_GET_BODY_CLASSES = @"document.getElementsByTagName('body')[0].className";
-
-@implementation QueueITWKViewController
-
--(instancetype)initWithHost:(UIViewController *)host
- queueUrl:(NSString*)queueUrl
- eventTargetUrl:(NSString*)eventTargetUrl
- customerId:(NSString*)customerId
- eventId:(NSString*)eventId
-{
- self = [super init];
- if(self) {
- self.host = host;
- self.queueUrl = queueUrl;
- self.eventTargetUrl = eventTargetUrl;
- self.customerId = customerId;
- self.eventId = eventId;
- self.isQueuePassed = NO;
- }
- return self;
-}
-
-- (void)close:(void (^ __nullable)(void))onComplete {
- [self.host dismissViewControllerAnimated:YES completion:^{
- if(onComplete!=nil){
- onComplete();
- }
- }];
-}
-
-- (BOOL) isTargetUrl:(nonnull NSURL*) targetUrl
- destinationUrl:(nonnull NSURL*) destinationUrl {
- NSString* destinationHost = destinationUrl.host;
- NSString* destinationPath = destinationUrl.path;
- NSString* targetHost = targetUrl.host;
- NSString* targetPath = targetUrl.path;
-
- return [destinationHost isEqualToString: targetHost]
- && [destinationPath isEqualToString: targetPath];
-}
-
-- (BOOL) isBlockedUrl:(nonnull NSURL*) destinationUrl {
- NSString* path = destinationUrl.path;
- if([path hasPrefix: @"/what-is-this.html"]){
- return true;
- }
- return false;
-}
-
-- (BOOL)handleSpecialUrls:(NSURL*) url
- decisionHandler:(nonnull void (^)(WKNavigationActionPolicy))decisionHandler {
- if([[url absoluteString] isEqualToString: QueueCloseUrl]){
- [self close: ^{
- [self.delegate notifyViewControllerClosed];
- }];
- decisionHandler(WKNavigationActionPolicyCancel);
- return true;
- } else if ([[url absoluteString] isEqualToString: QueueRestartSessionUrl]){
- [self close:^{
- [self.delegate notifyViewControllerSessionRestart];
- }];
- decisionHandler(WKNavigationActionPolicyCancel);
- return true;
- }
- return NO;
-}
-
-- (void)viewDidLoad {
- [super viewDidLoad];
- self.spinner = [[UIActivityIndicatorView alloc]initWithFrame:self.view.bounds];
- [self.spinner setColor:[UIColor grayColor]];
-
- WKPreferences* preferences = [[WKPreferences alloc]init];
- preferences.javaScriptEnabled = YES;
- WKWebViewConfiguration* config = [[WKWebViewConfiguration alloc]init];
- config.preferences = preferences;
- WKWebView* webview = [[WKWebView alloc]initWithFrame:self.view.bounds configuration:config];
- webview.navigationDelegate = self;
- [webview setAutoresizingMask: UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
- // Make webview transparent
- webview.opaque = NO;
- webview.backgroundColor = [UIColor clearColor];
- self.webView = webview;
-}
-
-- (void)viewWillAppear:(BOOL)animated{
- [super viewWillAppear:animated];
-}
-
--(void)viewWillLayoutSubviews{
- [super viewWillLayoutSubviews];
- [self.spinner startAnimating];
- self.webView.frame = self.view.bounds;
- self.spinner.frame = self.view.bounds;
-
- [self.view addSubview:self.webView];
- [self.webView addSubview:self.spinner];
-
- [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.queueUrl]]];
-}
-
--(void)viewDidAppear:(BOOL)animated{
- [super viewDidAppear:animated];
-}
-
-- (void)viewDidDisappear:(BOOL)animated
-{
- [super viewDidDisappear:animated];
- [self.webView removeFromSuperview];
- self.webView = nil;
-}
-
-#pragma mark - WKNavigationDelegate
-
-- (void)webView:(WKWebView*)webView decidePolicyForNavigationAction:(nonnull WKNavigationAction *)navigationAction decisionHandler:(nonnull void (^)(WKNavigationActionPolicy))decisionHandler{
- if (!self.isQueuePassed) {
- NSURLRequest* request = navigationAction.request;
- NSString* urlString = [[request URL] absoluteString];
- NSString* targetUrlString = self.eventTargetUrl;
- if (urlString != nil) {
- NSURL* url = [NSURL URLWithString:urlString];
- NSURL* targetUrl = [NSURL URLWithString:targetUrlString];
- if(urlString != nil && ![urlString isEqualToString:@"about:blank"]) {
- BOOL isQueueUrl = [self.queueUrl containsString:url.host];
- BOOL isNotFrame = [[[request URL] absoluteString] isEqualToString:[[request mainDocumentURL] absoluteString]];
-
- if([self handleSpecialUrls:url decisionHandler:decisionHandler]){
- return;
- }
-
- if([self isBlockedUrl: url]){
- decisionHandler(WKNavigationActionPolicyCancel);
- return;
- }
-
- if (isNotFrame) {
- if (isQueueUrl) {
- [self raiseQueuePageUrl:urlString];
- }
- if ([self isTargetUrl: targetUrl
- destinationUrl: url]) {
- self.isQueuePassed = YES;
- NSString* queueitToken = [self extractQueueToken:url.absoluteString];
- [self.delegate notifyViewControllerQueuePassed:queueitToken];
- [self.host dismissViewControllerAnimated:YES completion:^{
- }];
- decisionHandler(WKNavigationActionPolicyCancel);
- return;
- }
- }
- if (navigationAction.navigationType == WKNavigationTypeLinkActivated && !isQueueUrl) {
- if (@available(iOS 10, *)){
- [[UIApplication sharedApplication] openURL:[request URL] options:@{} completionHandler:^(BOOL success){
-
- }];
- }
- else {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- [[UIApplication sharedApplication] openURL:[request URL]];
-#pragma GCC diagnostic pop
- }
-
- decisionHandler(WKNavigationActionPolicyCancel);
- return;
- }
- }
- }
- }
-
- decisionHandler(WKNavigationActionPolicyAllow);
-}
-
-- (NSString*)extractQueueToken:(NSString*) url {
- NSString* tokenKey = @"queueittoken=";
- if ([url containsString:tokenKey]) {
- NSString* token = [url substringFromIndex:NSMaxRange([url rangeOfString:tokenKey])];
- if([token containsString:@"&"]) {
- token = [token substringToIndex:NSMaxRange([token rangeOfString:@"&"]) - 1];
- }
- return token;
- }
- return nil;
-}
-
-- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
-}
-
-- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
- [self.spinner stopAnimating];
- if (![self.webView isLoading])
- {
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
- }
-
- // Check if user exitted through the default exit link and notify the engine
- [self.webView evaluateJavaScript:JAVASCRIPT_GET_BODY_CLASSES completionHandler:^(id result, NSError* error){
- if (error != nil) {
- NSLog(@"evaluateJavaScript error : %@", error.localizedDescription);
- }
- else {
- NSString* resultString = [NSString stringWithFormat:@"%@", result];
- NSArray *htmlBodyClasses = [resultString componentsSeparatedByString:@" "];
- BOOL isExitClassPresent = [htmlBodyClasses containsObject:@"exit"];
- if (isExitClassPresent) {
- [self.delegate notifyViewControllerUserExited];
- }
- }
- }];
-}
-
-- (void)raiseQueuePageUrl:(NSString *)urlString {
- [self.delegate notifyViewControllerPageUrlChanged:urlString];
-}
-
--(void)appWillResignActive:(NSNotification*)note
-{
-}
-
-@end
diff --git a/QueueITLib/QueueITWaitingRoomProvider.h b/QueueITLib/QueueITWaitingRoomProvider.h
deleted file mode 100644
index 2bd25b3..0000000
--- a/QueueITLib/QueueITWaitingRoomProvider.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#import "QueueITWaitingRoomView.h"
-#import "QueueTryPassResult.h"
-
-@protocol QueueITWaitingRoomProviderDelegate;
-
-@interface QueueITWaitingRoomProvider : NSObject
-
-typedef enum {
- NetworkUnavailable = -100,
- RequestAlreadyInProgress = 10
-} QueueITRuntimeError;
-#define QueueITRuntimeErrorArray @"Network connection is unavailable", @"Enqueue request is already in progress", nil
-
-@property (nonatomic, weak)id _Nullable delegate;
-
--(instancetype _Nonnull)initWithCustomerId:(NSString* _Nonnull)customerId
- eventOrAliasId:(NSString* _Nonnull)eventOrAliasId
- layoutName:(NSString* _Nullable)layoutName
- language:(NSString* _Nullable)language;
-
--(BOOL)TryPass: (NSError* _Nullable*_Nullable)error;
--(BOOL)TryPassWithEnqueueToken:(NSString* _Nullable)enqueueToken
- error:(NSError* _Nullable*_Nullable)error;
--(BOOL)TryPassWithEnqueueKey:(NSString* _Nullable)enqueueKey
- error:(NSError* _Nullable*_Nullable)error;
--(BOOL)IsRequestInProgress;
-@end
-
-@protocol QueueITWaitingRoomProviderDelegate
-
--(void)waitingRoomProvider:(nonnull QueueITWaitingRoomProvider*)provider notifyProviderSuccess:(QueueTryPassResult* _Nonnull) queuePassResult;
--(void)waitingRoomProvider:(nonnull QueueITWaitingRoomProvider*)provider notifyProviderFailure:(NSString* _Nullable)errorMessage
- errorCode:(long)errorCode;
-@end
diff --git a/QueueITLib/QueueITWaitingRoomProvider.m b/QueueITLib/QueueITWaitingRoomProvider.m
deleted file mode 100644
index 189639b..0000000
--- a/QueueITLib/QueueITWaitingRoomProvider.m
+++ /dev/null
@@ -1,207 +0,0 @@
-#import "QueueITWaitingRoomProvider.h"
-#import "IOSUtils.h"
-#import "QueueITApiClient.h"
-#import "QueueTryPassResult.h"
-#import "QueueITReachability.h"
-
-// TODO: Include all the method calls here
-@interface QueueITWaitingRoomProvider()
-@property (nonatomic) QueueITReachability *internetReachability;
-@property NSString* customerId;
-@property NSString* eventOrAliasId;
-@property NSString* layoutName;
-@property NSString* language;
-@property BOOL requestInProgress;
-@property int deltaSec;
-
-
-@end
-
-@implementation QueueITWaitingRoomProvider
-
-static int MAX_RETRY_SEC = 10;
-static int INITIAL_WAIT_RETRY_SEC = 1;
-
--(instancetype _Nonnull)initWithCustomerId:(NSString* _Nonnull)customerId
- eventOrAliasId:(NSString* _Nonnull)eventOrAliasId
- layoutName:(NSString* _Nullable)layoutName
- language:(NSString* _Nullable)language {
-
- if(self = [super init]) {
- self.customerId = customerId;
- self.eventOrAliasId = eventOrAliasId;
- self.layoutName = layoutName;
- self.language = language;
- self.deltaSec = INITIAL_WAIT_RETRY_SEC;
- self.internetReachability = [QueueITReachability reachabilityForInternetConnection];
- }
-
- return self;
-}
-
--(BOOL) TryPass: (NSError**)error {
- return [self tryEnqueue:nil enqueueKey:nil error:error];
-}
-
--(BOOL) TryPassWithEnqueueToken: (NSString*)enqueueToken error:(NSError *__autoreleasing *)error {
- return [self tryEnqueue:enqueueToken enqueueKey:nil error:error];
-}
-
--(BOOL) TryPassWithEnqueueKey: (NSString*)enqueueKey error:(NSError *__autoreleasing *)error {
- return [self tryEnqueue:nil enqueueKey:enqueueKey error:error];
-}
-
-
--(BOOL)tryEnqueue:(NSString*)enqueueToken
- enqueueKey:(NSString*)enqueueKey
- error:(NSError**)error
-{
- if(![self checkConnection:error]) {
- return NO;
- }
-
- if(self.requestInProgress) {
- *error = [NSError errorWithDomain:@"QueueITRuntimeException" code:RequestAlreadyInProgress userInfo:nil];
- return NO;
- }
-
- [IOSUtils getUserAgent:^(NSString * userAgent) {
- [self tryEnqueueWithUserAgent:userAgent enqueueToken:enqueueToken enqueueKey:enqueueKey error:error];
- }];
-
- return YES;
-}
-
--(void)tryEnqueueWithUserAgent:(NSString*)secretAgent
- enqueueToken:(NSString*)enqueueToken
- enqueueKey:(NSString*)enqueueKey
- error:(NSError**)error
-{
- NSString* userId = [IOSUtils getUserId];
- NSString* userAgent = [NSString stringWithFormat:@"%@;%@", secretAgent, [IOSUtils getLibraryVersion]];
- NSString* sdkVersion = [IOSUtils getSdkVersion];
-
- QueueITApiClient* apiClient = [QueueITApiClient getInstance];
- [apiClient enqueue:self.customerId
- eventOrAliasId:self.eventOrAliasId
- userId:userId
- userAgent:userAgent
- sdkVersion:sdkVersion
- layoutName:self.layoutName
- language:self.language
- enqueueToken:enqueueToken
- enqueueKey:enqueueKey
- success:^(QueueStatus *queueStatus)
-{
- if (queueStatus == NULL) {
- [self enqueueRetryMonitor:enqueueToken enqueueKey:enqueueKey error:error];
- return;
- }
-
- [self handleAppEnqueueResponse: queueStatus.queueId
- queueURL:queueStatus.queueUrlString
- eventTargetURL:queueStatus.eventTargetUrl
- queueItToken:queueStatus.queueitToken];
-
- self.requestInProgress = NO;
- }
- failure:^(NSError *error, NSString* errorMessage)
- {
- if (error.code >= 400 && error.code < 500)
- {
- [self.delegate waitingRoomProvider:self notifyProviderFailure:errorMessage errorCode:error.code];
- }
- else
- {
- [self enqueueRetryMonitor:enqueueToken enqueueKey:enqueueKey error:&error];
- }
- }];
-}
-
--(void)handleAppEnqueueResponse:(NSString*) queueId
- queueURL:(NSString*) queueURL
- eventTargetURL:(NSString*) targetURL
- queueItToken:(NSString*) token {
-
- bool isPassedThrough = ![self isNullOrEmpty:token];
-
- NSString* redirectType = [self getRedirectTypeFromToken:token];
-
- QueueTryPassResult* queueTryPassResult = [[QueueTryPassResult alloc]
- initWithQueueUrl:queueURL
- targetUrl:targetURL
- redirectType:redirectType
- isPassedThrough:isPassedThrough
- queueToken:token];
-
- [self.delegate waitingRoomProvider:self notifyProviderSuccess:queueTryPassResult];
-}
-
--(void)enqueueRetryMonitor:(NSString*)enqueueToken
- enqueueKey:(NSString*)enqueueKey
- error:(NSError**)error
-{
- if (self.deltaSec < MAX_RETRY_SEC)
- {
- [self tryEnqueue:enqueueToken enqueueKey:enqueueKey error:error];
-
- [NSThread sleepForTimeInterval:self.deltaSec];
- self.deltaSec = self.deltaSec * 2;
- }
- else
- {
- self.deltaSec = INITIAL_WAIT_RETRY_SEC;
- self.requestInProgress = NO;
- [self.delegate waitingRoomProvider:self notifyProviderFailure:@"Error! Queue is unavailable." errorCode:3];
- }
-}
-
--(BOOL)checkConnection:(NSError **)error
-{
- int count = 0;
- while (count < 5)
- {
- NetworkStatus netStatus = [self.internetReachability currentReachabilityStatus];
- if (netStatus == NotReachable)
- {
- [NSThread sleepForTimeInterval:1.0f];
- count++;
- }
- else
- {
- return YES;
- }
- }
- *error = [NSError errorWithDomain:@"QueueITRuntimeException" code:NetworkUnavailable userInfo:nil];
- return NO;
-}
-
--(BOOL)IsRequestInProgress {
- return self.requestInProgress;
-}
-
--(BOOL)isNullOrEmpty:(NSString*)queueToken {
- bool isNull = queueToken == nil || queueToken == (id)[NSNull null];
- bool isEmpty = isNull || [queueToken length] == 0;
-
- return isNull && isEmpty;
-}
-
--(NSString*) getRedirectTypeFromToken: (NSString*) queueToken {
-
- if([self isNullOrEmpty:queueToken])
- {
- return @"queue";
- }
-
- NSString *searchedString = queueToken;
- NSRange searchedRange = NSMakeRange(0, [searchedString length]);
- NSString *pattern = @"\\~rt_(.*?)\\~";
- NSError *error = nil;
-
- NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
- NSTextCheckingResult *match = [regex firstMatchInString:searchedString options:0 range: searchedRange];
- return [searchedString substringWithRange:[match rangeAtIndex:1]];
-}
-
-@end
diff --git a/QueueITLib/QueueITWaitingRoomView.h b/QueueITLib/QueueITWaitingRoomView.h
deleted file mode 100644
index ca4af3c..0000000
--- a/QueueITLib/QueueITWaitingRoomView.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#import "QueueITWKViewController.h"
-#import "QueueDisabledInfo.h"
-#import "QueuePassedInfo.h"
-
-@protocol QueueITWaitingRoomViewDelegate;
-
-@interface QueueITWaitingRoomView : NSObject
-
-@property (nonatomic, weak)id _Nullable delegate;
-
--(instancetype _Nonnull)initWithHost:(UIViewController* _Nonnull)host
- customerId: (NSString* _Nonnull)customerId
- eventId: (NSString* _Nonnull)eventId;
-
--(void)show:(NSString* _Nonnull)queueUrl targetUrl:(NSString* _Nonnull)targetUrl;
--(void)setViewDelay:(int)delayInterval;
--(void)close:(void (^ __nullable)(void))onComplete;
-
-@end
-
-@protocol QueueITWaitingRoomViewDelegate
--(void) notifyViewUserExited:(nonnull QueueITWaitingRoomView*)view;
--(void) notifyViewUserClosed:(nonnull QueueITWaitingRoomView*)view;
--(void) notifyViewSessionRestart:(nonnull QueueITWaitingRoomView*)view;
--(void) waitingRoomView:(nonnull QueueITWaitingRoomView*)view notifyViewPassedQueue:(QueuePassedInfo* _Nullable)queuePassedInfo;
--(void) notifyViewQueueDidAppear:(nonnull QueueITWaitingRoomView*)view;
--(void) notifyViewQueueWillOpen:(nonnull QueueITWaitingRoomView*)view;
--(void) waitingRoomView:(nonnull QueueITWaitingRoomView*)view notifyViewUpdatePageUrl:(NSString* _Nullable) urlString;
-@end
diff --git a/QueueITLib/QueueITWaitingRoomView.m b/QueueITLib/QueueITWaitingRoomView.m
deleted file mode 100644
index 329095b..0000000
--- a/QueueITLib/QueueITWaitingRoomView.m
+++ /dev/null
@@ -1,100 +0,0 @@
-#import
-#import "QueueITWaitingRoomView.h"
-#import "QueueITWKViewController.h"
-
-@interface QueueITWaitingRoomView ()
-@property (nonatomic, weak) UIViewController* host;
-@property (nonatomic, weak) QueueITWKViewController* currentWebView;
-@property NSString* customerId;
-@property NSString* eventId;
-@property int delayInterval;
-@end
-
-@implementation QueueITWaitingRoomView
-
--(instancetype _Nonnull)initWithHost:(UIViewController *)host
- customerId: (NSString* _Nonnull) customerId
- eventId: (NSString * _Nonnull)eventId
-
-{
- if(self = [super init]) {
- self.host = host;
- self.customerId = customerId;
- self.eventId = eventId;
- }
-
- return self;
-}
-
--(void) show:(NSString* _Nonnull)queueUrl targetUrl:(NSString* _Nonnull)targetUrl
-{
- [self raiseQueueViewWillOpen];
-
- QueueITWKViewController *queueWKVC = [[QueueITWKViewController alloc] initWithHost:self.host
- queueUrl:queueUrl
- eventTargetUrl:targetUrl
- customerId:self.customerId
- eventId:self.eventId];
-
- queueWKVC.delegate = self;
-
- if (@available(iOS 13.0, *)) {
- [queueWKVC setModalPresentationStyle: UIModalPresentationFullScreen];
- }
- if (self.delayInterval > 0) {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.delayInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- [self.host presentViewController:queueWKVC animated:YES completion:^{
- self.currentWebView = queueWKVC;
- [self.delegate notifyViewQueueDidAppear:self ];
- }];
- });
- } else {
- dispatch_async(dispatch_get_main_queue(), ^{
- [self.host presentViewController:queueWKVC animated:YES completion:^{
- self.currentWebView = queueWKVC;
- [self.delegate notifyViewQueueDidAppear:self ];
- }];
- });
- }
-}
-
--(void)close:(void (^ __nullable)(void))onComplete
-{
- if(self.currentWebView!=nil){
- dispatch_async(dispatch_get_main_queue(), ^{
- [self.currentWebView close: onComplete];
- });
- }
-}
-
-- (void)raiseQueueViewWillOpen {
- [self.delegate notifyViewQueueWillOpen:self];
-}
-
--(void)setViewDelay:(int)delayInterval {
- self.delayInterval = delayInterval;
-}
-
--(void) notifyViewControllerUserExited {
- [self.delegate notifyViewUserExited:self];
-}
-
--(void) notifyViewControllerClosed {
- [self.delegate notifyViewUserClosed:self];
-}
-
--(void) notifyViewControllerSessionRestart {
- [self.delegate notifyViewSessionRestart:self];
-}
-
--(void) notifyViewControllerQueuePassed:(NSString *)queueToken {
- QueuePassedInfo* queuePassedInfo = [[QueuePassedInfo alloc] initWithQueueitToken:queueToken];
- [self.delegate waitingRoomView:self notifyViewPassedQueue:queuePassedInfo];
-}
-
--(void)notifyViewControllerPageUrlChanged:(NSString* _Nullable) urlString {
- [self.delegate waitingRoomView:self notifyViewUpdatePageUrl:urlString];
-}
-
-@end
-
diff --git a/QueueITLib/QueuePassedInfo.h b/QueueITLib/QueuePassedInfo.h
deleted file mode 100644
index 36fcc6f..0000000
--- a/QueueITLib/QueuePassedInfo.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#import
-
-@interface QueuePassedInfo : NSObject
-
-@property (nonatomic, strong) NSString* _Nullable queueitToken;
-
--(instancetype _Nonnull )initWithQueueitToken:(NSString* _Nullable) queueitToken;
-
-@end
diff --git a/QueueITLib/QueuePassedInfo.m b/QueueITLib/QueuePassedInfo.m
deleted file mode 100644
index 66def51..0000000
--- a/QueueITLib/QueuePassedInfo.m
+++ /dev/null
@@ -1,14 +0,0 @@
-#import "QueuePassedInfo.h"
-
-@implementation QueuePassedInfo
-
--(instancetype)initWithQueueitToken:(NSString *)queueitToken
-{
- if(self = [super init]) {
- self.queueitToken = queueitToken;
- }
-
- return self;
-}
-
-@end
diff --git a/QueueITLib/QueueStatus.h b/QueueITLib/QueueStatus.h
deleted file mode 100644
index e3713d6..0000000
--- a/QueueITLib/QueueStatus.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#import
-
-@interface QueueStatus : NSObject
-
-@property (nonatomic, strong) NSString* queueId;
-@property (nonatomic, strong)NSString* queueUrlString;
-@property (nonatomic, strong) NSString* eventTargetUrl;
-@property (nonatomic, strong) NSString* queueitToken;
-
--(instancetype)initWithDictionary:(NSDictionary *)dictionary;
-
-@end
diff --git a/QueueITLib/QueueStatus.m b/QueueITLib/QueueStatus.m
deleted file mode 100644
index b53b58f..0000000
--- a/QueueITLib/QueueStatus.m
+++ /dev/null
@@ -1,59 +0,0 @@
-#import "QueueStatus.h"
-
-NSString * const KEY_QUEUE_ID = @"QueueId";
-NSString * const KEY_QUEUE_URL = @"QueueUrl";
-NSString * const KEY_EVENT_TARGET_URL = @"EventTargetUrl";
-NSString * const KEY_QUEUEIT_TOKEN = @"QueueitToken";
-
-@implementation QueueStatus
-
--(instancetype)init:(NSString *)queueId
- queueUrl:(NSString *)queueUrlString
- eventTargetUrl:(NSString *)eventTargetUrl
- queueitToken:(NSString *)queueitToken
-{
- if(self = [super init]) {
- self.queueId = queueId;
- self.queueUrlString = queueUrlString;
- self.eventTargetUrl = eventTargetUrl;
- self.queueitToken = queueitToken;
- }
-
- return self;
-}
-
-- (instancetype)initWithDictionary:(NSDictionary *)dictionary
-{
- NSString *queueId;
- NSString *queueUrlString;
- NSString *eventTargetUrl;
- NSString *queueitToken;
- id value;
-
-
- value = dictionary[KEY_QUEUE_ID];
- if ([value isKindOfClass:[NSString class]]) {
- queueId = (NSString*)value;
- }
-
- value = dictionary[KEY_QUEUE_URL];
- if ([value isKindOfClass:[NSString class]]) {
- queueUrlString = (NSString*)value;
- }
-
- value = dictionary[KEY_EVENT_TARGET_URL];
- if ([value isKindOfClass:[NSString class]]) {
- eventTargetUrl = (NSString*)value;
- }
-
- value = dictionary[KEY_QUEUEIT_TOKEN];
- if ([value isKindOfClass:[NSString class]]) {
- queueitToken = (NSString*)value;
- }
-
- return [self init:queueId
- queueUrl:queueUrlString
- eventTargetUrl:eventTargetUrl
- queueitToken:queueitToken];
-}
-@end
diff --git a/QueueITLib/QueueTryPassResult.h b/QueueITLib/QueueTryPassResult.h
deleted file mode 100644
index 8abef8f..0000000
--- a/QueueITLib/QueueTryPassResult.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#import
-
-@interface QueueTryPassResult : NSObject
-
-@property (nonatomic, strong) NSString* _Nullable queueUrl;
-@property (nonatomic, strong) NSString* _Nullable targetUrl;
-@property (nonatomic, strong) NSString* _Nonnull redirectType;
-@property (nonatomic) BOOL isPassedThrough;
-@property (nonatomic) NSString* _Nullable queueToken;
-
-
--(instancetype _Nonnull )
- initWithQueueUrl: (NSString* _Nullable) queueUrl
- targetUrl:(NSString* _Nullable)targetUrl
- redirectType: (NSString* _Nonnull) redirectType
- isPassedThrough: (BOOL) isPassedThrough
- queueToken: (NSString* _Nullable) queueToken;
-
-@end
diff --git a/QueueITLib/QueueTryPassResult.m b/QueueITLib/QueueTryPassResult.m
deleted file mode 100644
index 76784c3..0000000
--- a/QueueITLib/QueueTryPassResult.m
+++ /dev/null
@@ -1,24 +0,0 @@
-#import "QueueTryPassResult.h"
-
-
-@implementation QueueTryPassResult
-
--(instancetype _Nonnull )
- initWithQueueUrl: (NSString* _Nullable) queueUrl
- targetUrl:(NSString* _Nullable)targetUrl
- redirectType: (NSString* _Nonnull) redirectType
- isPassedThrough: (BOOL) isPassedThrough
- queueToken: (NSString* _Nullable) queueToken
-{
- if(self = [super init]) {
- self.queueUrl = queueUrl;
- self.targetUrl = targetUrl;
- self.redirectType = redirectType;
- self.isPassedThrough = isPassedThrough;
- self.queueToken = queueToken;
- }
-
- return self;
-}
-
-@end
diff --git a/README.md b/README.md
index 4c870ec..ab38737 100644
--- a/README.md
+++ b/README.md
@@ -168,7 +168,7 @@ When the user clicks back, the same check needs to be done.
### Getting the status of a waiting room
-If you're using version ```3.1.14``` or newer, it's possible to get the state of the waiting room using the new ```QueueITWaitingRoomProvider``` with one of the following methods:
+If you're using version ```3.1.14``` or newer, it's possible to get the state of the waiting room using the new ```WaitingRoomProvider``` with one of the following methods:
* ```TryPass```
* ```TryPassWithEnqueueToken```
@@ -176,21 +176,21 @@ If you're using version ```3.1.14``` or newer, it's possible to get the state of
Calling one of the above methods will trigger either the ```notifyProviderSuccess``` callback on success, or ```notifyProviderFailure``` callback on failure.
-When using the ```notifyProviderQueueITUnavailable``` from the ```ProviderSuccessDelegate``` it'll provide with a ```QueueTryPassResult``` depending on the ```isPassThrough``` result:
+When using the ```notifyProviderQueueITUnavailable``` from the ```ProviderSuccessDelegate``` it'll provide with a ```TryPassResult``` depending on the ```isPassThrough``` result:
-* ```true``` means that the ```QueueItToken``` is *not* empty, and more information is available in the ```QueueTryPassResult```
-* ```false``` means that the waiting room is *active*. You can show the visitor the waiting room by calling ```show``` from the ```QueueITWaitingRoomView```, by providing a ```queueUrl``` and ```targetUrl``` *([Read more about it here](#showing-the-queue-page-to-visitors))*
+* ```true``` means that the ```QueueItToken``` is *not* empty, and more information is available in the ```TryPassResult```
+* ```false``` means that the waiting room is *active*. You can show the visitor the waiting room by calling ```show``` from the ```WaitingRoomView```, by providing a ```queueUrl``` and ```targetUrl``` *([Read more about it here](#showing-the-queue-page-to-visitors))*
### Showing the queue page to visitors
-If you're using version ```3.1.14``` or newer, the ```QueueITWaitingRoomView``` class is available.
+If you're using version ```3.1.14``` or newer, the ```WaitingRoomView``` class is available.
-When the waiting room is queueing visitors, each visitor has to visit it once. Using the ```show``` method you can do this, you have to provide the ```queueUrl```, and the ```targetUrl``` which is returned by the ```notifyProviderSuccess``` from ```QueueITWaitingRoomProvider``` class, given the waiting room is *active* ([Read more about it here](#getting-the-status-of-a-waiting-room))
+When the waiting room is queueing visitors, each visitor has to visit it once. Using the ```show``` method you can do this, you have to provide the ```queueUrl```, and the ```targetUrl``` which is returned by the ```notifyProviderSuccess``` from ```WaitingRoomProvider``` class, given the waiting room is *active* ([Read more about it here](#getting-the-status-of-a-waiting-room))
#### Sample code showing the queue page:
``` objc
--(void)notifyProviderSuccess:(QueueTryPassResult* _Nonnull) queuePassResult {
+-(void)notifyProviderSuccess:(TryPassResult* _Nonnull) queuePassResult {
[self.waitingRoomView show:queuePassResult.queueUrl targetUrl:queuePassResult.targetUrl];
}
```
diff --git a/Sources/QueueITLib/ApiClient.swift b/Sources/QueueITLib/ApiClient.swift
new file mode 100644
index 0000000..3676bb0
--- /dev/null
+++ b/Sources/QueueITLib/ApiClient.swift
@@ -0,0 +1,122 @@
+import Foundation
+
+typealias QueueServiceSuccess = (Data) -> Void
+typealias QueueServiceFailure = (Error, String) -> Void
+
+class ApiClient {
+ static let API_ROOT = "https://%@.queue-it.net/api/mobileapp/queue"
+ static let TESTING_API_ROOT = "https://%@.test.queue-it.net/api/mobileapp/queue"
+ private static var testingIsEnabled = false
+ private static var sharedInstance: ApiClient?
+
+ static func getInstance() -> ApiClient {
+ if sharedInstance == nil {
+ sharedInstance = Connection()
+ }
+ return sharedInstance!
+ }
+
+ static func setTesting(_ enabled: Bool) {
+ testingIsEnabled = enabled
+ }
+
+ func enqueue(
+ customerId: String,
+ eventOrAliasId: String,
+ userId: String,
+ userAgent: String,
+ sdkVersion: String,
+ layoutName: String?,
+ language: String?,
+ enqueueToken: String?,
+ enqueueKey: String?,
+ success: @escaping (Status?) -> Void,
+ failure: @escaping QueueServiceFailure
+ ) {
+ var bodyDict: [String: Any] = [
+ "userId": userId,
+ "userAgent": userAgent,
+ "sdkVersion": sdkVersion,
+ ]
+
+ if let layoutName = layoutName {
+ bodyDict["layoutName"] = layoutName
+ }
+
+ if let language = language {
+ bodyDict["language"] = language
+ }
+
+ if let enqueueToken = enqueueToken {
+ bodyDict["enqueueToken"] = enqueueToken
+ }
+
+ if let enqueueKey = enqueueKey {
+ bodyDict["enqueueKey"] = enqueueKey
+ }
+
+ let apiRoot = ApiClient.testingIsEnabled ? ApiClient.TESTING_API_ROOT : ApiClient.API_ROOT
+ var urlAsString = String(format: apiRoot, customerId)
+ urlAsString += "/\(customerId)"
+ urlAsString += "/\(eventOrAliasId)"
+ urlAsString += "/enqueue"
+
+ submitPOSTPath(
+ path: urlAsString,
+ body: bodyDict,
+ success: { data in
+ do {
+ if let userDict = try JSONSerialization.jsonObject(
+ with: data,
+ options: []
+ ) as? [String: Any] {
+ let Status = Status(dictionary: userDict)
+ success(Status)
+ } else {
+ success(nil)
+ }
+ } catch {
+ success(nil)
+ }
+ },
+ failure: failure
+ )
+ }
+
+ func submitPOSTPath(
+ path: String,
+ body bodyDict: [String: Any],
+ success: @escaping QueueServiceSuccess,
+ failure: @escaping QueueServiceFailure
+ ) {
+ guard let url = URL(string: path) else {
+ let error = NSError(
+ domain: "ApiClient",
+ code: -1,
+ userInfo: [NSLocalizedDescriptionKey: "Invalid URL"]
+ )
+ failure(error, "Invalid URL")
+ return
+ }
+
+ submitRequest(
+ with: url,
+ method: "POST",
+ body: bodyDict,
+ expectedStatus: 200,
+ success: success,
+ failure: failure
+ )
+ }
+
+ func submitRequest(
+ with _: URL,
+ method _: String,
+ body _: [String: Any],
+ expectedStatus _: Int,
+ success _: @escaping QueueServiceSuccess,
+ failure _: @escaping QueueServiceFailure
+ ) {
+ return
+ }
+}
diff --git a/Sources/QueueITLib/Connection.swift b/Sources/QueueITLib/Connection.swift
new file mode 100644
index 0000000..0c6f9b6
--- /dev/null
+++ b/Sources/QueueITLib/Connection.swift
@@ -0,0 +1,42 @@
+import Foundation
+
+final class Connection: ApiClient {
+ private var connectionRequest: ConnectionRequest?
+
+ override func submitRequest(
+ with url: URL,
+ method httpMethod: String,
+ body bodyDict: [String: Any],
+ expectedStatus: Int,
+ success: @escaping QueueServiceSuccess,
+ failure: @escaping QueueServiceFailure
+ ) {
+ var request = URLRequest(url: url)
+ request.httpMethod = httpMethod
+
+ do {
+ let jsonData = try JSONSerialization.data(withJSONObject: bodyDict, options: [])
+ request.httpBody = jsonData
+ } catch {
+ failure(error, "Failed to serialize request body.")
+ return
+ }
+
+ request.addValue("application/json", forHTTPHeaderField: "Accept")
+ request.addValue("application/json", forHTTPHeaderField: "Content-Type")
+
+ connectionRequest = ConnectionRequest(
+ request: request,
+ expectedStatusCode: expectedStatus,
+ success: success,
+ failure: failure,
+ delegate: self
+ )
+ }
+}
+
+extension Connection: ConnectionRequestDelegate {
+ func requestDidComplete(_: ConnectionRequest) {
+ // Handle the completion of the request if needed
+ }
+}
diff --git a/Sources/QueueITLib/ConnectionRequest.swift b/Sources/QueueITLib/ConnectionRequest.swift
new file mode 100644
index 0000000..08c2128
--- /dev/null
+++ b/Sources/QueueITLib/ConnectionRequest.swift
@@ -0,0 +1,97 @@
+import Foundation
+
+protocol ConnectionRequestDelegate: AnyObject {
+ func requestDidComplete(_ request: ConnectionRequest)
+}
+
+final class ConnectionRequest {
+ let uniqueIdentifier: String
+
+ private var request: URLRequest
+ private var response: URLResponse?
+ private var data: Data
+ private var successCallback: QueueServiceSuccess
+ private var failureCallback: QueueServiceFailure
+ private weak var delegate: ConnectionRequestDelegate?
+ private var expectedStatusCode: Int
+ private var actualStatusCode: Int = NSNotFound
+
+ init(
+ request: URLRequest,
+ expectedStatusCode: Int,
+ success: @escaping QueueServiceSuccess,
+ failure: @escaping QueueServiceFailure,
+ delegate: ConnectionRequestDelegate?
+ ) {
+ self.request = request
+ self.expectedStatusCode = expectedStatusCode
+ successCallback = success
+ failureCallback = failure
+ self.delegate = delegate
+ uniqueIdentifier = UUID().uuidString
+ data = Data()
+ initiateRequest()
+ }
+}
+
+private extension ConnectionRequest {
+ func initiateRequest() {
+ response = nil
+ data = Data()
+
+ let task = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
+ guard let self else { return }
+
+ if let error = error {
+ DispatchQueue.main.async {
+ self.failureCallback(error, "Unexpected failure occurred.")
+ self.delegate?.requestDidComplete(self)
+ }
+ return
+ }
+
+ if let response = response as? HTTPURLResponse {
+ self.actualStatusCode = response.statusCode
+ self.response = response
+ }
+
+ if let receivedData = data {
+ self.data.append(receivedData)
+ }
+
+ DispatchQueue.main.async {
+ self.handleResponse()
+ }
+ }
+ task.resume()
+ }
+
+ func handleResponse() {
+ if hasExpectedStatusCode() {
+ successCallback(data)
+ } else {
+ var message = "Unexpected response code: \(actualStatusCode)"
+ if actualStatusCode >= 400, actualStatusCode < 500 {
+ if let decodedMessage = String(data: data, encoding: .ascii) {
+ message = decodedMessage
+ }
+ } else if let json = try? JSONSerialization.jsonObject(with: data, options: []),
+ let jsonDict = json as? [String: Any],
+ let errorMessage = jsonDict["error"] as? String
+ {
+ message = errorMessage
+ }
+
+ let error = NSError(domain: "QueueService",
+ code: actualStatusCode,
+ userInfo: [NSLocalizedDescriptionKey: message])
+ failureCallback(error, message)
+ }
+
+ delegate?.requestDidComplete(self)
+ }
+
+ func hasExpectedStatusCode() -> Bool {
+ return actualStatusCode == expectedStatusCode
+ }
+}
diff --git a/Sources/QueueITLib/Constants.swift b/Sources/QueueITLib/Constants.swift
new file mode 100644
index 0000000..7f9e5b8
--- /dev/null
+++ b/Sources/QueueITLib/Constants.swift
@@ -0,0 +1,5 @@
+enum Constants {
+ static let queueCloseUrl = "queueit://close"
+ static let queueRestartSessionUrl = "queueit://restartSession"
+ static let sdkVersion = "iOS-3.4.4"
+}
diff --git a/Sources/QueueITLib/QueueITEngine.swift b/Sources/QueueITLib/QueueITEngine.swift
new file mode 100644
index 0000000..884e59d
--- /dev/null
+++ b/Sources/QueueITLib/QueueITEngine.swift
@@ -0,0 +1,152 @@
+import UIKit
+
+public protocol QueuePassedDelegate: AnyObject {
+ func notifyYourTurn(queuePassedInfo: QueuePassedInfo?)
+}
+
+public protocol QueueViewWillOpenDelegate: AnyObject {
+ func notifyQueueViewWillOpen()
+}
+
+public protocol QueueDisabledDelegate: AnyObject {
+ func notifyQueueDisabled(queueDisabledInfo: QueueDisabledInfo?)
+}
+
+public protocol QueueUnavailableDelegate: AnyObject {
+ func notifyQueueITUnavailable(errorMessage: String)
+}
+
+public protocol QueueErrorDelegate: AnyObject {
+ func notifyQueueError(errorMessage: String, errorCode: Int)
+}
+
+public protocol QueueViewClosedDelegate: AnyObject {
+ func notifyViewClosed()
+}
+
+public protocol QueueUserExitedDelegate: AnyObject {
+ func notifyUserExited()
+}
+
+public protocol QueueSessionRestartDelegate: AnyObject {
+ func notifySessionRestart()
+}
+
+public protocol QueueUrlChangedDelegate: AnyObject {
+ func notifyQueueUrlChanged(url: String)
+}
+
+public protocol QueueViewDidAppearDelegate: AnyObject {
+ func notifyQueueViewDidAppear()
+}
+
+public final class QueueItEngine {
+ public weak var queuePassedDelegate: QueuePassedDelegate?
+ public weak var queueViewWillOpenDelegate: QueueViewWillOpenDelegate?
+ public weak var queueDisabledDelegate: QueueDisabledDelegate?
+ public weak var queueUnavailableDelegate: QueueUnavailableDelegate?
+ public weak var queueErrorDelegate: QueueErrorDelegate?
+ public weak var queueViewClosedDelegate: QueueViewClosedDelegate?
+ public weak var queueUserExitedDelegate: QueueUserExitedDelegate?
+ public weak var queueSessionRestartDelegate: QueueSessionRestartDelegate?
+ public weak var queueUrlChangedDelegate: QueueUrlChangedDelegate?
+ public weak var queueViewDidAppearDelegate: QueueViewDidAppearDelegate?
+
+ public weak var host: UIViewController?
+ private var waitingRoomProvider: WaitingRoomProvider
+ private var waitingRoomView: WaitingRoomView
+
+ public init(host: UIViewController, customerId: String, eventOrAliasId: String, layoutName: String?, language: String?) {
+ self.host = host
+
+ waitingRoomProvider = WaitingRoomProvider(
+ customerId: customerId,
+ eventOrAliasId: eventOrAliasId,
+ layoutName: layoutName,
+ language: language
+ )
+ waitingRoomView = WaitingRoomView(host: host, eventId: eventOrAliasId)
+ waitingRoomView.delegate = self
+ waitingRoomProvider.delegate = self
+ }
+
+ public func setViewDelay(_ delayInterval: Int) {
+ waitingRoomView.setViewDelay(delayInterval)
+ }
+
+ public func isRequestInProgress() -> Bool {
+ return waitingRoomProvider.isRequestInProgress()
+ }
+
+ public func run(withEnqueueKey enqueueKey: String) throws {
+ try waitingRoomProvider.tryPassWithEnqueueKey(enqueueKey)
+ }
+
+ public func run(withEnqueueToken enqueueToken: String) throws {
+ try waitingRoomProvider.tryPassWithEnqueueToken(enqueueToken)
+ }
+
+ public func run() throws {
+ try waitingRoomProvider.tryPass()
+ }
+
+ public func showQueue(queueUrl: String, targetUrl: String) {
+ waitingRoomView.show(queueUrl: queueUrl, targetUrl: targetUrl)
+ }
+}
+
+extension QueueItEngine: WaitingRoomViewDelegate {
+ func notifyViewUserExited() {
+ queueUserExitedDelegate?.notifyUserExited()
+ }
+
+ func notifyViewUserClosed() {
+ queueViewClosedDelegate?.notifyViewClosed()
+ }
+
+ func notifyViewSessionRestart() {
+ queueSessionRestartDelegate?.notifySessionRestart()
+ }
+
+ func notifyQueuePassed(info: QueuePassedInfo?) {
+ queuePassedDelegate?.notifyYourTurn(queuePassedInfo: info)
+ }
+
+ func notifyViewQueueDidAppear() {
+ queueViewDidAppearDelegate?.notifyQueueViewDidAppear()
+ }
+
+ func notifyViewQueueWillOpen() {
+ queueViewWillOpenDelegate?.notifyQueueViewWillOpen()
+ }
+
+ func notifyViewUpdatePageUrl(urlString: String?) {
+ // TODO: fix optional parameter
+ queueUrlChangedDelegate?.notifyQueueUrlChanged(url: urlString ?? "")
+ }
+}
+
+extension QueueItEngine: WaitingRoomProviderDelegate {
+ func notifyProviderSuccess(queuePassResult: TryPassResult) {
+ switch queuePassResult.redirectType {
+ case "safetynet":
+ let queuePassedInfo = QueuePassedInfo(queueitToken: queuePassResult.queueToken)
+ queuePassedDelegate?.notifyYourTurn(queuePassedInfo: queuePassedInfo)
+ case "disabled", "idle", "afterevent":
+ let queueDisabledInfo = QueueDisabledInfo(queueitToken: queuePassResult.queueToken)
+ queueDisabledDelegate?.notifyQueueDisabled(queueDisabledInfo: queueDisabledInfo)
+ default:
+ // TODO: fix optional parameter
+ showQueue(queueUrl: queuePassResult.queueUrl ?? "", targetUrl: queuePassResult.targetUrl ?? "")
+ }
+ }
+
+ func notifyProviderFailure(errorMessage: String?, errorCode: Int) {
+ // TODO: fix optional parameter
+ let errorMessage = errorMessage ?? ""
+ if errorCode == 3 {
+ queueUnavailableDelegate?.notifyQueueITUnavailable(errorMessage: errorMessage)
+ }
+ queueErrorDelegate?.notifyQueueError(errorMessage: errorMessage, errorCode: errorCode)
+ }
+}
diff --git a/Sources/QueueITLib/QueueInfo.swift b/Sources/QueueITLib/QueueInfo.swift
new file mode 100644
index 0000000..5411c03
--- /dev/null
+++ b/Sources/QueueITLib/QueueInfo.swift
@@ -0,0 +1,17 @@
+import Foundation
+
+public struct QueuePassedInfo {
+ public var queueitToken: String?
+
+ public init(queueitToken: String?) {
+ self.queueitToken = queueitToken
+ }
+}
+
+public struct QueueDisabledInfo {
+ public var queueitToken: String?
+
+ public init(queueitToken: String?) {
+ self.queueitToken = queueitToken
+ }
+}
diff --git a/Sources/QueueITLib/Reachability.swift b/Sources/QueueITLib/Reachability.swift
new file mode 100644
index 0000000..79236ed
--- /dev/null
+++ b/Sources/QueueITLib/Reachability.swift
@@ -0,0 +1,118 @@
+import Foundation
+import Network
+import SystemConfiguration
+
+
+extension Notification.Name {
+ static let reachabilityChanged = Notification.Name("kNetworkReachabilityChangedNotification")
+}
+
+final class Reachability {
+ private var monitor: NWPathMonitor?
+ private var isMonitoringLocalWiFi: Bool = false
+ private var queue = DispatchQueue.global(qos: .background)
+
+ private init() {}
+
+ static func reachabilityWithHostName(_ hostName: String) -> Reachability {
+ let reachability = Reachability()
+ reachability.startMonitoringHost(hostName: hostName)
+ return reachability
+ }
+
+ static func reachabilityWithAddress(_ hostAddress: sockaddr_in) -> Reachability {
+ let reachability = Reachability()
+ reachability.startMonitoringIP(address: hostAddress)
+ return reachability
+ }
+
+ static func reachabilityForInternetConnection() -> Reachability {
+ let reachability = Reachability()
+ reachability.startMonitoringInternet()
+ return reachability
+ }
+
+ static func reachabilityForLocalWiFi() -> Reachability {
+ let reachability = Reachability()
+ reachability.startMonitoringWiFi()
+ return reachability
+ }
+
+ func startNotifier() -> Bool {
+ guard monitor == nil else { return true }
+ monitor = NWPathMonitor()
+ monitor?.pathUpdateHandler = { [weak self] _ in
+ NotificationCenter.default.post(name: .reachabilityChanged, object: nil)
+ }
+ monitor?.start(queue: queue)
+ return true
+ }
+
+ func stopNotifier() {
+ monitor?.cancel()
+ monitor = nil
+ }
+
+ func currentReachabilityStatus() -> NetworkStatus {
+ guard let monitor = monitor else { return .notReachable }
+ let path = monitor.currentPath
+ if path.status == .unsatisfied {
+ return .notReachable
+ }
+ if path.usesInterfaceType(.wifi) {
+ return .reachableViaWiFi
+ }
+ if path.usesInterfaceType(.cellular) {
+ return .reachableViaWWAN
+ }
+ return .notReachable
+ }
+
+ func connectionRequired() -> Bool {
+ guard let monitor = monitor else { return false }
+ return monitor.currentPath.status != .satisfied
+ }
+}
+
+extension Reachability {
+ enum NetworkStatus: Int {
+ case notReachable = 0
+ case reachableViaWiFi
+ case reachableViaWWAN
+ }
+}
+
+private extension Reachability {
+ func startMonitoringHost(hostName _: String) {
+ monitor = NWPathMonitor(requiredInterfaceType: .other)
+ monitor?.pathUpdateHandler = { _ in
+ NotificationCenter.default.post(name: .reachabilityChanged, object: nil)
+ }
+ monitor?.start(queue: queue)
+ }
+
+ func startMonitoringIP(address _: sockaddr_in) {
+ monitor = NWPathMonitor()
+ monitor?.pathUpdateHandler = { _ in
+ NotificationCenter.default.post(name: .reachabilityChanged, object: nil)
+ }
+ monitor?.start(queue: queue)
+ }
+
+ func startMonitoringInternet() {
+ monitor = NWPathMonitor()
+ monitor?.pathUpdateHandler = { _ in
+ NotificationCenter.default.post(name: .reachabilityChanged, object: nil)
+ }
+ monitor?.start(queue: queue)
+ }
+
+ func startMonitoringWiFi() {
+ isMonitoringLocalWiFi = true
+ monitor = NWPathMonitor(requiredInterfaceType: .wifi)
+ monitor?.pathUpdateHandler = { _ in
+ NotificationCenter.default.post(name: .reachabilityChanged, object: nil)
+ }
+ monitor?.start(queue: queue)
+ }
+}
diff --git a/Sources/QueueITLib/Status.swift b/Sources/QueueITLib/Status.swift
new file mode 100644
index 0000000..a5da82f
--- /dev/null
+++ b/Sources/QueueITLib/Status.swift
@@ -0,0 +1,31 @@
+struct Status {
+ let queueId: String
+ let queueUrlString: String
+ let eventTargetUrl: String
+ let queueitToken: String
+
+ init(queueId: String, queueUrl: String, eventTargetUrl: String, queueitToken: String) {
+ self.queueId = queueId
+ self.queueUrlString = queueUrl
+ self.eventTargetUrl = eventTargetUrl
+ self.queueitToken = queueitToken
+ }
+
+ init(dictionary: [String: Any]) {
+ self.init(
+ queueId: dictionary[Constants.KEY_QUEUE_ID] as? String ?? "",
+ queueUrl: dictionary[Constants.KEY_QUEUE_URL] as? String ?? "",
+ eventTargetUrl: dictionary[Constants.KEY_EVENT_TARGET_URL] as? String ?? "",
+ queueitToken: dictionary[Constants.KEY_QUEUEIT_TOKEN] as? String ?? ""
+ )
+ }
+}
+
+private extension Status {
+ enum Constants {
+ static let KEY_QUEUE_ID = "QueueId"
+ static let KEY_QUEUE_URL = "QueueUrl"
+ static let KEY_EVENT_TARGET_URL = "EventTargetUrl"
+ static let KEY_QUEUEIT_TOKEN = "QueueitToken"
+ }
+}
diff --git a/Sources/QueueITLib/TryPassResult.swift b/Sources/QueueITLib/TryPassResult.swift
new file mode 100644
index 0000000..30f0d98
--- /dev/null
+++ b/Sources/QueueITLib/TryPassResult.swift
@@ -0,0 +1,9 @@
+import Foundation
+
+struct TryPassResult {
+ let queueUrl: String?
+ let targetUrl: String?
+ let redirectType: String
+ let isPassedThrough: Bool
+ let queueToken: String?
+}
diff --git a/Sources/QueueITLib/Utils.swift b/Sources/QueueITLib/Utils.swift
new file mode 100644
index 0000000..2e412f4
--- /dev/null
+++ b/Sources/QueueITLib/Utils.swift
@@ -0,0 +1,40 @@
+import Foundation
+import WebKit
+
+enum Utils {
+ static func getUserId() -> String {
+ let device = UIDevice()
+ if let deviceId = device.identifierForVendor {
+ return deviceId.uuidString
+ }
+ return ""
+ }
+
+ static func getUserAgent(completionHandler: @escaping (String) -> Void) {
+ DispatchQueue.main.async {
+ let view = WKWebView(frame: .zero)
+ view.evaluateJavaScript("navigator.userAgent") { result, error in
+ if let userAgent = result as? String, error == nil {
+ completionHandler(userAgent)
+ } else {
+ completionHandler("")
+ }
+ }
+ }
+ }
+
+ static func getLibraryVersion() -> String {
+ if let infoDictionary = Bundle.main.infoDictionary,
+ let libName = infoDictionary[kCFBundleNameKey as String] as? String,
+ let major = infoDictionary["CFBundleShortVersionString"] as? String,
+ let minor = infoDictionary[kCFBundleVersionKey as String] as? String
+ {
+ return "\(libName)-\(major).\(minor)"
+ }
+ return ""
+ }
+
+ static func getSdkVersion() -> String {
+ return Constants.sdkVersion
+ }
+}
diff --git a/Sources/QueueITLib/WaitingRoomProvider.swift b/Sources/QueueITLib/WaitingRoomProvider.swift
new file mode 100644
index 0000000..33e8fb1
--- /dev/null
+++ b/Sources/QueueITLib/WaitingRoomProvider.swift
@@ -0,0 +1,198 @@
+import Foundation
+
+protocol WaitingRoomProviderDelegate: AnyObject {
+ func notifyProviderSuccess(queuePassResult: TryPassResult)
+ func notifyProviderFailure(errorMessage: String?, errorCode: Int)
+}
+
+enum QueueITRuntimeError: Int {
+ case networkUnavailable = -100
+ case requestAlreadyInProgress = 10
+
+ static let errorMessages = [
+ networkUnavailable: "Network connection is unavailable",
+ requestAlreadyInProgress: "Enqueue request is already in progress",
+ ]
+}
+
+final class WaitingRoomProvider {
+ static let maxRetrySec = 10
+ static let initialWaitRetrySec = 1
+
+ weak var delegate: WaitingRoomProviderDelegate?
+
+ private let customerId: String
+ private let eventOrAliasId: String
+ private let layoutName: String?
+ private let language: String?
+
+ private var deltaSec: Int = WaitingRoomProvider.initialWaitRetrySec
+ private var requestInProgress: Bool = false
+ private let internetReachability: Reachability
+
+ init(customerId: String, eventOrAliasId: String, layoutName: String? = nil, language: String? = nil) {
+ self.customerId = customerId
+ self.eventOrAliasId = eventOrAliasId
+ self.layoutName = layoutName
+ self.language = language
+ internetReachability = Reachability.reachabilityForInternetConnection()
+ }
+
+ func tryPass() throws {
+ try tryEnqueue(enqueueToken: nil, enqueueKey: nil)
+ }
+
+ func tryPassWithEnqueueToken(_ enqueueToken: String?) throws {
+ try tryEnqueue(enqueueToken: enqueueToken, enqueueKey: nil)
+ }
+
+ func tryPassWithEnqueueKey(_ enqueueKey: String?) throws {
+ try tryEnqueue(enqueueToken: nil, enqueueKey: enqueueKey)
+ }
+
+ func isRequestInProgress() -> Bool {
+ return requestInProgress
+ }
+}
+
+private extension WaitingRoomProvider {
+ func tryEnqueue(enqueueToken: String?, enqueueKey: String?) throws {
+ guard checkConnection() else {
+ throw NSError(
+ domain: "QueueITRuntimeException",
+ code: QueueITRuntimeError.networkUnavailable.rawValue,
+ userInfo: nil
+ )
+ }
+
+ if requestInProgress {
+ throw NSError(
+ domain: "QueueITRuntimeException",
+ code: QueueITRuntimeError.requestAlreadyInProgress.rawValue,
+ userInfo: nil
+ )
+ }
+
+ requestInProgress = true
+
+ Utils.getUserAgent { [weak self] userAgent in
+ guard let self else {
+ return
+ }
+ do {
+ try self.tryEnqueueWithUserAgent(
+ secretAgent: userAgent,
+ enqueueToken: enqueueToken,
+ enqueueKey: enqueueKey
+ )
+ } catch {
+ self.requestInProgress = false
+ self.delegate?.notifyProviderFailure(
+ errorMessage: error.localizedDescription,
+ errorCode: (error as NSError).code
+ )
+ }
+ }
+ }
+
+ func tryEnqueueWithUserAgent(secretAgent: String, enqueueToken: String?, enqueueKey: String?) throws {
+ let userId = Utils.getUserId()
+ let userAgent = "\(secretAgent);\(Utils.getLibraryVersion())"
+ let sdkVersion = Utils.getSdkVersion()
+ let apiClient = ApiClient.getInstance()
+
+ apiClient.enqueue(
+ customerId: customerId,
+ eventOrAliasId: eventOrAliasId,
+ userId: userId,
+ userAgent: userAgent,
+ sdkVersion: sdkVersion,
+ layoutName: layoutName,
+ language: language,
+ enqueueToken: enqueueToken,
+ enqueueKey: enqueueKey,
+ success: { [weak self] Status in
+ guard let self else {
+ return
+ }
+ guard let Status else {
+ self.enqueueRetryMonitor(enqueueToken: enqueueToken, enqueueKey: enqueueKey)
+ return
+ }
+
+ self.handleAppEnqueueResponse(
+ queueURL: Status.queueUrlString,
+ eventTargetURL: Status.eventTargetUrl,
+ queueItToken: Status.queueitToken
+ )
+ self.requestInProgress = false
+ },
+ failure: { [weak self] error, errorMessage in
+ guard let self else {
+ return
+ }
+ if let nsError = error as? NSError {
+ if nsError.code >= 400, nsError.code < 500 {
+ self.delegate?.notifyProviderFailure(errorMessage: errorMessage, errorCode: nsError.code)
+ } else {
+ self.enqueueRetryMonitor(enqueueToken: enqueueToken, enqueueKey: enqueueKey)
+ }
+ }
+ }
+ )
+ }
+
+ func handleAppEnqueueResponse(
+ queueURL: String,
+ eventTargetURL: String?,
+ queueItToken: String?
+ ) {
+ let isPassedThrough = !(queueItToken?.isEmpty ?? true)
+ let redirectType = getRedirectType(fromToken: queueItToken)
+
+ let TryPassResult = TryPassResult(
+ queueUrl: queueURL,
+ targetUrl: eventTargetURL,
+ redirectType: redirectType,
+ isPassedThrough: isPassedThrough,
+ queueToken: queueItToken
+ )
+ delegate?.notifyProviderSuccess(queuePassResult: TryPassResult)
+ }
+
+ func enqueueRetryMonitor(enqueueToken: String?, enqueueKey: String?) {
+ if deltaSec < WaitingRoomProvider.maxRetrySec {
+ try? tryEnqueue(enqueueToken: enqueueToken, enqueueKey: enqueueKey)
+ Thread.sleep(forTimeInterval: TimeInterval(deltaSec))
+ deltaSec *= 2
+ } else {
+ deltaSec = WaitingRoomProvider.initialWaitRetrySec
+ requestInProgress = false
+ delegate?.notifyProviderFailure(errorMessage: "Error! Queue is unavailable.", errorCode: 3)
+ }
+ }
+
+ func checkConnection() -> Bool {
+ for _ in 0 ..< 5 {
+ if internetReachability.currentReachabilityStatus() != .notReachable {
+ return true
+ }
+ Thread.sleep(forTimeInterval: 1.0)
+ }
+ return false
+ }
+
+ func getRedirectType(fromToken queueToken: String?) -> String {
+ guard let token = queueToken, !token.isEmpty else {
+ return "queue"
+ }
+
+ let pattern = "\\~rt_(.*?)\\~"
+ if let regex = try? NSRegularExpression(pattern: pattern),
+ let match = regex.firstMatch(in: token, range: NSRange(token.startIndex..., in: token))
+ {
+ return String(token[Range(match.range(at: 1), in: token)!])
+ }
+ return "queue"
+ }
+}
diff --git a/Sources/QueueITLib/WaitingRoomView.swift b/Sources/QueueITLib/WaitingRoomView.swift
new file mode 100644
index 0000000..453dd07
--- /dev/null
+++ b/Sources/QueueITLib/WaitingRoomView.swift
@@ -0,0 +1,100 @@
+import UIKit
+
+protocol WaitingRoomViewDelegate: AnyObject {
+ func notifyViewUserExited()
+ func notifyViewUserClosed()
+ func notifyViewSessionRestart()
+ func notifyQueuePassed(info: QueuePassedInfo?)
+ func notifyViewQueueDidAppear()
+ func notifyViewQueueWillOpen()
+ func notifyViewUpdatePageUrl(urlString: String?)
+}
+
+final class WaitingRoomView {
+ weak var host: UIViewController?
+ weak var delegate: WaitingRoomViewDelegate?
+ weak var currentWebView: WebViewController?
+
+ private var eventId: String
+ private var delayInterval: Int = 0
+
+ init(host: UIViewController, eventId: String) {
+ self.host = host
+ self.eventId = eventId
+ }
+
+ func show(queueUrl: String, targetUrl: String) {
+ raiseQueueViewWillOpen()
+
+ let queueWKVC = WebViewController(
+ queueUrl: queueUrl,
+ eventTargetUrl: targetUrl,
+ eventId: eventId
+ )
+
+ queueWKVC.delegate = self
+
+ if #available(iOS 13.0, *) {
+ queueWKVC.modalPresentationStyle = UIModalPresentationStyle.fullScreen
+ }
+
+ DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(delayInterval)) { [weak self] in
+ guard let self else {
+ return
+ }
+ self.host?.present(queueWKVC, animated: true, completion: { [weak self] in
+ guard let self else {
+ return
+ }
+ self.currentWebView = queueWKVC
+ self.currentWebView?.loadWebView()
+ self.delegate?.notifyViewQueueDidAppear()
+ })
+ }
+ }
+
+ func setViewDelay(_ delayInterval: Int) {
+ self.delayInterval = delayInterval
+ }
+}
+
+extension WaitingRoomView: WebViewControllerDelegate {
+ func notifyViewControllerClosed() {
+ delegate?.notifyViewUserClosed()
+ close()
+ }
+
+ func notifyViewControllerUserExited() {
+ delegate?.notifyViewUserExited()
+ }
+
+ func notifyViewControllerSessionRestart() {
+ delegate?.notifyViewSessionRestart()
+ close()
+ }
+
+ func notifyViewControllerQueuePassed(queueToken: String?) {
+ let queuePassedInfo = QueuePassedInfo(queueitToken: queueToken)
+ delegate?.notifyQueuePassed(info: queuePassedInfo)
+ close()
+ }
+
+ func notifyViewControllerPageUrlChanged(urlString: String?) {
+ delegate?.notifyViewUpdatePageUrl(urlString: urlString)
+ }
+}
+
+private extension WaitingRoomView {
+ func close(onComplete: (() -> Void)? = nil) {
+ DispatchQueue.main.async { [weak self] in
+ guard let self, let host else {
+ return
+ }
+ host.dismiss(animated: true)
+ }
+ }
+
+ func raiseQueueViewWillOpen() {
+ delegate?.notifyViewQueueWillOpen()
+ }
+}
diff --git a/Sources/QueueITLib/WebViewController.swift b/Sources/QueueITLib/WebViewController.swift
new file mode 100644
index 0000000..ee6c755
--- /dev/null
+++ b/Sources/QueueITLib/WebViewController.swift
@@ -0,0 +1,193 @@
+import UIKit
+import WebKit
+
+protocol WebViewControllerDelegate: AnyObject {
+ func notifyViewControllerClosed()
+ func notifyViewControllerUserExited()
+ func notifyViewControllerSessionRestart()
+ func notifyViewControllerQueuePassed(queueToken: String?)
+ func notifyViewControllerPageUrlChanged(urlString: String?)
+}
+
+final class WebViewController: UIViewController {
+ weak var delegate: WebViewControllerDelegate?
+ weak var webView: WKWebView?
+
+ private var spinner: UIActivityIndicatorView?
+ private var isQueuePassed: Bool
+
+ private var queueUrl: String
+ private var eventTargetUrl: String
+ private var eventId: String
+
+ private let JAVASCRIPT_GET_BODY_CLASSES = "document.getElementsByTagName('body')[0].className"
+
+ init(queueUrl: String, eventTargetUrl: String, eventId: String) {
+ self.queueUrl = queueUrl
+ self.eventTargetUrl = eventTargetUrl
+ self.eventId = eventId
+ isQueuePassed = false
+ super.init(nibName: nil, bundle: nil)
+ }
+
+ @available(*, unavailable)
+ required init?(coder _: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ let preferences = WKPreferences()
+ preferences.javaScriptEnabled = true
+
+ let config = WKWebViewConfiguration()
+ config.preferences = preferences
+
+ spinner = UIActivityIndicatorView(frame: view.bounds)
+ webView = WKWebView(frame: view.bounds, configuration: config)
+
+ guard let spinner, let webView else {
+ return
+ }
+
+ spinner.color = .gray
+ webView.navigationDelegate = self
+ webView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
+ webView.isOpaque = false
+ webView.backgroundColor = .clear
+
+ view.addSubview(webView)
+ view.addSubview(spinner)
+
+ webView.frame = view.bounds
+ spinner.frame = view.bounds
+ }
+
+ func loadWebView() {
+ guard let spinner,
+ let webView,
+ let url = URL(string: queueUrl)
+ else {
+ return
+ }
+ spinner.startAnimating()
+ webView.load(URLRequest(url: url))
+ }
+}
+
+extension WebViewController: WKNavigationDelegate {
+ func webView(
+ _: WKWebView,
+ decidePolicyFor navigationAction: WKNavigationAction,
+ decisionHandler: @escaping (WKNavigationActionPolicy) -> Void
+ ) {
+ if !isQueuePassed {
+ let request = navigationAction.request
+ let urlString = request.url?.absoluteString
+ let targetUrlString = eventTargetUrl
+ if let urlString, urlString != "about:blank" {
+ let url = URL(string: urlString)!
+ let targetUrl = URL(string: targetUrlString)!
+ let isQueueUrl = queueUrl.contains(url.host!)
+ let isNotFrame = request.url?.absoluteString == request.mainDocumentURL?.absoluteString
+
+
+ if url.absoluteString == Constants.queueCloseUrl {
+ delegate?.notifyViewControllerClosed()
+ decisionHandler(.cancel)
+ return
+ } else if url.absoluteString == Constants.queueRestartSessionUrl {
+ delegate?.notifyViewControllerSessionRestart()
+ decisionHandler(.cancel)
+ return
+ }
+
+ if isBlockedUrl(destinationUrl: url) {
+ decisionHandler(.cancel)
+ return
+ }
+
+ if isNotFrame {
+ if isQueueUrl {
+ raiseQueuePageUrl(urlString)
+ }
+ if isTargetUrl(targetUrl: targetUrl, destinationUrl: url) {
+ isQueuePassed = true
+ let queueitToken = extractQueueToken(urlString)
+ delegate?.notifyViewControllerQueuePassed(queueToken: queueitToken)
+ decisionHandler(.cancel)
+ return
+ }
+ }
+
+ if navigationAction.navigationType == .linkActivated && !isQueueUrl {
+ UIApplication.shared.open(request.url!)
+ decisionHandler(.cancel)
+ return
+ }
+ }
+ }
+
+ decisionHandler(.allow)
+ }
+
+ func webView(_: WKWebView, didStartProvisionalNavigation _: WKNavigation!) {}
+
+ func webView(_: WKWebView, didFinish _: WKNavigation!) {
+ NotificationCenter.default.addObserver(
+ self,
+ selector: #selector(appWillResignActive(_:)),
+ name: UIApplication.willResignActiveNotification,
+ object: nil
+ )
+
+ guard let spinner, let webView else {
+ return
+ }
+
+ spinner.stopAnimating()
+ webView.evaluateJavaScript(JAVASCRIPT_GET_BODY_CLASSES) { [weak self] result, error in
+ guard let self else {
+ return
+ }
+ if let error {
+ print("evaluateJavaScript error: \(error.localizedDescription)")
+ } else if let resultString = result as? String {
+ let htmlBodyClasses = resultString.split(separator: " ")
+ let isExitClassPresent = htmlBodyClasses.contains("exit")
+ if isExitClassPresent {
+ self.delegate?.notifyViewControllerUserExited()
+ }
+ }
+ }
+ }
+}
+
+private extension WebViewController {
+ func isTargetUrl(targetUrl: URL, destinationUrl: URL) -> Bool {
+ return destinationUrl.host == targetUrl.host && destinationUrl.path == targetUrl.path
+ }
+
+ func isBlockedUrl(destinationUrl: URL) -> Bool {
+ return destinationUrl.path.hasPrefix("/what-is-this.html")
+ }
+
+ func extractQueueToken(_ url: String) -> String? {
+ let tokenKey = "queueittoken="
+ if let range = url.range(of: tokenKey) {
+ var token = String(url[range.upperBound...])
+ if let ampersandRange = token.range(of: "&") {
+ token = String(token[..