Skip to content

Commit

Permalink
Merge pull request #204 from ruslandoga/support-serialiser-v2
Browse files Browse the repository at this point in the history
support v2 json serializer
  • Loading branch information
dsrees authored Nov 5, 2021
2 parents a2a0fba + aff2577 commit 8a4fcb5
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public class StarscreamTransport: NSObject, PhoenixTransport, WebSocketDelegate
}

public func send(data: Data) {
self.socket?.write(data: data)
self.socket?.write(string: String(data: data, encoding: .utf8)!)
}


Expand Down
8 changes: 4 additions & 4 deletions Sources/SwiftPhoenixClient/Defaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,22 @@ public class Defaults {
public static let rejoinSteppedBackOff: (Int) -> TimeInterval = { tries in
return tries > 3 ? 10 : [1, 2, 5][tries - 1]
}


public static let vsn = "2.0.0"

/// Default encode function, utilizing JSONSerialization.data
public static let encode: ([String: Any]) -> Data = { json in
public static let encode: (Any) -> Data = { json in
return try! JSONSerialization
.data(withJSONObject: json,
options: JSONSerialization.WritingOptions())
}

/// Default decode function, utilizing JSONSerialization.jsonObject
public static let decode: (Data) -> [String: Any]? = { data in
public static let decode: (Data) -> Any? = { data in
guard
let json = try? JSONSerialization
.jsonObject(with: data,
options: JSONSerialization.ReadingOptions())
as? [String: Any]
else { return nil }
return json
}
Expand Down
19 changes: 9 additions & 10 deletions Sources/SwiftPhoenixClient/Message.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ public class Message {
public var status: String? {
return rawPayload["status"] as? String
}


init(ref: String = "",
topic: String = "",
Expand All @@ -66,16 +65,16 @@ public class Message {
self.rawPayload = payload
self.joinRef = joinRef
}
init?(json: [String: Any]) {
self.ref = json["ref"] as? String ?? ""
self.joinRef = json["join_ref"] as? String

init?(json: [Any?]) {
self.joinRef = json[0] as? String
self.ref = json[1] as? String ?? ""

if
let topic = json["topic"] as? String,
let event = json["event"] as? String,
let payload = json["payload"] as? Payload {

if
let topic = json[2] as? String,
let event = json[3] as? String,
let payload = json[4] as? Payload {
self.topic = topic
self.event = event
self.rawPayload = payload
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftPhoenixClient/PhoenixTransport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ public class URLSessionTransport: NSObject, PhoenixTransport, URLSessionWebSocke
}

public func send(data: Data) {
self.task?.send(.data(data)) { (error) in
self.task?.send(.string(String(data: data, encoding: .utf8)!)) { (error) in
// TODO: What is the behavior when an error occurs?
}
}
Expand Down
49 changes: 27 additions & 22 deletions Sources/SwiftPhoenixClient/Socket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,15 @@ public class Socket: PhoenixTransportDelegate {
/// The WebSocket transport. Default behavior is to provide a Starscream
/// WebSocket instance. Potentially allows changing WebSockets in future
private let transport: ((URL) -> PhoenixTransport)

/// Phoenix serializer version, defaults to "2.0.0"
public let vsn: String

/// Override to provide custom encoding of data before writing to the socket
public var encode: ([String: Any]) -> Data = Defaults.encode
public var encode: (Any) -> Data = Defaults.encode

/// Override to provide customd decoding of data read from the socket
public var decode: (Data) -> [String: Any]? = Defaults.decode
public var decode: (Data) -> Any? = Defaults.decode

/// Timeout to use when opening connections
public var timeout: TimeInterval = Defaults.timeoutInterval
Expand Down Expand Up @@ -164,29 +167,36 @@ public class Socket: PhoenixTransportDelegate {
//----------------------------------------------------------------------
@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
public convenience init(_ endPoint: String,
params: Payload? = nil) {
params: Payload? = nil,
vsn: String = Defaults.vsn) {
self.init(endPoint: endPoint,
transport: { url in return URLSessionTransport(url: url) },
paramsClosure: { params })
paramsClosure: { params },
vsn: vsn)
}

@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *)
public convenience init(_ endPoint: String,
paramsClosure: PayloadClosure?) {
paramsClosure: PayloadClosure?,
vsn: String = Defaults.vsn) {
self.init(endPoint: endPoint,
transport: { url in return URLSessionTransport(url: url) },
paramsClosure: paramsClosure)
paramsClosure: paramsClosure,
vsn: vsn)
}


public init(endPoint: String,
transport: @escaping ((URL) -> PhoenixTransport),
paramsClosure: PayloadClosure? = nil) {
paramsClosure: PayloadClosure? = nil,
vsn: String = Defaults.vsn) {
self.transport = transport
self.paramsClosure = paramsClosure
self.endPoint = endPoint
self.vsn = vsn
self.endPointUrl = Socket.buildEndpointUrl(endpoint: endPoint,
paramsClosure: paramsClosure)
paramsClosure: paramsClosure,
vsn: vsn)

self.reconnectTimer = TimeoutTimer()
self.reconnectTimer.callback.delegate(to: self) { (self) in
Expand Down Expand Up @@ -235,7 +245,8 @@ public class Socket: PhoenixTransportDelegate {
// We need to build this right before attempting to connect as the
// parameters could be built upon demand and change over time
self.endPointUrl = Socket.buildEndpointUrl(endpoint: self.endPoint,
paramsClosure: self.paramsClosure)
paramsClosure: self.paramsClosure,
vsn: vsn)

self.connection = self.transport(self.endPointUrl)
self.connection?.delegate = self
Expand Down Expand Up @@ -523,15 +534,7 @@ public class Socket: PhoenixTransportDelegate {
joinRef: String? = nil) {

let callback: (() throws -> ()) = {
var body: [String: Any] = [
"topic": topic,
"event": event,
"payload": payload
]

if let safeRef = ref { body["ref"] = safeRef }
if let safeJoinRef = joinRef { body["join_ref"] = safeJoinRef}

let body: [Any?] = [joinRef, ref, topic, event, payload]
let data = self.encode(body)

self.logItems("push", "Sending \(String(data: data, encoding: String.Encoding.utf8) ?? "")" )
Expand Down Expand Up @@ -615,7 +618,7 @@ public class Socket: PhoenixTransportDelegate {

guard
let data = rawMessage.data(using: String.Encoding.utf8),
let json = self.decode(data),
let json = decode(data) as? [Any?],
let message = Message(json: json)
else {
self.logItems("receive: Unable to parse JSON: \(rawMessage)")
Expand Down Expand Up @@ -660,7 +663,7 @@ public class Socket: PhoenixTransportDelegate {
}

/// Builds a fully qualified socket `URL` from `endPoint` and `params`.
internal static func buildEndpointUrl(endpoint: String, paramsClosure params: PayloadClosure?) -> URL {
internal static func buildEndpointUrl(endpoint: String, paramsClosure params: PayloadClosure?, vsn: String) -> URL {
guard
let url = URL(string: endpoint),
var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false)
Expand All @@ -678,11 +681,13 @@ public class Socket: PhoenixTransportDelegate {

}

urlComponents.queryItems = [URLQueryItem(name: "vsn", value: vsn)]

// If there are parameters, append them to the URL
if let params = params?() {
urlComponents.queryItems = params.map {
urlComponents.queryItems?.append(contentsOf: params.map {
URLQueryItem(name: $0.key, value: String(describing: $0.value))
}
})
}

guard let qualifiedUrl = urlComponents.url
Expand Down
3 changes: 1 addition & 2 deletions Tests/Helpers/TestHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,11 @@ enum TestError: Error {
case stub
}

func toWebSocketText(data: [String: Any]) -> String {
func toWebSocketText(data: [Any?]) -> String {
let encoded = Defaults.encode(data)
return String(decoding: encoded, as: UTF8.self)
}


/// Transforms two Dictionaries into NSDictionaries so they can be conpared
func transform(_ lhs: [AnyHashable: Any],
and rhs: [AnyHashable: Any]) -> (lhs: NSDictionary, rhs: NSDictionary) {
Expand Down
8 changes: 4 additions & 4 deletions Tests/Mocks/MockableClass.generated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -585,16 +585,16 @@ class SocketMock: Socket {
set(value) { underlyingEndPointUrl = value }
}
var underlyingEndPointUrl: (URL)!
override var encode: ([String: Any]) -> Data {
override var encode: (Any) -> Data {
get { return underlyingEncode }
set(value) { underlyingEncode = value }
}
var underlyingEncode: (([String: Any]) -> Data)!
override var decode: (Data) -> [String: Any]? {
var underlyingEncode: ((Any) -> Data)!
override var decode: (Data) -> Any? {
get { return underlyingDecode }
set(value) { underlyingDecode = value }
}
var underlyingDecode: ((Data) -> [String: Any]?)!
var underlyingDecode: ((Data) -> Any?)!
override var timeout: TimeInterval {
get { return underlyingTimeout }
set(value) { underlyingTimeout = value }
Expand Down
18 changes: 4 additions & 14 deletions Tests/SwiftPhoenixClientTests/DefaultSerializerSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,13 @@ import Nimble
class DefaultSerializerSpec: QuickSpec {

override func spec() {


describe("encode and decode") {
describe("encode and decode message") {
it("converts dictionary to Data and back to Message", closure: {
let body: [String: Any] = [
"ref": "ref",
"join_ref": "join_ref",
"topic": "topic",
"event": "event",
"payload": ["user_id": "abc123"]
]


let body: [Any] = ["join_ref", "ref", "topic", "event", ["user_id": "abc123"]]
let data = Defaults.encode(body)
expect(data).toNot(beNil())
expect(String(data: data, encoding: .utf8)).to(equal("[\"join_ref\",\"ref\",\"topic\",\"event\",{\"user_id\":\"abc123\"}]"))

let json = Defaults.decode(data)
let json = Defaults.decode(data) as? [Any]

let message = Message(json: json!)
expect(message?.ref).to(equal("ref"))
Expand Down
28 changes: 4 additions & 24 deletions Tests/SwiftPhoenixClientTests/MessageSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,14 @@ import Nimble
class MessageSpec: QuickSpec {

override func spec() {

describe("json parsing") {

it("parses a normal message") {
let json: [String: Any] = [
"event": "update",
"payload": [
"user": "James S.",
"message": "This is a test"
],
"ref": "6",
"topic": "my-topic"
]
let json: [Any] = ["2", "6", "my-topic", "update", ["user": "James S.", "message": "This is a test"]]

let message = Message(json: json)
expect(message?.ref).to(equal("6"))
expect(message?.joinRef).to(beNil())
expect(message?.joinRef).to(equal("2"))
expect(message?.topic).to(equal("my-topic"))
expect(message?.event).to(equal("update"))
expect(message?.payload["user"] as? String).to(equal("James S."))
Expand All @@ -39,22 +30,11 @@ class MessageSpec: QuickSpec {
}

it("parses a reply") {
let json: [String: Any] = [
"event": "phx_reply",
"payload": [
"response": [
"user": "James S.",
"message": "This is a test"
],
"status": "ok"
],
"ref": "6",
"topic": "my-topic"
]
let json: [Any] = ["2", "6", "my-topic", "phx_reply", ["response": ["user": "James S.", "message": "This is a test"], "status": "ok"]]

let message = Message(json: json)
expect(message?.ref).to(equal("6"))
expect(message?.joinRef).to(beNil())
expect(message?.joinRef).to(equal("2"))
expect(message?.topic).to(equal("my-topic"))
expect(message?.event).to(equal("phx_reply"))
expect(message?.payload["user"] as? String).to(equal("James S."))
Expand Down
Loading

0 comments on commit 8a4fcb5

Please sign in to comment.