Skip to content

Commit

Permalink
Merge branch 'release/3.1.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
anthonyGuiguen committed Jul 24, 2020
2 parents 1c22c03 + 94fae2c commit 78e9526
Show file tree
Hide file tree
Showing 19 changed files with 269 additions and 211 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# CHANGELOG
All notable changes to this project will be documented in this file.

## 3.1.0
* Errors - Create recorder for sharing important errors
* Errors - Refact error to be more precise on the failure
[Anthony GUIGUEN](https://https://github.com/anthonyGuiguen)
[#34](https://github.com/Insurlytech/zetapush-swift/pull/34)

## 3.0.0
* CometD - Remove CometDClient from ZetaPush
[Anthony GUIGUEN](https://https://github.com/anthonyGuiguen)
Expand Down
6 changes: 3 additions & 3 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"repositoryURL": "https://github.com/Insurlytech/CometDClient-iOS.git",
"state": {
"branch": null,
"revision": "7dc8edfe6af41db6c6e64bf8541b64d2c93a559a",
"version": "1.0.0"
"revision": "44ce6ecd3594a670ea59d375ff69af4c090d0edb",
"version": "1.1.0"
}
},
{
Expand Down Expand Up @@ -52,7 +52,7 @@
"state": {
"branch": null,
"revision": "2b6054efa051565954e1d2b9da831680026cd768",
"version": "4.3.0"
"version": "5.0.0"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ let package = Package(
],
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(name: "CometDClient", url: "https://github.com/Insurlytech/CometDClient-iOS.git", .upToNextMajor(from: "1.0.0")),
.package(name: "CometDClient", url: "https://github.com/Insurlytech/CometDClient-iOS.git", .upToNextMajor(from: "1.1.0")),
// .package(name: "CometDClient", path: "../CometDClient-iOS"), //AGU
.package(url: "https://github.com/hkellaway/Gloss.git", .upToNextMajor(from: "3.1.0")),
.package(url: "https://github.com/mxcl/PromiseKit", .upToNextMajor(from: "6.13.1")),
Expand Down
118 changes: 51 additions & 67 deletions Sources/ZetaPushNetwork/Client/ClientHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import UIKit
// MARK: - ClientHelper
open class ClientHelper: NSObject {
// MARK: Properties
var sandboxId = ""
let serverConfiguration: ServerConfiguration
private let remote: ServerRemoteDataSource
var server = ""
var apiUrl = ""
var connected = false
var userId = ""
var resource = ""
Expand All @@ -44,28 +44,30 @@ open class ClientHelper: NSObject {

let log = XCGLogger(identifier: "zetaPushLogger", includeDefaultDestinations: true)
let tags = XCGLogger.Constants.userInfoKeyTags
public var timeout: TimeInterval = ZetaPushConstants.timeout
private weak var recorder: ZetapushNetworkRecorder?

// MARK: Lifecycle
public init(apiUrl: String, sandboxId: String, authentication: AbstractHandshake, resource: String = "", logLevel: XCGLogger.Level = .severe) {
self.sandboxId = sandboxId
public init(serverConfiguration: ServerConfiguration, authentication: AbstractHandshake, resource: String = "", logLevel: XCGLogger.Level = .severe, recorder: ZetapushNetworkRecorder?) {
self.serverConfiguration = serverConfiguration
self.recorder = recorder
self.remote = ServerRemoteDataSource(configuration: serverConfiguration, recorder: recorder)
self.authentication = authentication
self.resource = resource
self.apiUrl = apiUrl
self.cometdClient = CometdClient()
super.init()

self.logLevel = logLevel
log.setup(level: logLevel)
self.cometdClient.log.outputLevel = self.logLevel

// Handle resource
let defaults = UserDefaults.standard
if resource.isEmpty {
if let storedResource = defaults.string(forKey: zetaPushDefaultKeys.resource) {
if let storedResource = defaults.string(forKey: ZetaPushDefaultKeys.resource) {
self.resource = storedResource
} else {
self.resource = ZetaPushUtils.generateResourceName()
defaults.set(self.resource, forKey: zetaPushDefaultKeys.resource)
defaults.set(self.resource, forKey: ZetaPushDefaultKeys.resource)
}
}

Expand Down Expand Up @@ -93,67 +95,37 @@ open class ClientHelper: NSObject {

// Connect to server
open func connect() {
log.debug("Client Connection: check the validation of server url : \(server)")
log.zp.debug("ZetaPushNetwork try to connect")

guard server.isEmpty else {
log.zp.debug("Client Connection: ZetaPush configured Server")
log.zp.debug(self.server)
log.zp.debug("ZetaPushNetwork already has a server url")
configureCometdClient()
return
}
let stringUrl = self.apiUrl + "/" + sandboxId
guard let url = URL(string: stringUrl), UIApplication.shared.canOpenURL(url) else {
self.log.verbose("ZP server -> can't open url : " + stringUrl)
return
}

// Check the http://api.zpush.io with sandboxId
self.log.verbose("ZP server -> target url : " + url.description)

let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = timeout
configuration.timeoutIntervalForResource = timeout * 3
let task = URLSession(configuration: configuration).dataTask(with: url) { [weak self] data, response, error in
log.zp.debug("ZetaPushNetwork try to fetch servers URLs")
remote.fetchServersURLs { [weak self] result in
guard let self = self else { return }
guard let data = data else {
self.log.zp.error("Client Connection: No server for the sandbox")
return
}
guard error == nil else {
self.log.error (error!)
return
}

self.log.verbose("ZP server -> server response data : " + data.description)
let jsonAnyTest = try? JSONSerialization.jsonObject(with: data, options: [])
let jsonTest = jsonAnyTest as? [String: Any] ?? [:]
self.log.verbose("ZP server -> server response : " + jsonTest.description)

guard let jsonAny = try? JSONSerialization.jsonObject(with: data, options: []),
let json = jsonAny as? [String : Any],
let servers = json["servers"] as? [Any] else {
self.log.zp.error("Client Connection: Failed to parse data from server")
return
}

guard let randomServer = servers.randomElement() as? String else {
self.log.zp.error("Client Connection: No server in servers object")
return
switch result {
case .success(let servers):
self.log.zp.debug("ZetaPushNetwork succeded to fetch servers URLs : \(servers)")
guard let randomServer = servers.randomElement() else { return }
self.log.zp.debug("ZetaPushNetwork select a random server : \(randomServer)")
self.server = randomServer + "/strd"

self.configureCometdClient()
case .failure(let error):
self.log.zp.error("ZetaPushNetwork failed to fetch servers URLs : \(error.localizedDescription)")
self.delegate?.onConnectionFailed(self, error: ClientHelperError.connectionFailed)
}
self.server = randomServer + "/strd"
self.log.debug("Client Connection: ZetaPush selected Server")
self.log.debug("Client Connection: server returned server url : \(self.server)")

self.cometdClient.log.outputLevel = self.logLevel
self.configureCometdClient()
}
task.resume()
}

private func configureCometdClient() {
cometdClient.configure(url: server)
log.zp.debug("ZetaPushNetwork configure CometdClient")
cometdClient.configure(url: server, recorder: recorder)
let handshakeFields = authentication.getHandshakeFields(self)
self.log.debug("authentification = \(authentication)")
log.zp.debug("authentification = \(authentication)")
cometdClient.handshake(fields: handshakeFields)
}

Expand Down Expand Up @@ -204,7 +176,7 @@ open class ClientHelper: NSObject {
}

open func composeServiceChannel(_ verb: String, deploymentId: String) -> String {
return "/service/" + sandboxId + "/" + deploymentId + "/" + verb
return "/service/" + serverConfiguration.sandboxId + "/" + deploymentId + "/" + verb
}

open func getLogLevel() -> XCGLogger.Level {
Expand Down Expand Up @@ -237,7 +209,7 @@ open class ClientHelper: NSObject {
}

open func getSandboxId() -> String {
return sandboxId
return serverConfiguration.sandboxId
}

open func getServer() -> String {
Expand Down Expand Up @@ -324,31 +296,43 @@ extension ClientHelper: CometdClientDelegate {

delegate?.onSuccessfulHandshake(self)
}
public func handshakeDidFailed(from client: CometdClientContract) {

public func handshakeDidFailed(error: Error, from client: CometdClientContract) {
log.zp.error("ClientHelper Handshake Failed")
delegate?.onFailedHandshake(self)
var handshakeError: ClientHelperError = .handshakeFailed(reason: nil)
if let error = error as? CometDClientError {
switch error {
case .handshake(let reason):
handshakeError = .handshakeFailed(reason: reason)
default: break
}
}
delegate?.onFailedHandshake(self, error: handshakeError)
}

public func didDisconnected(error: Error?, from client: CometdClientContract) {
log.zp.debug("ClientHelper Disconnected from Cometd server")
connected = false
delegate?.onConnectionClosed(self)
if error != nil {
delegate?.onConnectionClosed(self, error: ClientHelperError.connectionClosed)
} else {
delegate?.onConnectionClosed(self, error: nil)
}
}

public func didAdvisedToReconnect(from client: CometdClientContract) {
log.zp.debug("ClientHelper Disconnected from Cometd server")
delegate?.onConnectionClosedAdviceReconnect(self)
}

public func didFailConnection(error: Error?, from client: CometdClientContract) {
log.zp.error("ClientHelper Failed to connect to Cometd server!")
public func didLostConnection(error: Error, from client: CometdClientContract) {
log.zp.error("ClientHelper lost connection")
if wasConnected {
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + .seconds(automaticReconnectionDelay)) { [weak self] in
self?.connect()
}
}
delegate?.onConnectionBroken(self)
delegate?.onConnectionBroken(self, error: ClientHelperError.connectionBroken)
}

public func didSubscribeToChannel(channel: String, from client: CometdClientContract) {
Expand All @@ -361,9 +345,9 @@ extension ClientHelper: CometdClientDelegate {
delegate?.onDidUnsubscribeFromChannel(self, channel: channel)
}

public func subscriptionFailedWithError(error: SubscriptionError, from client: CometdClientContract) {
public func subscriptionFailedWithError(error: Error, from client: CometdClientContract) {
log.zp.error("ClientHelper Subscription failed")
delegate?.onSubscriptionFailedWithError(self, error: error)
delegate?.onSubscriptionFailedWithError(self, error: ClientHelperError.subscription)
}

public func didWriteError(error: Error, from client: CometdClientContract) {
Expand Down
18 changes: 10 additions & 8 deletions Sources/ZetaPushNetwork/Client/ClientHelperDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,27 @@ import Foundation

// MARK: CometdClientDelegate
public protocol ClientHelperDelegate: class {
func onConnectionFailed(_ client: ClientHelper, error: Error)
func onConnectionEstablished(_ client: ClientHelper)
func onConnectionBroken(_ client: ClientHelper)
func onConnectionClosed(_ client: ClientHelper)
func onConnectionBroken(_ client: ClientHelper, error: Error)
func onConnectionClosed(_ client: ClientHelper, error: Error?)
func onConnectionClosedAdviceReconnect(_ client: ClientHelper)
func onSuccessfulHandshake(_ client: ClientHelper)
func onFailedHandshake(_ client: ClientHelper)
func onFailedHandshake(_ client: ClientHelper, error: Error)
func onDidSubscribeToChannel(_ client: ClientHelper, channel: String)
func onDidUnsubscribeFromChannel(_ client: ClientHelper, channel: String)
func onSubscriptionFailedWithError(_ client: ClientHelper, error: SubscriptionError)
func onSubscriptionFailedWithError(_ client: ClientHelper, error: Error)
}

public extension ClientHelperDelegate {
func onConnectionFailed(_ client: ClientHelper, error: Error) { }
func onConnectionEstablished(_ client: ClientHelper) { }
func onConnectionBroken(_ client: ClientHelper) { }
func onConnectionClosed(_ client: ClientHelper) { }
func onConnectionBroken(_ client: ClientHelper, error: Error) { }
func onConnectionClosed(_ client: ClientHelper, error: Error?) { }
func onConnectionClosedAdviceReconnect(_ client: ClientHelper) { }
func onSuccessfulHandshake(_ client: ClientHelper) { }
func onFailedHandshake(_ client: ClientHelper) { }
func onFailedHandshake(_ client: ClientHelper, error: Error) { }
func onDidSubscribeToChannel(_ client: ClientHelper, channel: String) { }
func onDidUnsubscribeFromChannel(_ client: ClientHelper, channel: String) { }
func onSubscriptionFailedWithError(_ client: ClientHelper, error: SubscriptionError) { }
func onSubscriptionFailedWithError(_ client: ClientHelper, error: Error) { }
}
15 changes: 15 additions & 0 deletions Sources/ZetaPushNetwork/Client/ClientHelperError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// ClientHelperError.swift
//
//
// Created by Anthony Guiguen on 22/07/2020.
//

import Foundation
import CometDClient

public typealias HandshakeError = CometDClient.HandshakeError

public enum ClientHelperError: Error {
case connectionFailed, connectionBroken, connectionClosed, handshakeFailed(reason: HandshakeError?), subscription
}
80 changes: 80 additions & 0 deletions Sources/ZetaPushNetwork/Client/Server/ServerRemoteDataSource.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//
// ServerRemoteDataSource.swift
//
//
// Created by Anthony Guiguen on 22/07/2020.
//

import Foundation
import UIKit

public struct ServerConfiguration {
var serverUrl: String
let sandboxId: String
var timeout: TimeInterval
}

class ServerRemoteDataSource {

// MARK: Properties
private let url: URL?
private let session: URLSession!
private var task: URLSessionDataTask?
private weak var recorder: ZetapushNetworkRecorder?

// MARK: Lifecycle
init(configuration: ServerConfiguration, recorder: ZetapushNetworkRecorder?) {
self.url = URL(string: configuration.serverUrl)?.appendingPathComponent(configuration.sandboxId)
self.recorder = recorder

let timeout = configuration.timeout
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = timeout
configuration.timeoutIntervalForResource = timeout * 3

self.session = URLSession(configuration: configuration)
}

// MARK: Methods
func fetchServersURLs(callback: @escaping (Result<[String], Error>) -> Void) {
guard let url = url, UIApplication.shared.canOpenURL(url) else {
let error: ServerRemoteDataSourceError = .canNotOpenURL(url: self.url?.absoluteString ?? "")
recorder?.record(error: error.toNSError())
callback(.failure(error))
return
}
task?.cancel()

task = session.dataTask(with: url) { [weak self] data, response, error in
defer { self?.task = nil }

if let error = error {
self?.recorder?.record(error: error as NSError)
callback(.failure(error))
} else if let response = response as? HTTPURLResponse, response.statusCode != 200 {
let error: ServerRemoteDataSourceError = .response(response: response)
self?.recorder?.record(error: error.toNSError())
callback(.failure(error))
} else if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
if let servers = json?["servers"] as? [String] {
callback(.success(servers))
} else {
let error: ServerRemoteDataSourceError = .serversNotFound
self?.recorder?.record(error: error.toNSError())
callback(.failure(error))
}
} catch let error {
self?.recorder?.record(error: error as NSError)
callback(.failure(error))
}
} else {
let error: ServerRemoteDataSourceError = .unknown
self?.recorder?.record(error: error.toNSError())
callback(.failure(error))
}
}
task?.resume()
}
}
Loading

0 comments on commit 78e9526

Please sign in to comment.