diff --git a/.github/workflows/build-deploy-docs.yml b/.github/workflows/build-deploy-docs.yml
index 64be3b1..7419c84 100644
--- a/.github/workflows/build-deploy-docs.yml
+++ b/.github/workflows/build-deploy-docs.yml
@@ -10,8 +10,8 @@ permissions:
id-token: write
jobs:
- build-deploy-docs:
- name: Build and Deploy Docs
+ build-docs:
+ name: Build Docs
runs-on: macos-13
steps:
@@ -27,11 +27,32 @@ jobs:
scheme: RxNetworkKit
run: |
xcodebuild docbuild -workspace "${workspace}" -scheme "${scheme}" -derivedDataPath derivedData | xcpretty
- - name: Perpare Docs for Deployment
- run: |
mkdir docArchives
cp -R `find derivedData -type d -name "*.doccarchive"` docArchives
+ zip -r RxNetworkKitDocCArchive.zip docArchives/RxNetworkKit.doccarchive
+ - name: Upload Docs Archive
+ uses: actions/upload-artifact@v3
+ with:
+ name: doc-archive-zip
+ path: RxNetworkKitDocCArchive.zip
+
+ deploy-docs:
+ name: Deploy Docs
+ runs-on: macos-13
+ needs: build-docs
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Download Docs Archive
+ uses: actions/download-artifact@v3
+ with:
+ name: doc-archive-zip
+ - name: Perpare Docs for Deployment
+ run: |
+ unzip RxNetworkKitDocCArchive.zip
$(xcrun --find docc) process-archive transform-for-static-hosting docArchives/RxNetworkKit.doccarchive --hosting-base-path RxNetworkKit --output-path docs
+ echo "" > docs/index.html;
- name: Upload Docs artifact
uses: actions/upload-pages-artifact@v1
with:
diff --git a/Docs.docc/Pages/NetworkManager.md b/Docs.docc/Pages/NetworkManager.md
index 21e055b..3061998 100644
--- a/Docs.docc/Pages/NetworkManager.md
+++ b/Docs.docc/Pages/NetworkManager.md
@@ -34,4 +34,5 @@
- ``WebSocketMessage``
- ``WebSocketCloseCode``
- ``WebSocketCloseHandler``
+- ``WebSocketError``
- ``NetworkManager/webSocket(_:_:_:)``
diff --git a/Examples/iOS/iOS Example/View Model/ViewModel.swift b/Examples/iOS/iOS Example/View Model/ViewModel.swift
index dfe174f..aa5517e 100644
--- a/Examples/iOS/iOS Example/View Model/ViewModel.swift
+++ b/Examples/iOS/iOS Example/View Model/ViewModel.swift
@@ -40,7 +40,8 @@ class ViewModel {
// Create default sequence with default API call request.
let loadObservable = viewState
.filter( { ![.idle, .loading(loadType: .paginate), .error].contains($0) })
- .flatMapLatest{ _ in
+ .flatMapLatest{ [weak self] _ in
+ guard let self = self else { return Observable<[Model]>.empty().materialize() }
let single: Single<[Model]> = self.networkManager.request(Router.default)
return single
.asObservable()
diff --git a/Examples/macOS/macOS Example/View Model/ViewModel.swift b/Examples/macOS/macOS Example/View Model/ViewModel.swift
index dfe174f..aa5517e 100644
--- a/Examples/macOS/macOS Example/View Model/ViewModel.swift
+++ b/Examples/macOS/macOS Example/View Model/ViewModel.swift
@@ -40,7 +40,8 @@ class ViewModel {
// Create default sequence with default API call request.
let loadObservable = viewState
.filter( { ![.idle, .loading(loadType: .paginate), .error].contains($0) })
- .flatMapLatest{ _ in
+ .flatMapLatest{ [weak self] _ in
+ guard let self = self else { return Observable<[Model]>.empty().materialize() }
let single: Single<[Model]> = self.networkManager.request(Router.default)
return single
.asObservable()
diff --git a/RxNetworkKit.xcodeproj/project.pbxproj b/RxNetworkKit.xcodeproj/project.pbxproj
index c6a5a47..936b8d2 100644
--- a/RxNetworkKit.xcodeproj/project.pbxproj
+++ b/RxNetworkKit.xcodeproj/project.pbxproj
@@ -63,6 +63,7 @@
C6A9BEFA2A93F16200459E32 /* URLSessionConfiguration+setAdditionalHTTPHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A9BEF92A93F16200459E32 /* URLSessionConfiguration+setAdditionalHTTPHeader.swift */; };
C6A9BEFD2A93FAF100459E32 /* URLSessionConfiguration+setUserAgentHTTPHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A9BEFC2A93FAF100459E32 /* URLSessionConfiguration+setUserAgentHTTPHeader.swift */; };
C6A9BEFF2A93FB1D00459E32 /* ProcessInfo+operatingSystemName.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A9BEFE2A93FB1D00459E32 /* ProcessInfo+operatingSystemName.swift */; };
+ C6B4B4C42AD47A2F009073ED /* WebSocketError.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6B4B4C32AD47A2F009073ED /* WebSocketError.swift */; };
C6BDFFE82ACDF3830022F675 /* Reactive+receive.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6BDFFE72ACDF3830022F675 /* Reactive+receive.swift */; };
C6BDFFEA2ACDF3D90022F675 /* Reactive+send.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6BDFFE92ACDF3D90022F675 /* Reactive+send.swift */; };
C6BDFFEC2ACDF4100022F675 /* Reactive+ping.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6BDFFEB2ACDF4100022F675 /* Reactive+ping.swift */; };
@@ -127,6 +128,7 @@
C6A9BEF92A93F16200459E32 /* URLSessionConfiguration+setAdditionalHTTPHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSessionConfiguration+setAdditionalHTTPHeader.swift"; sourceTree = ""; };
C6A9BEFC2A93FAF100459E32 /* URLSessionConfiguration+setUserAgentHTTPHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSessionConfiguration+setUserAgentHTTPHeader.swift"; sourceTree = ""; };
C6A9BEFE2A93FB1D00459E32 /* ProcessInfo+operatingSystemName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProcessInfo+operatingSystemName.swift"; sourceTree = ""; };
+ C6B4B4C32AD47A2F009073ED /* WebSocketError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSocketError.swift; sourceTree = ""; };
C6BDFFE72ACDF3830022F675 /* Reactive+receive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Reactive+receive.swift"; sourceTree = ""; };
C6BDFFE92ACDF3D90022F675 /* Reactive+send.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Reactive+send.swift"; sourceTree = ""; };
C6BDFFEB2ACDF4100022F675 /* Reactive+ping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Reactive+ping.swift"; sourceTree = ""; };
@@ -364,6 +366,7 @@
C6BDFFEF2ACDF4AB0022F675 /* WebSocketCloseHandler.swift */,
C6BDFFF22ACDF50F0022F675 /* WebSocketMessage.swift */,
C6BDFFF42ACDF5250022F675 /* WebSocketCloseCode.swift */,
+ C6B4B4C32AD47A2F009073ED /* WebSocketError.swift */,
);
path = "Web Socket";
sourceTree = "";
@@ -498,6 +501,7 @@
0B77E09129D965D30077FBC0 /* Reactive+URLSessionAdaptedUploadResponse.swift in Sources */,
C6A9BEFA2A93F16200459E32 /* URLSessionConfiguration+setAdditionalHTTPHeader.swift in Sources */,
C6BDFFF32ACDF5100022F675 /* WebSocketMessage.swift in Sources */,
+ C6B4B4C42AD47A2F009073ED /* WebSocketError.swift in Sources */,
0B77E0A629D965D30077FBC0 /* DefaultNetworkAPIError.swift in Sources */,
0B77E0A429D965D30077FBC0 /* NetworkReachability.swift in Sources */,
0B77E0B229D965D30077FBC0 /* Completable+Retry.swift in Sources */,
diff --git a/Source/Web Socket/Extensions/Reactive+ping.swift b/Source/Web Socket/Extensions/Reactive+ping.swift
index 10ae88b..deea8d2 100644
--- a/Source/Web Socket/Extensions/Reactive+ping.swift
+++ b/Source/Web Socket/Extensions/Reactive+ping.swift
@@ -9,6 +9,7 @@ import Foundation
import RxSwift
extension Reactive where Base: URLSessionWebSocketTask {
+
/// Sends a ping to the websocket server.
///
/// - Returns: `Completable` observable encapsulating send ping operation.
@@ -19,9 +20,10 @@ extension Reactive where Base: URLSessionWebSocketTask {
subscription(.completed)
return
}
- subscription(.error(error))
+ subscription(.error(WebSocketError.ping(error: error)))
}
return Disposables.create()
}
}
+
}
diff --git a/Source/Web Socket/Extensions/Reactive+receive.swift b/Source/Web Socket/Extensions/Reactive+receive.swift
index 701fb75..988d0b9 100644
--- a/Source/Web Socket/Extensions/Reactive+receive.swift
+++ b/Source/Web Socket/Extensions/Reactive+receive.swift
@@ -23,16 +23,13 @@ extension Reactive where Base: URLSessionWebSocketTask {
subscription.onNext(message)
receive(subscription: subscription)
case .failure(let error):
- subscription.onError(error)
+ subscription.onError(WebSocketError.receive(error: error))
}
}
}
return Observable.create { subscription in
receive(subscription: subscription)
- return Disposables.create {
- let request = base.currentRequest
- base.cancel(with: closeHandler.code(for: request), reason: closeHandler.reason(for: request))
- }
+ return Disposables.create()
}
.share()
}
diff --git a/Source/Web Socket/Extensions/Reactive+send.swift b/Source/Web Socket/Extensions/Reactive+send.swift
index 383f7d1..693ae8b 100644
--- a/Source/Web Socket/Extensions/Reactive+send.swift
+++ b/Source/Web Socket/Extensions/Reactive+send.swift
@@ -9,6 +9,7 @@ import Foundation
import RxSwift
extension Reactive where Base: URLSessionWebSocketTask {
+
/// Sends message to the websocket server.
///
/// - Parameter message: `WebSocketMessage` to be sent to websocket server.
@@ -21,9 +22,10 @@ extension Reactive where Base: URLSessionWebSocketTask {
subscription(.completed)
return
}
- subscription(.error(error))
+ subscription(.error(WebSocketError.send(error: error)))
}
return Disposables.create()
}
}
+
}
diff --git a/Source/Web Socket/WebSocket.swift b/Source/Web Socket/WebSocket.swift
index 7edb256..7c7a644 100644
--- a/Source/Web Socket/WebSocket.swift
+++ b/Source/Web Socket/WebSocket.swift
@@ -17,7 +17,7 @@ public class WebSocket {
/// a generic `PublishRelay` object for data messages received from websocket server.
public let data: PublishRelay = .init()
/// a `PublishRelay` object for errors encountered while receiving/sending from/to websocket server.
- public let error: PublishRelay = .init()
+ public let error: PublishRelay = .init()
private let task: URLSessionWebSocketTask
private let closeHandler: WebSocketCloseHandler
private let receiveObservable: Observable
@@ -35,6 +35,11 @@ public class WebSocket {
setupBindings()
}
+ /// Destroys current `WebSocket` instance and cancels current task.
+ deinit {
+ disconnect()
+ }
+
/// Resumes current task to establish the connection.
public func connect() {
task.resume()
@@ -49,17 +54,23 @@ public class WebSocket {
/// Sends message to the websocket server.
///
/// - Parameter message: `WebSocketMessage` to be sent to websocket server.
- ///
- /// - Returns: `Completable` observable encapsulating send message operation.
- public func send(_ message: WebSocketMessage) -> Completable {
+ public func send(_ message: WebSocketMessage) {
task.rx.send(message: message)
+ .subscribe(onError: { error in
+ guard let error = error as? WebSocketError else { return }
+ self.error.accept(error)
+ })
+ .disposed(by: disposeBag)
}
/// Sends a ping to the websocket server.
- ///
- /// - Returns: `Completable` observable encapsulating send ping operation.
- public func ping() -> Completable {
+ public func ping() {
task.rx.ping()
+ .subscribe(onError: { error in
+ guard let error = error as? WebSocketError else { return }
+ self.error.accept(error)
+ })
+ .disposed(by: disposeBag)
}
/// Sets up internal observable bindings.
@@ -92,6 +103,7 @@ public class WebSocket {
.materialize()
.compactMap({
guard case .error(let error) = $0 else { return nil }
+ guard let error = error as? WebSocketError else { return nil }
return error
})
.bind(to: error)
diff --git a/Source/Web Socket/WebSocketError.swift b/Source/Web Socket/WebSocketError.swift
new file mode 100644
index 0000000..5b8f2a9
--- /dev/null
+++ b/Source/Web Socket/WebSocketError.swift
@@ -0,0 +1,15 @@
+//
+// WebSocketError.swift
+// RxNetworkKit
+//
+// Created by Loay Ashraf on 09/10/2023.
+//
+
+import Foundation
+
+/// An enumeration that contains cases where error is received from websocket.
+public enum WebSocketError: Error {
+ case receive(error: Error)
+ case send(error: Error)
+ case ping(error: Error)
+}