start work on adding polling

This commit is contained in:
Erik 2015-03-03 20:53:57 -05:00
parent 761623a0f8
commit 8bebc3c159
2 changed files with 207 additions and 5 deletions

190
SwiftIO/SocketEngine.swift Normal file
View File

@ -0,0 +1,190 @@
//
// SocketEngine.swift
// Socket.IO-Swift
//
// Created by Erik Little on 3/3/15.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
private enum PacketType: String {
case OPEN = "0"
case CLOSE = "1"
case PING = "2"
case PONG = "3"
case MESSAGE = "4"
case UPGRADE = "5"
case NOOP = "6"
}
class SocketEngine: NSObject, SRWebSocketDelegate {
unowned let client:SocketIOClient
private var pingTimer:NSTimer?
private let pollingQueue = NSOperationQueue()
private var _polling = true
private var _websocket = false
private var websocketConnected = false
var pingInterval:Int?
var polling:Bool {
return self._polling
}
var sid = ""
var websocket:Bool {
return self._websocket
}
var ws:SRWebSocket?
init(client:SocketIOClient) {
self.client = client
}
func open(opts:[String: AnyObject]? = nil) {
var url:String
var urlPolling:String
var urlWebSocket:String
if self.client.secure {
url = "\(self.client.socketURL)/socket.io/?transport="
urlPolling = "https://" + url + "polling"
urlWebSocket = "wss://" + url + "websocket"
} else {
url = "\(self.client.socketURL)/socket.io/?transport="
urlPolling = "http://" + url + "polling"
urlWebSocket = "ws://" + url + "websocket"
}
let reqPolling = NSURLRequest(URL: NSURL(string: urlPolling)!)
NSURLConnection.sendAsynchronousRequest(reqPolling, queue: self.pollingQueue) {[weak self] res, data, err in
var err:NSError?
if self == nil || err != nil || data == nil {
println("Error")
println(err)
exit(1)
}
let sub = data.subdataWithRange(NSMakeRange(5, data.length - 5))
if let json = NSJSONSerialization.JSONObjectWithData(sub,
options: NSJSONReadingOptions.AllowFragments, error: &err) as? NSDictionary {
println(json)
if let sid = json["sid"] as? String {
self?.sid = sid
self?.ws = SRWebSocket(URL: NSURL(string: urlWebSocket + "&sid=\(self!.sid)")!)
self?.ws?.delegate = self
self?.ws?.open()
} else {
NSLog("Error handshaking")
return
}
if let pingInterval = json["pingInterval"] as? Int {
self?.pingInterval = pingInterval / 1000
}
}
}
}
func handlePollingResponse(str:String) {
// TODO add polling
}
func parseWebSocketMessage(message:AnyObject?) {
if !(message is String) {
return
}
var strMessage = RegexMutable(message as String)
// We should upgrade
if strMessage == "3probe" {
self.upgradeTransport()
return
}
let type = strMessage["(\\d)"].matches()[0]
if type != PacketType.MESSAGE.rawValue {
// TODO Handle other packets
return
}
}
func probeWebSocket() {
if self.websocketConnected {
self.ws?.send("2probe")
}
}
func sendPing() {
if self.websocketConnected {
self.ws?.send(PacketType.PING.rawValue)
}
}
// Starts the ping timer
private func startPingTimer() {
if self.pingInterval == nil {
return
}
dispatch_async(dispatch_get_main_queue()) {
self.pingTimer = NSTimer.scheduledTimerWithTimeInterval(NSTimeInterval(self.pingInterval!), target: self,
selector: Selector("sendPing"), userInfo: nil, repeats: true)
}
}
private func upgradeTransport() {
if self.websocketConnected {
self.ws?.send(PacketType.UPGRADE.rawValue)
}
}
// Called when a message is recieved
func webSocket(webSocket:SRWebSocket!, didReceiveMessage message:AnyObject?) {
// println(message)
self.parseWebSocketMessage(message)
}
// Called when the socket is opened
func webSocketDidOpen(webSocket:SRWebSocket!) {
println("socket opened")
self.startPingTimer()
self.websocketConnected = true
self.probeWebSocket()
}
// Called when the socket is closed
func webSocket(webSocket:SRWebSocket!, didCloseWithCode code:Int, reason:String!, wasClean:Bool) {
println("socket closed")
self.pingTimer?.invalidate()
self.websocketConnected = false
}
// Called when an error occurs.
func webSocket(webSocket:SRWebSocket!, didFailWithError error:NSError!) {
self.pingTimer?.invalidate()
self.websocketConnected = false
}
}

View File

@ -25,6 +25,7 @@
import Foundation import Foundation
class SocketIOClient: NSObject, SRWebSocketDelegate { class SocketIOClient: NSObject, SRWebSocketDelegate {
let engine:SocketEngine!
let socketURL:NSMutableString! let socketURL:NSMutableString!
let ackQueue = dispatch_queue_create("ackQueue".cStringUsingEncoding(NSUTF8StringEncoding), let ackQueue = dispatch_queue_create("ackQueue".cStringUsingEncoding(NSUTF8StringEncoding),
DISPATCH_QUEUE_SERIAL) DISPATCH_QUEUE_SERIAL)
@ -39,7 +40,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
private var lastSocketMessage:SocketEvent? private var lastSocketMessage:SocketEvent?
private var paramConnect = false private var paramConnect = false
private var pingTimer:NSTimer! private var pingTimer:NSTimer!
private var secure = false private var _secure = false
var closed = false var closed = false
var connected = false var connected = false
var connecting = false var connecting = false
@ -49,13 +50,16 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
var reconnecting = false var reconnecting = false
var reconnectAttempts = -1 var reconnectAttempts = -1
var reconnectWait = 10 var reconnectWait = 10
var secure:Bool {
return self._secure
}
var sid:String? var sid:String?
init(socketURL:String, opts:[String: AnyObject]? = nil) { init(socketURL:String, opts:[String: AnyObject]? = nil) {
var mutURL = RegexMutable(socketURL) var mutURL = RegexMutable(socketURL)
if mutURL["https://"].matches().count != 0 { if mutURL["https://"].matches().count != 0 {
self.secure = true self._secure = true
} }
mutURL = mutURL["http://"] ~= "" mutURL = mutURL["http://"] ~= ""
@ -81,6 +85,10 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
self.nsp = nsp self.nsp = nsp
} }
} }
super.init()
self.engine = SocketEngine(client: self)
} }
// Closes the socket // Closes the socket
@ -144,7 +152,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
} }
private func createConnectURL() -> String { private func createConnectURL() -> String {
if self.secure { if self._secure {
return "wss://\(self.socketURL)/socket.io/?transport=websocket" return "wss://\(self.socketURL)/socket.io/?transport=websocket"
} else { } else {
return "ws://\(self.socketURL)/socket.io/?transport=websocket" return "ws://\(self.socketURL)/socket.io/?transport=websocket"
@ -313,7 +321,7 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
} }
} }
private func joinNamespace() { func joinNamespace() {
if self.nsp != nil { if self.nsp != nil {
self.io?.send("40/\(self.nsp!)") self.io?.send("40/\(self.nsp!)")
} }
@ -891,4 +899,8 @@ class SocketIOClient: NSObject, SRWebSocketDelegate {
self.tryReconnect(triesLeft: self.reconnectAttempts) self.tryReconnect(triesLeft: self.reconnectAttempts)
} }
} }
func testEngine() {
self.engine.open()
}
} }