From 4564aebec19404a03fd761968821444f989ef713 Mon Sep 17 00:00:00 2001 From: Erik Little Date: Fri, 30 Mar 2018 14:16:54 -0400 Subject: [PATCH] Add way to skip binary inspection. Still a WIP. ACKs still don't have a way to bypass --- .../project.pbxproj | 4 + Source/SocketIO/Ack/SocketAckEmitter.swift | 7 +- Source/SocketIO/Client/SocketBinaryView.swift | 106 ++++++++++++++++++ Source/SocketIO/Client/SocketIOClient.swift | 8 +- Source/SocketIO/Parse/SocketPacket.swift | 12 +- 5 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 Source/SocketIO/Client/SocketBinaryView.swift diff --git a/Socket.IO-Client-Swift.xcodeproj/project.pbxproj b/Socket.IO-Client-Swift.xcodeproj/project.pbxproj index 0157206..c7f9eb4 100644 --- a/Socket.IO-Client-Swift.xcodeproj/project.pbxproj +++ b/Socket.IO-Client-Swift.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 1C6572803D7E252A77A86E5F /* SocketManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C65763817782DFAC67BE05C /* SocketManager.swift */; }; + 1C6573B22DC9423CDFC32F05 /* SocketBinaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C657533E849FC3E4342C602 /* SocketBinaryView.swift */; }; 1C657FBB3F670261780FD72E /* SocketManagerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C6574AF9687A213814753E4 /* SocketManagerSpec.swift */; }; 1C686BE21F869AFD007D8627 /* SocketIOClientConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C686BD21F869AF1007D8627 /* SocketIOClientConfigurationTest.swift */; }; 1C686BE31F869AFD007D8627 /* SocketEngineTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C686BD31F869AF1007D8627 /* SocketEngineTest.swift */; }; @@ -61,6 +62,7 @@ /* Begin PBXFileReference section */ 1C6574AF9687A213814753E4 /* SocketManagerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketManagerSpec.swift; sourceTree = ""; }; + 1C657533E849FC3E4342C602 /* SocketBinaryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketBinaryView.swift; sourceTree = ""; }; 1C65763817782DFAC67BE05C /* SocketManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocketManager.swift; sourceTree = ""; }; 1C686BD21F869AF1007D8627 /* SocketIOClientConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketIOClientConfigurationTest.swift; sourceTree = ""; }; 1C686BD31F869AF1007D8627 /* SocketEngineTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocketEngineTest.swift; sourceTree = ""; }; @@ -300,6 +302,7 @@ DD52B078DB0A3C3D1BB507CD /* SocketIOClientOption.swift */, DD52B1D9BC4AE46D38D827DE /* SocketIOStatus.swift */, DD52B57FFEE8560CFFD793B3 /* SocketIOClientConfiguration.swift */, + 1C657533E849FC3E4342C602 /* SocketBinaryView.swift */, ); name = Client; path = Source/SocketIO/Client; @@ -480,6 +483,7 @@ DD52B9412F660F828B683422 /* SocketParsable.swift in Sources */, 1C6572803D7E252A77A86E5F /* SocketManager.swift in Sources */, 1C657FBB3F670261780FD72E /* SocketManagerSpec.swift in Sources */, + 1C6573B22DC9423CDFC32F05 /* SocketBinaryView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Source/SocketIO/Ack/SocketAckEmitter.swift b/Source/SocketIO/Ack/SocketAckEmitter.swift index a7c80be..274db9f 100644 --- a/Source/SocketIO/Ack/SocketAckEmitter.swift +++ b/Source/SocketIO/Ack/SocketAckEmitter.swift @@ -91,13 +91,16 @@ public final class SocketAckEmitter : NSObject { /// ``` public final class OnAckCallback : NSObject { private let ackNumber: Int + private let binary: Bool private let items: [Any] + private weak var socket: SocketIOClient? - init(ackNumber: Int, items: [Any], socket: SocketIOClient) { + init(ackNumber: Int, items: [Any], socket: SocketIOClient, binary: Bool = true) { self.ackNumber = ackNumber self.items = items self.socket = socket + self.binary = binary } deinit { @@ -116,7 +119,7 @@ public final class OnAckCallback : NSObject { guard let socket = self.socket, ackNumber != -1 else { return } socket.ackHandlers.addAck(ackNumber, callback: callback) - socket.emit(items, ack: ackNumber) + socket.emit(items, ack: ackNumber, binary: binary) guard seconds != 0 else { return } diff --git a/Source/SocketIO/Client/SocketBinaryView.swift b/Source/SocketIO/Client/SocketBinaryView.swift new file mode 100644 index 0000000..abc8755 --- /dev/null +++ b/Source/SocketIO/Client/SocketBinaryView.swift @@ -0,0 +1,106 @@ +// +// Created by Erik Little on 3/30/18. +// + +import Foundation + +/// Class that gives a backwards compatible way to cause an emit not to recursively check for Data objects. +/// +/// Usage: +/// ```swift +/// socket.binary(false).emit("myEvent", myObject) +/// ``` +public final class SocketBinaryView : NSObject { + private unowned let socket: SocketIOClient + private let binary: Bool + + init(socket: SocketIOClient, binary: Bool) { + self.socket = socket + self.binary = binary + } + + /// Send an event to the server, with optional data items. + /// + /// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error` + /// will be emitted. The structure of the error data is `[eventName, items, theError]` + /// + /// - parameter event: The event to send. + /// - parameter items: The items to send with this event. May be left out. + open func emit(_ event: String, _ items: SocketData...) { + do { + try emit(event, with: items.map({ try $0.socketRepresentation() })) + } catch let err { + DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)", + type: "SocketIOClient") + + socket.handleClientEvent(.error, data: [event, items, err]) + } + } + + /// Same as emit, but meant for Objective-C + /// + /// - parameter event: The event to send. + /// - parameter items: The items to send with this event. Send an empty array to send no data. + @objc + open func emit(_ event: String, with items: [Any]) { + guard socket.status == .connected else { + socket.handleClientEvent(.error, data: ["Tried emitting \(event) when not connected"]) + return + } + + socket.emit([event] + items, binary: binary) + } + + /// Sends a message to the server, requesting an ack. + /// + /// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack. + /// Check that your server's api will ack the event being sent. + /// + /// If an error occurs trying to transform `items` into their socket representation, a `SocketClientEvent.error` + /// will be emitted. The structure of the error data is `[eventName, items, theError]` + /// + /// Example: + /// + /// ```swift + /// socket.emitWithAck("myEvent", 1).timingOut(after: 1) {data in + /// ... + /// } + /// ``` + /// + /// - parameter event: The event to send. + /// - parameter items: The items to send with this event. May be left out. + /// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent. + open func emitWithAck(_ event: String, _ items: SocketData...) -> OnAckCallback { + do { + return emitWithAck(event, with: try items.map({ try $0.socketRepresentation() })) + } catch let err { + DefaultSocketLogger.Logger.error("Error creating socketRepresentation for emit: \(event), \(items)", + type: "SocketIOClient") + + socket.handleClientEvent(.error, data: [event, items, err]) + + return OnAckCallback(ackNumber: -1, items: [], socket: socket) + } + } + + /// Same as emitWithAck, but for Objective-C + /// + /// **NOTE**: It is up to the server send an ack back, just calling this method does not mean the server will ack. + /// Check that your server's api will ack the event being sent. + /// + /// Example: + /// + /// ```swift + /// socket.emitWithAck("myEvent", with: [1]).timingOut(after: 1) {data in + /// ... + /// } + /// ``` + /// + /// - parameter event: The event to send. + /// - parameter items: The items to send with this event. Use `[]` to send nothing. + /// - returns: An `OnAckCallback`. You must call the `timingOut(after:)` method before the event will be sent. + @objc + open func emitWithAck(_ event: String, with items: [Any]) -> OnAckCallback { + return socket.createOnAck([event] + items, binary: binary) + } +} diff --git a/Source/SocketIO/Client/SocketIOClient.swift b/Source/SocketIO/Client/SocketIOClient.swift index a8f12f4..c1b3629 100644 --- a/Source/SocketIO/Client/SocketIOClient.swift +++ b/Source/SocketIO/Client/SocketIOClient.swift @@ -148,7 +148,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { } } - private func createOnAck(_ items: [Any]) -> OnAckCallback { + func createOnAck(_ items: [Any], binary: Bool = true) -> OnAckCallback { currentAck += 1 return OnAckCallback(ackNumber: currentAck, items: items, socket: self) @@ -277,13 +277,13 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { return createOnAck([event] + items) } - func emit(_ data: [Any], ack: Int? = nil) { + func emit(_ data: [Any], ack: Int? = nil, binary: Bool = true) { guard status == .connected else { handleClientEvent(.error, data: ["Tried emitting when not connected"]) return } - let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false) + let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false, checkForBinary: binary) let str = packet.packetString DefaultSocketLogger.Logger.log("Emitting: \(str)", type: logType) @@ -300,7 +300,7 @@ open class SocketIOClient : NSObject, SocketIOClientSpec { open func emitAck(_ ack: Int, with items: [Any]) { guard status == .connected else { return } - let packet = SocketPacket.packetFromEmit(items, id: ack, nsp: nsp, ack: true) + let packet = SocketPacket.packetFromEmit(items, id: ack, nsp: nsp, ack: true, checkForBinary: true) let str = packet.packetString DefaultSocketLogger.Logger.log("Emitting Ack: \(str)", type: logType) diff --git a/Source/SocketIO/Parse/SocketPacket.swift b/Source/SocketIO/Parse/SocketPacket.swift index 28fbf35..4b316fc 100644 --- a/Source/SocketIO/Parse/SocketPacket.swift +++ b/Source/SocketIO/Parse/SocketPacket.swift @@ -200,11 +200,15 @@ extension SocketPacket { } } - static func packetFromEmit(_ items: [Any], id: Int, nsp: String, ack: Bool) -> SocketPacket { - let (parsedData, binary) = deconstructData(items) + static func packetFromEmit(_ items: [Any], id: Int, nsp: String, ack: Bool, checkForBinary: Bool = true) -> SocketPacket { + if checkForBinary { + let (parsedData, binary) = deconstructData(items) - return SocketPacket(type: findType(binary.count, ack: ack), data: parsedData, id: id, nsp: nsp, - binary: binary) + return SocketPacket(type: findType(binary.count, ack: ack), data: parsedData, id: id, nsp: nsp, + binary: binary) + } else { + return SocketPacket(type: findType(0, ack: ack), data: items, id: id, nsp: nsp) + } } }