diff --git a/MVMCore/MVMCore/Constants/MVMCoreErrorConstants.m b/MVMCore/MVMCore/Constants/MVMCoreErrorConstants.m index d626352..e9028ff 100644 --- a/MVMCore/MVMCore/Constants/MVMCoreErrorConstants.m +++ b/MVMCore/MVMCore/Constants/MVMCoreErrorConstants.m @@ -9,6 +9,10 @@ #import "MVMCoreErrorConstants.h" // Error Domains + +/// Communication breakddowns. NSString * const ErrorDomainSystem = @"ErrorDomainSystem"; +/// Any sort of native error not due to server directivees. NSString * const ErrorDomainNative = @"ErrorDomainNative"; +/// Specific errors defined by the server. NSString * const ErrorDomainServer = @"ErrorDomainServer"; diff --git a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.h b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.h index 84de194..93e7404 100644 --- a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.h +++ b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.h @@ -33,6 +33,15 @@ // Returns the error location for the given requesting object and page type and modules. Important for proper logging. - (nonnull NSString *)errorLocationForRequest:(nonnull id)requestingObject pageType:(nonnull NSString *)pageType modules:(nonnull NSString *)modules; +// Returns an error given a load object and error details. Attaches session data related to the load. Important for proper logging. +- (nonnull MVMCoreErrorObject *)errorForLoadObject:(nonnull MVMCoreLoadObject *)loadObject withTitle:(nullable NSString *)title message:(nullable NSString *)message code:(NSInteger)code domain:(nonnull NSString *)domain; + +// Returns an error given a load object and NSError. Attaches session data related to the load. Important for proper logging. +- (nonnull MVMCoreErrorObject *)errorForLoadObject:(nonnull MVMCoreLoadObject *)loadObject causedBy:(nonnull NSError *)error; + +// Decorates an error object given a load object. +- (nonnull MVMCoreErrorObject *)attachLoadInformation:(nonnull MVMCoreLoadObject *)loadObject toError:(nonnull MVMCoreErrorObject *)error; + #pragma mark - Request Functions. - (void)setHeadersForRequest:(nonnull NSMutableURLRequest *)request requestParameters:(nonnull MVMCoreRequestParameters *)requestParameters; diff --git a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m index 842d032..e5eb99d 100644 --- a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m +++ b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m @@ -95,9 +95,22 @@ } } +- (nonnull MVMCoreErrorObject *)errorForLoadObject:(MVMCoreLoadObject *)loadObject withTitle:(NSString *)title message:(NSString *)message code:(NSInteger)code domain:(NSString *)domain { + return [self attachLoadInformation:loadObject toError:[[MVMCoreErrorObject alloc] initWithTitle:title messageToLog:message code:code domain:domain location:[self errorLocationForRequest:loadObject]]]; +} + +- (nonnull MVMCoreErrorObject *)errorForLoadObject:(MVMCoreLoadObject *)loadObject causedBy:(NSError *)error { + return [self attachLoadInformation:loadObject toError:[MVMCoreErrorObject createErrorObjectForNSError:error location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]]; +} + +- (nonnull MVMCoreErrorObject *)attachLoadInformation:(MVMCoreLoadObject *)loadObject toError:(MVMCoreErrorObject *)error { + return error; // For now, just exposed for overriding. +} + - (nonnull NSString *)errorLocationForRequest:(nonnull MVMCoreLoadObject *)loadObject { - - return [self errorLocationForRequest:loadObject.delegateObject.loadDelegate pageType:loadObject.requestParameters.pageType modules:[NSString stringWithFormat:@"%@",loadObject.requestParameters.modules]]; + return [self errorLocationForRequest:loadObject.delegateObject.loadDelegate + pageType:loadObject.requestParameters.pageType + modules:[NSString stringWithFormat:@"%@", loadObject.requestParameters.modules]]; } - (nonnull NSString *)errorLocationForRequest:(nonnull id)requestingObject pageType:(nonnull NSString *)pageType modules:(nonnull NSString *)modules { @@ -349,7 +362,7 @@ if (!jsonObject) { // Error serializing json. - errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] messageToLog:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] code:ErrorCodeParsingJSON domain:ErrorDomainNative location:locationForError]; + errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] messageToLog:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] code:ErrorCodeParsingJSON domain:ErrorDomainSystem location:locationForError]; } else { // Uncomment to get the raw UTF-8 string response from server before it is parsed. Useful for identifying issues such as duplicate definitions which are removed after parsing. (Also, be careful of parsing tools such as jsoneditoronline.org which will autoresolve some of these issues as well.) @@ -362,7 +375,7 @@ } } else { // Empty response. - errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeEmptyResponse domain:ErrorDomainNative location:locationForError]; + errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeEmptyResponse domain:ErrorDomainSystem location:locationForError]; } } else if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(createErrorObjectForRequestNSError:forRequest:location:)]) { diff --git a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.h b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.h index 1a9f80a..0afd035 100644 --- a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.h +++ b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.h @@ -22,6 +22,7 @@ @property (nullable, strong, nonatomic) MVMCoreLoadObject *loadObject; @property (nullable, strong, nonatomic) NSDictionary *dataForPage; @property (nullable, strong, nonatomic) DelegateObject *delegateObject; +@property (nullable, nonatomic, readonly) NSURLSessionTask *sessionTask; @property (nullable, nonatomic, readonly) NSString *finalLoadSource; @property (nonatomic) BOOL backgroundLoad; @property (nonatomic, getter=areDependenciesAdded) BOOL dependenciesAdded; diff --git a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m index 48f104c..848d283 100644 --- a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m +++ b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m @@ -291,7 +291,7 @@ } else { // Error json not correct format. - MVMCoreErrorObject *errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeJSONNotDictionary domain:ErrorDomainNative location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]; + MVMCoreErrorObject *errorObject = [[MVMCoreLoadHandler sharedGlobal] errorForLoadObject:loadObject withTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeJSONNotDictionary domain:ErrorDomainSystem]; [MVMCoreLoadRequestOperation loadAbortedWithError:errorObject loadObject:loadObject]; } } else { @@ -498,6 +498,7 @@ if (error.errorScreenError && !error.nativeDrivenErrorScreen && loadObject.pageType.length == 0) { error.logError = YES; error.errorScreenError = NO; + error.silentError = NO; error.location = [NSString stringWithFormat:@"%li-%@",(long)ErrorCodeNoErrorPageSent,error.location]; [MVMCoreLoadRequestOperation handleError:error loadObject:loadObject showAlertForErrorIfApplicable:YES]; [MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:nil errorObject:error]; @@ -571,7 +572,8 @@ } else if ([ValueTypeErrorScreen isEqualToString:type]) { // Error Screen, abort the load and handle the screen if necessary - MVMCoreErrorObject *error = [MVMCoreErrorObject createErrorObjectForErrorInfo:loadObject.responseInfoMap location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]; + MVMCoreErrorObject *error = [[MVMCoreLoadHandler sharedGlobal] attachLoadInformation:loadObject toError:[MVMCoreErrorObject createErrorObjectForErrorInfo:loadObject.responseInfoMap location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]]; + [MVMCoreLoadRequestOperation loadAbortedWithError:error loadObject:loadObject]; } else { @@ -582,7 +584,7 @@ } else { // Check for controller specific errors. BOOL shouldContinue; - MVMCoreErrorObject *error = [MVMCoreErrorObject createErrorObjectForErrorInfo:loadObject.responseInfoMap location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]; + MVMCoreErrorObject *error = [[MVMCoreLoadHandler sharedGlobal] attachLoadInformation:loadObject toError:[MVMCoreErrorObject createErrorObjectForErrorInfo:loadObject.responseInfoMap location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]]; if ([loadObject.delegateObject.loadDelegate respondsToSelector:@selector(checkForDelegateSpecificErrors:loadObject:completionHandler:)]) { shouldContinue = [loadObject.delegateObject.loadDelegate checkForDelegateSpecificErrors:error loadObject:loadObject completionHandler:completionHandler]; } else { @@ -614,16 +616,22 @@ } if (obj && [obj isKindOfClass:[NSDictionary class]]) { - NSDictionary *responseInfo = [obj dict:KeyResponseInfo]; if (![ValueTypeSuccess isEqualToString:[responseInfo string:KeyType]]) { - errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[responseInfo stringForKey:KeyErrorHeading] message:[responseInfo stringForKey:KeyUserMessage] messageToLog:[responseInfo stringForKey:KeyMessage] code:[[responseInfo string:KeyCode] integerValue] domain:ErrorDomainServer location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]; + errorObject = [[MVMCoreLoadHandler sharedGlobal] attachLoadInformation:loadObject toError: + [[MVMCoreErrorObject alloc] + initWithTitle:[responseInfo stringForKey:KeyErrorHeading] + message:[responseInfo stringForKey:KeyUserMessage] + messageToLog:[responseInfo stringForKey:KeyMessage] + code:[[responseInfo string:KeyCode] integerValue] + domain:ErrorDomainServer + location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]]; } // Caches each dictionary from the array. [[MVMCoreCache sharedCache] addModuleToCache:obj module:key queue:nil waitUntilFinished:YES completionBlock:NULL]; } else { - errorObject = [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeJSONNotDictionary domain:ErrorDomainNative location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]; + errorObject = [[MVMCoreLoadHandler sharedGlobal] errorForLoadObject:loadObject withTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeJSONNotDictionary domain:ErrorDomainSystem]; } if (errorObject) { @@ -666,10 +674,10 @@ if (pageType) { [[MVMCoreCache sharedCache] addPageToCache:obj pageType:pageType queue:nil waitUntilFinished:YES completionBlock:NULL]; } else { - errorObject = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeNoPageType domain:ErrorDomainNative location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]; + errorObject = [[MVMCoreLoadHandler sharedGlobal] errorForLoadObject:loadObject withTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeNoPageType domain:ErrorDomainNative]; } } else { - errorObject = [[MVMCoreErrorObject alloc] initWithTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeJSONNotDictionary domain:ErrorDomainNative location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]; + errorObject = [[MVMCoreLoadHandler sharedGlobal] errorForLoadObject:loadObject withTitle:nil message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeJSONNotDictionary domain:ErrorDomainNative]; } // Logs the error. @@ -713,7 +721,7 @@ } } else { // Couldn't initialize view controller, serious error. - error = [[MVMCoreErrorObject alloc] initWithTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeInitViewController domain:ErrorDomainNative location:[[MVMCoreLoadHandler sharedGlobal] errorLocationForRequest:loadObject]]; + error = [[MVMCoreLoadHandler sharedGlobal] errorForLoadObject:loadObject withTitle:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle] message:[MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorCritical] code:ErrorCodeInitViewController domain:ErrorDomainNative]; } [MVMCoreLoadRequestOperation handleShouldContinue:shouldContinue error:error loadObject:loadObject errorBlock:NULL continueBlock:^{ diff --git a/MVMCore/MVMCore/Utility/MVMCoreErrorObject.h b/MVMCore/MVMCore/Utility/MVMCoreErrorObject.h index 86fdda0..b91326e 100644 --- a/MVMCore/MVMCore/Utility/MVMCoreErrorObject.h +++ b/MVMCore/MVMCore/Utility/MVMCoreErrorObject.h @@ -22,6 +22,11 @@ @property (nullable, strong, nonatomic) NSString *systemDomain; @property (nonatomic) NSInteger code; @property (nonatomic) UIApplicationState applicationState; +@property (nullable, strong, nonatomic) NSString *sessionId; +@property (nullable, strong, nonatomic) NSString *requestId; +@property (nullable, strong, nonatomic) NSString *requestUrl; +@property (nonatomic, assign) NSInteger httpStatusCode; +@property (nonatomic, strong) NSDictionary *serverResponseInfo; // For the crash log. @property (nullable, strong, nonatomic) NSDictionary *crashLog; diff --git a/MVMCore/MVMCore/Utility/MVMCoreErrorObject.m b/MVMCore/MVMCore/Utility/MVMCoreErrorObject.m index 09f76b4..40432d0 100644 --- a/MVMCore/MVMCore/Utility/MVMCoreErrorObject.m +++ b/MVMCore/MVMCore/Utility/MVMCoreErrorObject.m @@ -28,21 +28,17 @@ self.domain = domain; self.location = location; self.date = [NSDate date]; + self.silentError = YES; // TODO: Hold on this. Messes with server errors. + self.logError = YES; [MVMCoreDispatchUtility performSyncBlockOnMainThread:^{ self.applicationState = [UIApplication sharedApplication].applicationState; }]; - - // We don't log server errors. - if (![domain isEqualToString:ErrorDomainServer]) { - self.logError = YES; - // Native and system errors have an error screen. - if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(getNativeScreenForRequestError:requestObject:)]) { - self.errorScreenError = YES; - self.nativeDrivenErrorScreen = YES; - } - } else { - self.logError = NO; + // Native and system errors have an error screen. + if (![domain isEqualToString:ErrorDomainServer] && [[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(getNativeScreenForRequestError:requestObject:)]) { + self.errorScreenError = YES; + self.nativeDrivenErrorScreen = YES; + self.silentError = NO; } } return self; @@ -58,20 +54,17 @@ self.domain = domain; self.location = location; self.date = [NSDate date]; + self.silentError = YES; // TODO: Hold on this. Messes with server errors. + self.logError = YES; [MVMCoreDispatchUtility performSyncBlockOnMainThread:^{ self.applicationState = [UIApplication sharedApplication].applicationState; }]; - // We don't log server errors. - if (![domain isEqualToString:ErrorDomainServer]) { - self.logError = YES; - - // Native and system errors have an error screen. - if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(getNativeScreenForRequestError:requestObject:)]) { - self.errorScreenError = YES; - self.nativeDrivenErrorScreen = YES; - } - } else { - self.logError = NO; + + // Native and system errors have an error screen. + if (![domain isEqualToString:ErrorDomainServer] && [[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(getNativeScreenForRequestError:requestObject:)]) { + self.errorScreenError = YES; + self.nativeDrivenErrorScreen = YES; + self.silentError = NO; } } return self; @@ -91,12 +84,12 @@ NSInteger errorCode = [[errorInfo string:KeyCode] integerValue]; NSString *type = [errorInfo string:KeyType]; if (![ValueTypeSuccess isEqualToString:type]) { - NSString *title = [errorInfo string:KeyErrorHeading] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorTitle]; NSString *message = [errorInfo string:KeyUserMessage] ?: [MVMCoreGetterUtility hardcodedStringWithKey:HardcodedErrorUnableToProcess]; - MVMCoreErrorObject *error = [[MVMCoreErrorObject alloc] initWithTitle:title message:message messageToLog:[errorInfo string:KeyMessage] code:errorCode domain:ErrorDomainServer location:location]; + MVMCoreErrorObject *error = [[MVMCoreErrorObject alloc] initWithTitle:title message:message messageToLog:[errorInfo string:KeyMessage] ?: @"ResponseInfo type is not Success." code:errorCode domain:ErrorDomainServer location:location]; + error.silentError = NO; + error.serverResponseInfo = errorInfo; if ([ValueTypeErrorScreen isEqualToString:type]) { - // If this is a server error screen, there should be no additional alerts... It will be handled by the load handler. error.errorScreenError = YES; }