diff --git a/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/WebSocketClient.swift b/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/WebSocketClient.swift index e2e8c85503..2267ea6cb5 100644 --- a/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/WebSocketClient.swift +++ b/AmplifyPlugins/Core/AWSPluginsCore/WebSocket/WebSocketClient.swift @@ -248,8 +248,13 @@ extension WebSocketClient: URLSessionWebSocketDelegate { let nsError = error as NSError switch (nsError.domain, nsError.code) { - case (NSURLErrorDomain.self, NSURLErrorNetworkConnectionLost), // connection lost - (NSPOSIXErrorDomain.self, Int(ECONNABORTED)): // background to foreground + case (NSURLErrorDomain.self, NSURLErrorNetworkConnectionLost), + (NSURLErrorDomain.self, NSURLErrorCannotConnectToHost), + (NSURLErrorDomain.self, NSURLErrorTimedOut), + (NSURLErrorDomain.self, NSURLErrorNotConnectedToInternet), + (NSURLErrorDomain.self, NSURLErrorDataNotAllowed), + (NSPOSIXErrorDomain.self, Int(ECONNABORTED)), + (NSPOSIXErrorDomain.self, 57): self.subject.send(.error(WebSocketClient.Error.connectionLost)) Task { [weak self] in await self?.networkMonitor.updateState(.offline) @@ -283,11 +288,11 @@ extension WebSocketClient { } switch stateChange { - case (.online, .offline): - log.debug("[WebSocketClient] NetworkMonitor - Device went offline") + case (.online, .offline), (.none, .offline), (.online, .none): + log.debug("[WebSocketClient] NetworkMonitor - Device went offline or network status became unknown") self.connection?.cancel(with: .invalid, reason: nil) self.subject.send(.disconnected(.invalid, nil)) - case (.offline, .online): + case (.offline, .online), (.none, .online): log.debug("[WebSocketClient] NetworkMonitor - Device back online") await self.createConnectionAndRead() default: @@ -335,13 +340,19 @@ extension WebSocketClient { } switch closeCode { - case .internalServerError: + case .internalServerError, + .abnormalClosure, + .invalid, + .policyViolation: + log.debug("[WebSocketClient] Retrying on closeCode: \(closeCode)") let delayInMs = await retryWithJitter.next() Task { [weak self] in try await Task.sleep(nanoseconds: UInt64(delayInMs) * 1_000_000) await self?.createConnectionAndRead() } - default: break + default: + log.debug("[WebSocketClient] Not retrying for closeCode: \(closeCode)") + break } } diff --git a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUpload.swift b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUpload.swift index 5a2f1a1b6e..b68c81c5ae 100644 --- a/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUpload.swift +++ b/AmplifyPlugins/Storage/Sources/AWSS3StoragePlugin/Support/Internal/StorageMultipartUpload.swift @@ -229,14 +229,14 @@ enum StorageMultipartUpload { case .parts(let uploadId, let uploadFile, let partSize, let parts): self = .paused(uploadId: uploadId, uploadFile: uploadFile, partSize: partSize, parts: parts) default: - throw Failure.invalidStateTransition(reason: "Cannot pause from current state: \(self)") + throw Failure.invalidStateTransition(reason: "Cannot pause upload: upload must be in progress") } case .resuming: switch self { case .paused(let uploadId, let uploadFile, let partSize, let parts): self = .parts(uploadId: uploadId, uploadFile: uploadFile, partSize: partSize, parts: parts) default: - throw Failure.invalidStateTransition(reason: "Cannot resume from current state: \(self)") + throw Failure.invalidStateTransition(reason: "Cannot resume upload: upload must be paused") } break case .completing(let taskIdentifier): @@ -246,20 +246,20 @@ enum StorageMultipartUpload { case .parts: self = .completed(uploadId: uploadId) default: - throw Failure.invalidStateTransition(reason: "Cannot complete from current state: \(self)") + throw Failure.invalidStateTransition(reason: "Cannot complete upload: upload must be in progress") } case .aborting(let error): if let uploadId = uploadId { self = .aborting(uploadId: uploadId, error: error) } else { - throw Failure.invalidStateTransition(reason: "Cannot abort from current state: \(self)") + throw Failure.invalidStateTransition(reason: "Cannot abort upload: no upload ID available") } case .aborted(let uploadId, let error): switch self { case .created, .parts, .aborting: self = .aborted(uploadId: uploadId, error: error) default: - throw Failure.invalidStateTransition(reason: "Cannot abort from current state: \(self)") + throw Failure.invalidStateTransition(reason: "Cannot abort upload: upload must be in progress or created") } case .failed(let uploadId, let error): switch self { @@ -268,7 +268,7 @@ enum StorageMultipartUpload { case .parts(_, _, _, let parts): self = .failed(uploadId: uploadId, parts: parts, error: error) default: - throw Failure.invalidStateTransition(reason: "Cannot fail from current state: \(self)") + throw Failure.invalidStateTransition(reason: "Cannot fail upload: invalid state for failure") } } } @@ -277,7 +277,7 @@ enum StorageMultipartUpload { mutating func transition(uploadPartEvent: StorageUploadPartEvent) throws { guard !isAborting, !isAborted else { return } guard case .parts(let uploadId, let uploadFile, let partSize, var parts) = self else { - throw Failure.invalidStateTransition(reason: "Parts are required for this transition: \(uploadPartEvent)") + throw Failure.invalidStateTransition(reason: "Cannot process part event: upload must be in progress") } let partNumber = uploadPartEvent.number @@ -297,12 +297,12 @@ enum StorageMultipartUpload { parts[index] = .inProgress(bytes: part.bytes, bytesTransferred: 0, taskIdentifier: taskIdentifier) case .progressUpdated(_, let bytesTransferred, _): guard case .inProgress(let bytes, _, let taskIdentifier) = part else { - throw Failure.invalidStateTransition(reason: "Part cannot update progress in current state: \(self)") + throw Failure.invalidStateTransition(reason: "Cannot update progress: part must be in progress") } parts[index] = .inProgress(bytes: bytes, bytesTransferred: bytesTransferred, taskIdentifier: taskIdentifier) case .completed(_, let eTag, _): guard case .inProgress(let bytes, _, _) = part else { - throw Failure.invalidStateTransition(reason: "Part cannot be completed in current state: \(self)") + throw Failure.invalidStateTransition(reason: "Cannot complete part: part must be in progress") } parts[index] = StorageUploadPart.completed(bytes: bytes, eTag: eTag) case .failed: