7 Commits

Author SHA1 Message Date
Darcy Laycock 7a19c23e50 More docs cleanup. 2016-04-04 10:52:43 +10:00
Darcy Laycock f8b0efd58f Updated license. 2016-01-06 17:58:50 +11:00
Darcy Laycock 0d4e21c42a Update to old license. 2016-01-06 17:58:28 +11:00
Darcy Laycock b60433b0cd Cleanup old / unused files. 2016-01-06 17:58:08 +11:00
Haris Amin c34b561e69 No more optional FayeClientDelegate functions! Hurray for protocol extensions :) 2015-12-07 12:32:02 -05:00
Haris Amin e182eb42d1 Swift 2 upgrade. Also upgraded SwiftyJSON and Starscream Websockets to latest version 2015-12-07 12:02:35 -05:00
Haris Amin ac3130fc70 Making sure unsubscribing from channel works. Closes #8 2015-06-11 01:15:36 -04:00
17 changed files with 99 additions and 3056 deletions
+94 -80
View File
@@ -11,13 +11,13 @@ import Foundation
// MARK: Custom Extensions
extension String {
subscript (i: Int) -> String {
return String(Array(self)[i])
return String(Array(self.characters)[i])
}
}
// MARK: BayuexChannel Messages
enum BayeuxChannel : Printable {
enum BayeuxChannel : CustomStringConvertible {
case HANDSHAKE_CHANNEL;
case CONNECT_CHANNEL;
case DISCONNECT_CHANNEL;
@@ -41,17 +41,29 @@ enum BayeuxChannel : Printable {
typealias ChannelSubscriptionBlock = (NSDictionary) -> Void
// MARK: FayeClientDelegate Protocol
@objc protocol FayeClientDelegate{
optional func messageReceived(messageDict: NSDictionary, channel: String)
optional func connectedToServer()
optional func disconnectedFromServer()
optional func connectionFailed()
optional func didSubscribeToChannel(channel:String)
optional func didUnsubscribeFromChannel(channel:String)
optional func subscriptionFailedWithError(error:String)
optional func fayeClientError(error:NSError)
protocol FayeClientDelegate: NSObjectProtocol{
func messageReceived(messageDict: NSDictionary, channel: String)
func connectedToServer()
func disconnectedFromServer()
func connectionFailed()
func didSubscribeToChannel(channel:String)
func didUnsubscribeFromChannel(channel:String)
func subscriptionFailedWithError(error:String)
func fayeClientError(error:NSError)
}
extension FayeClientDelegate {
func messageReceived(messageDict: NSDictionary, channel: String){}
func connectedToServer(){}
func disconnectedFromServer(){}
func connectionFailed(){}
func didSubscribeToChannel(channel:String){}
func didUnsubscribeFromChannel(channel:String){}
func subscriptionFailedWithError(error:String){}
func fayeClientError(error:NSError){}
}
protocol Transport{
func writeString(aString:String)
func openConnection()
@@ -102,29 +114,29 @@ public class WebsocketTransport: Transport, WebSocketDelegate {
// MARK: Websocket Delegate
public func websocketDidConnect(socket: WebSocket) {
println("websocket is connected")
print("websocket is connected")
self.delegate?.didConnect()
}
public func websocketDidDisconnect(socket: WebSocket, error: NSError?) {
if(error == nil){
println("websocket lost connection!")
print("websocket lost connection!")
self.delegate?.didDisconnect()
}else{
println("websocket is disconnected: \(error!.localizedDescription)")
print("websocket is disconnected: \(error!.localizedDescription)")
self.delegate?.didFailConenction(error)
}
}
public func websocketDidReceiveMessage(socket: WebSocket, text: String) {
println("got some text: \(text)")
print("got some text: \(text)")
self.delegate?.didReceiveMessage(text)
}
// MARK: TODO
public func websocketDidReceiveData(socket: WebSocket, data: NSData) {
println("got some data: \(data.length)")
print("got some data: \(data.length)")
//self.socket.writeData(data)
}
}
@@ -206,6 +218,8 @@ class FayeClient : TransportDelegate {
self.queuedSubscriptions.removeObject(channel)
self.unsubscribe(channel)
self.channelSubscriptionBlocks[channel] = nil;
self.openSubscriptions.removeObject(channel)
self.pendingSubscriptions.removeObject(channel)
}
func isSubscribedToChannel(channel:String) -> (Bool){
@@ -219,38 +233,38 @@ class FayeClient : TransportDelegate {
// MARK: Transport Delegate
private extension FayeClient {
internal func didConnect() {
println("Transport websocket is connected")
extension FayeClient {
func didConnect() {
print("Transport websocket is connected")
self.connectionInitiated = false;
self.handshake()
}
internal func didDisconnect() {
println("Transport websocket lost connection!")
self.delegate?.disconnectedFromServer?()
func didDisconnect() {
print("Transport websocket lost connection!")
self.delegate?.disconnectedFromServer()
self.connectionInitiated = false
self.fayeConnected = false
}
internal func didFailConenction(error: NSError?) {
println("Transport websocket is disconnected: \(error!.localizedDescription)")
self.delegate?.connectionFailed?()
func didFailConenction(error: NSError?) {
print("Transport websocket is disconnected: \(error!.localizedDescription)")
self.delegate?.connectionFailed()
self.connectionInitiated = false
self.fayeConnected = false
}
internal func didWriteError(error: NSError?) {
func didWriteError(error: NSError?) {
if(error == nil){
println("Transport websocket write failed: ERROR IS NIL!")
print("Transport websocket write failed: ERROR IS NIL!")
}else{
println("Transport websocket write failed: \(error!.localizedDescription)")
self.delegate?.fayeClientError?(error!)
print("Transport websocket write failed: \(error!.localizedDescription)")
self.delegate?.fayeClientError(error!)
}
}
internal func didReceiveMessage(text: String) {
println("Transport got some text: \(text)")
func didReceiveMessage(text: String) {
print("Transport got some text: \(text)")
self.receive(text)
}
@@ -266,11 +280,11 @@ private extension FayeClient {
switch(channel)
{
case BayeuxChannel.HANDSHAKE_CHANNEL.description:
println("HANDSHAKE_CHANNEL")
print("HANDSHAKE_CHANNEL")
self.fayeClientId = messageDict["clientId"].stringValue
if(messageDict["successful"].int == 1){
self.delegate?.connectedToServer?()
self.delegate?.connectedToServer()
self.fayeConnected = true;
self.connect()
self.subscribeQueuedSubscriptions()
@@ -280,7 +294,7 @@ private extension FayeClient {
}
case BayeuxChannel.CONNECT_CHANNEL.description:
println("CONNECT_CHANNEL")
print("CONNECT_CHANNEL")
if(messageDict["successful"].int == 1){
self.fayeConnected = true;
self.connect()
@@ -288,16 +302,16 @@ private extension FayeClient {
// OOPS
}
case BayeuxChannel.DISCONNECT_CHANNEL.description:
println("DISCONNECT_CHANNEL")
print("DISCONNECT_CHANNEL")
if(messageDict["successful"].int == 1){
self.fayeConnected = false;
self.transport?.closeConnection()
self.delegate?.disconnectedFromServer?()
self.delegate?.disconnectedFromServer()
}else{
// OOPS
}
case BayeuxChannel.SUBSCRIBE_CHANNEL.description:
println("SUBSCRIBE_CHANNEL")
print("SUBSCRIBE_CHANNEL")
let success = messageJSON[0]["successful"].int
@@ -305,49 +319,49 @@ private extension FayeClient {
if let subscription = messageJSON[0]["subscription"].string{
self.pendingSubscriptions.removeObject(subscription)
self.openSubscriptions.addObject(subscription)
self.delegate?.didSubscribeToChannel?(subscription)
self.delegate?.didSubscribeToChannel(subscription)
}else{
println("Missing subscription for Subscribe")
print("Missing subscription for Subscribe")
}
}else{
// Subscribe Failed
if let error = messageJSON[0]["error"].string{
self.delegate?.subscriptionFailedWithError?(error)
self.delegate?.subscriptionFailedWithError(error)
}
}
case BayeuxChannel.UNSUBSCRIBE_CHANNEL.description:
println("UNSUBSCRIBE_CHANNEL")
print("UNSUBSCRIBE_CHANNEL")
if let subscription = messageJSON[0]["subscription"].string{
self.openSubscriptions.removeObject(subscription)
self.delegate?.didUnsubscribeFromChannel?(subscription)
self.delegate?.didUnsubscribeFromChannel(subscription)
}else{
println("Missing subscription for Unsubscribe")
print("Missing subscription for Unsubscribe")
}
default:
if(self.isSubscribedToChannel(channel)){
println("New Message on \(channel)")
print("New Message on \(channel)")
if(messageJSON[0]["data"] != JSON.nullJSON){
if(messageJSON[0]["data"] != JSON.null){
// Call channel subscription block if there is one
let data: AnyObject = messageJSON[0]["data"].object
if let channelBlock = self.channelSubscriptionBlocks[channel]{
channelBlock(data as! NSDictionary)
}else{
self.delegate?.messageReceived?(data as! NSDictionary, channel: channel)
self.delegate?.messageReceived(data as! NSDictionary, channel: channel)
}
}else{
println("For some reason data is nil, maybe double posting?!")
print("For some reason data is nil, maybe double posting?!")
}
}else{
println("weird channel")
print("weird channel")
}
}
}else{
println("Missing channel")
print("Missing channel")
}
}
@@ -361,7 +375,7 @@ private extension FayeClient {
// "minimumVersion": "1.0beta",
// "supportedConnectionTypes": ["long-polling", "callback-polling", "iframe", "websocket]
func handshake() {
var connTypes:NSArray = ["long-polling", "callback-polling", "iframe", "websocket"]
let connTypes:NSArray = ["long-polling", "callback-polling", "iframe", "websocket"]
var dict = [String: AnyObject]()
dict["channel"] = BayeuxChannel.HANDSHAKE_CHANNEL.description
dict["version"] = "1.0"
@@ -377,7 +391,7 @@ private extension FayeClient {
// "clientId": "Un1q31d3nt1f13r",
// "connectionType": "long-polling"
func connect(){
var dict:[String:AnyObject] = ["channel": BayeuxChannel.CONNECT_CHANNEL.description, "clientId": self.fayeClientId!, "connectionType": "websocket"]
let dict:[String:AnyObject] = ["channel": BayeuxChannel.CONNECT_CHANNEL.description, "clientId": self.fayeClientId!, "connectionType": "websocket"]
let string = JSONStringify(dict)
self.transport?.writeString(string)
@@ -387,7 +401,7 @@ private extension FayeClient {
// "channel": "/meta/disconnect",
// "clientId": "Un1q31d3nt1f13r"
func disconnect(){
var dict:[String:AnyObject] = ["channel": BayeuxChannel.DISCONNECT_CHANNEL.description, "clientId": self.fayeClientId!, "connectionType": "websocket"]
let dict:[String:AnyObject] = ["channel": BayeuxChannel.DISCONNECT_CHANNEL.description, "clientId": self.fayeClientId!, "connectionType": "websocket"]
let string = JSONStringify(dict)
self.transport?.writeString(string)
}
@@ -399,7 +413,7 @@ private extension FayeClient {
// "subscription": "/foo/**"
// }
func subscribe(channel:String){
var dict:[String:AnyObject] = ["channel": BayeuxChannel.SUBSCRIBE_CHANNEL.description, "clientId": self.fayeClientId!, "subscription": channel]
let dict:[String:AnyObject] = ["channel": BayeuxChannel.SUBSCRIBE_CHANNEL.description, "clientId": self.fayeClientId!, "subscription": channel]
let string = JSONStringify(dict)
self.transport?.writeString(string)
self.pendingSubscriptions.addObject(channel)
@@ -412,9 +426,11 @@ private extension FayeClient {
// "subscription": "/foo/**"
// }
func unsubscribe(channel:String){
var dict:[String:AnyObject] = ["channel": BayeuxChannel.UNSUBSCRIBE_CHANNEL.description, "clientId": self.fayeClientId!, "subscription": channel]
let string = JSONStringify(dict)
self.transport?.writeString(string)
if let clientId = self.fayeClientId {
let dict:[String:AnyObject] = ["channel": BayeuxChannel.UNSUBSCRIBE_CHANNEL.description, "clientId": clientId, "subscription": channel]
let string = JSONStringify(dict)
self.transport?.writeString(string)
}
}
// Bayeux Publish
@@ -426,10 +442,10 @@ private extension FayeClient {
// }
func publish(data:[String:AnyObject], channel:String){
if(self.fayeConnected == true){
var dict:[String:AnyObject] = ["channel": channel, "clientId": self.fayeClientId!, "id": self.nextMessageId(), "data": data]
let dict:[String:AnyObject] = ["channel": channel, "clientId": self.fayeClientId!, "id": self.nextMessageId(), "data": data]
var string = JSONStringify(dict)
println("THIS IS THE PUBSLISH STRING: \(string)")
let string = JSONStringify(dict)
print("THIS IS THE PUBSLISH STRING: \(string)")
self.transport?.writeString(string)
}else{
// Faye is not connected
@@ -453,21 +469,21 @@ private extension FayeClient {
func send(message: NSDictionary){
// Parse JSON
var writeError:NSError?
var jsonData:NSData = NSJSONSerialization.dataWithJSONObject(message, options:nil, error: &writeError)!
if(writeError == nil){
println("COuldn't parse json")
}else{
var jsonString:NSString = NSString(data: jsonData, encoding:NSUTF8StringEncoding)!
do {
let jsonData:NSData = try! NSJSONSerialization.dataWithJSONObject(message, options:[])
let jsonString:NSString = NSString(data: jsonData, encoding:NSUTF8StringEncoding)!
self.transport?.writeString(jsonString as String)
} catch let error as NSError {
print("[Send Message] Couldn't Parse JSON: \(error.localizedDescription)")
} catch {
print("[Send Message]: Unknown error")
}
}
func receive(message: String){
// Parse JSON
var jsonData = message.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
var json = JSON(data: jsonData!)
let jsonData = message.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
let json = JSON(data: jsonData!)
self.parseFayeMessage(json)
}
@@ -477,8 +493,8 @@ private extension FayeClient {
if(self.messageNumber >= UINT32_MAX){
messageNumber = 0
}
var str = "\(self.messageNumber)"
println("Original: \(str)")
let str = "\(self.messageNumber)"
print("Original: \(str)")
// UTF 8 str from original
// NSData! type returned (optional)
@@ -489,7 +505,7 @@ private extension FayeClient {
// Notice the unwrapping given the NSData! optional
// NSString! returned (optional)
let base64Encoded = utf8str?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
println("Encoded: \(base64Encoded)")
print("Encoded: \(base64Encoded)")
// Base64 Decode (go back the other way)
// Notice the unwrapping given the NSString! optional
@@ -498,22 +514,20 @@ private extension FayeClient {
// Convert back to a string
let base64Decoded = NSString(data: data!, encoding: NSUTF8StringEncoding)
println("Decoded: \(base64Decoded)")
print("Decoded: \(base64Decoded)")
return base64Decoded! as String
}
// JSON Helpers
func JSONStringify(jsonObj: AnyObject) -> String {
var e: NSError?
let jsonData: NSData! = NSJSONSerialization.dataWithJSONObject(
jsonObj,
options: NSJSONWritingOptions(0),
error: &e)
if e != nil {
return ""
} else {
do {
let jsonData:NSData = try! NSJSONSerialization.dataWithJSONObject(jsonObj, options:NSJSONWritingOptions(rawValue: 0))
return NSString(data: jsonData, encoding: NSUTF8StringEncoding)! as String
} catch let error as NSError {
print("[JSONStringify] Couldn't Parse JSON: \(error.localizedDescription)")
} catch {
return ""
}
}
}
@@ -1,434 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
AF021BFA19DC58FC0059EB60 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF021BF919DC58FC0059EB60 /* AppDelegate.swift */; };
AF021BFC19DC58FC0059EB60 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF021BFB19DC58FC0059EB60 /* ViewController.swift */; };
AF021BFF19DC58FC0059EB60 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AF021BFD19DC58FC0059EB60 /* Main.storyboard */; };
AF021C0119DC58FC0059EB60 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AF021C0019DC58FC0059EB60 /* Images.xcassets */; };
AF021C0419DC58FC0059EB60 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = AF021C0219DC58FC0059EB60 /* LaunchScreen.xib */; };
AF021C1019DC58FC0059EB60 /* FayeSwiftDemoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF021C0F19DC58FC0059EB60 /* FayeSwiftDemoTests.swift */; };
AF021C1B19DC591E0059EB60 /* FayeClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF021C1919DC591E0059EB60 /* FayeClient.swift */; };
AF021C2019DC5B7D0059EB60 /* Websocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF021C1E19DC5B7D0059EB60 /* Websocket.swift */; };
AF021C2119DC5B7D0059EB60 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF021C1F19DC5B7D0059EB60 /* SwiftyJSON.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
AF021C0A19DC58FC0059EB60 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = AF021BEC19DC58FC0059EB60 /* Project object */;
proxyType = 1;
remoteGlobalIDString = AF021BF319DC58FC0059EB60;
remoteInfo = FayeSwiftDemo;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
AF021BF419DC58FC0059EB60 /* FayeSwiftDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FayeSwiftDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
AF021BF819DC58FC0059EB60 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
AF021BF919DC58FC0059EB60 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
AF021BFB19DC58FC0059EB60 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
AF021BFE19DC58FC0059EB60 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
AF021C0019DC58FC0059EB60 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
AF021C0319DC58FC0059EB60 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
AF021C0919DC58FC0059EB60 /* FayeSwiftDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FayeSwiftDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
AF021C0E19DC58FC0059EB60 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
AF021C0F19DC58FC0059EB60 /* FayeSwiftDemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FayeSwiftDemoTests.swift; sourceTree = "<group>"; };
AF021C1919DC591E0059EB60 /* FayeClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FayeClient.swift; path = ../FayeClient.swift; sourceTree = "<group>"; };
AF021C1E19DC5B7D0059EB60 /* Websocket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Websocket.swift; path = ../lib/Websocket.swift; sourceTree = "<group>"; };
AF021C1F19DC5B7D0059EB60 /* SwiftyJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftyJSON.swift; path = ../lib/SwiftyJSON.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
AF021BF119DC58FC0059EB60 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
AF021C0619DC58FC0059EB60 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
AF021BEB19DC58FC0059EB60 = {
isa = PBXGroup;
children = (
AF021C1E19DC5B7D0059EB60 /* Websocket.swift */,
AF021C1F19DC5B7D0059EB60 /* SwiftyJSON.swift */,
AF021C1919DC591E0059EB60 /* FayeClient.swift */,
AF021BF619DC58FC0059EB60 /* FayeSwiftDemo */,
AF021C0C19DC58FC0059EB60 /* FayeSwiftDemoTests */,
AF021BF519DC58FC0059EB60 /* Products */,
);
sourceTree = "<group>";
};
AF021BF519DC58FC0059EB60 /* Products */ = {
isa = PBXGroup;
children = (
AF021BF419DC58FC0059EB60 /* FayeSwiftDemo.app */,
AF021C0919DC58FC0059EB60 /* FayeSwiftDemoTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
AF021BF619DC58FC0059EB60 /* FayeSwiftDemo */ = {
isa = PBXGroup;
children = (
AF021BF919DC58FC0059EB60 /* AppDelegate.swift */,
AF021BFB19DC58FC0059EB60 /* ViewController.swift */,
AF021BFD19DC58FC0059EB60 /* Main.storyboard */,
AF021C0019DC58FC0059EB60 /* Images.xcassets */,
AF021C0219DC58FC0059EB60 /* LaunchScreen.xib */,
AF021BF719DC58FC0059EB60 /* Supporting Files */,
);
path = FayeSwiftDemo;
sourceTree = "<group>";
};
AF021BF719DC58FC0059EB60 /* Supporting Files */ = {
isa = PBXGroup;
children = (
AF021BF819DC58FC0059EB60 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
AF021C0C19DC58FC0059EB60 /* FayeSwiftDemoTests */ = {
isa = PBXGroup;
children = (
AF021C0F19DC58FC0059EB60 /* FayeSwiftDemoTests.swift */,
AF021C0D19DC58FC0059EB60 /* Supporting Files */,
);
path = FayeSwiftDemoTests;
sourceTree = "<group>";
};
AF021C0D19DC58FC0059EB60 /* Supporting Files */ = {
isa = PBXGroup;
children = (
AF021C0E19DC58FC0059EB60 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
AF021BF319DC58FC0059EB60 /* FayeSwiftDemo */ = {
isa = PBXNativeTarget;
buildConfigurationList = AF021C1319DC58FC0059EB60 /* Build configuration list for PBXNativeTarget "FayeSwiftDemo" */;
buildPhases = (
AF021BF019DC58FC0059EB60 /* Sources */,
AF021BF119DC58FC0059EB60 /* Frameworks */,
AF021BF219DC58FC0059EB60 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = FayeSwiftDemo;
productName = FayeSwiftDemo;
productReference = AF021BF419DC58FC0059EB60 /* FayeSwiftDemo.app */;
productType = "com.apple.product-type.application";
};
AF021C0819DC58FC0059EB60 /* FayeSwiftDemoTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = AF021C1619DC58FC0059EB60 /* Build configuration list for PBXNativeTarget "FayeSwiftDemoTests" */;
buildPhases = (
AF021C0519DC58FC0059EB60 /* Sources */,
AF021C0619DC58FC0059EB60 /* Frameworks */,
AF021C0719DC58FC0059EB60 /* Resources */,
);
buildRules = (
);
dependencies = (
AF021C0B19DC58FC0059EB60 /* PBXTargetDependency */,
);
name = FayeSwiftDemoTests;
productName = FayeSwiftDemoTests;
productReference = AF021C0919DC58FC0059EB60 /* FayeSwiftDemoTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
AF021BEC19DC58FC0059EB60 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0600;
ORGANIZATIONNAME = "Haris Amin";
TargetAttributes = {
AF021BF319DC58FC0059EB60 = {
CreatedOnToolsVersion = 6.0.1;
};
AF021C0819DC58FC0059EB60 = {
CreatedOnToolsVersion = 6.0.1;
TestTargetID = AF021BF319DC58FC0059EB60;
};
};
};
buildConfigurationList = AF021BEF19DC58FC0059EB60 /* Build configuration list for PBXProject "FayeSwiftDemo" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = AF021BEB19DC58FC0059EB60;
productRefGroup = AF021BF519DC58FC0059EB60 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
AF021BF319DC58FC0059EB60 /* FayeSwiftDemo */,
AF021C0819DC58FC0059EB60 /* FayeSwiftDemoTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
AF021BF219DC58FC0059EB60 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
AF021BFF19DC58FC0059EB60 /* Main.storyboard in Resources */,
AF021C0419DC58FC0059EB60 /* LaunchScreen.xib in Resources */,
AF021C0119DC58FC0059EB60 /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
AF021C0719DC58FC0059EB60 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
AF021BF019DC58FC0059EB60 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
AF021BFC19DC58FC0059EB60 /* ViewController.swift in Sources */,
AF021C2019DC5B7D0059EB60 /* Websocket.swift in Sources */,
AF021BFA19DC58FC0059EB60 /* AppDelegate.swift in Sources */,
AF021C2119DC5B7D0059EB60 /* SwiftyJSON.swift in Sources */,
AF021C1B19DC591E0059EB60 /* FayeClient.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
AF021C0519DC58FC0059EB60 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
AF021C1019DC58FC0059EB60 /* FayeSwiftDemoTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
AF021C0B19DC58FC0059EB60 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = AF021BF319DC58FC0059EB60 /* FayeSwiftDemo */;
targetProxy = AF021C0A19DC58FC0059EB60 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
AF021BFD19DC58FC0059EB60 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
AF021BFE19DC58FC0059EB60 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
AF021C0219DC58FC0059EB60 /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
AF021C0319DC58FC0059EB60 /* Base */,
);
name = LaunchScreen.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
AF021C1119DC58FC0059EB60 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
AF021C1219DC58FC0059EB60 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
AF021C1419DC58FC0059EB60 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = FayeSwiftDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
AF021C1519DC58FC0059EB60 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = FayeSwiftDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
AF021C1719DC58FC0059EB60 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = FayeSwiftDemoTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FayeSwiftDemo.app/FayeSwiftDemo";
};
name = Debug;
};
AF021C1819DC58FC0059EB60 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
INFOPLIST_FILE = FayeSwiftDemoTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FayeSwiftDemo.app/FayeSwiftDemo";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
AF021BEF19DC58FC0059EB60 /* Build configuration list for PBXProject "FayeSwiftDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
AF021C1119DC58FC0059EB60 /* Debug */,
AF021C1219DC58FC0059EB60 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
AF021C1319DC58FC0059EB60 /* Build configuration list for PBXNativeTarget "FayeSwiftDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
AF021C1419DC58FC0059EB60 /* Debug */,
AF021C1519DC58FC0059EB60 /* Release */,
);
defaultConfigurationIsVisible = 0;
};
AF021C1619DC58FC0059EB60 /* Build configuration list for PBXNativeTarget "FayeSwiftDemoTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
AF021C1719DC58FC0059EB60 /* Debug */,
AF021C1819DC58FC0059EB60 /* Release */,
);
defaultConfigurationIsVisible = 0;
};
/* End XCConfigurationList section */
};
rootObject = AF021BEC19DC58FC0059EB60 /* Project object */;
}
@@ -1,46 +0,0 @@
//
// AppDelegate.swift
// FayeSwiftDemo
//
// Created by Haris Amin on 10/1/14.
// Copyright (c) 2014 Haris Amin. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
@@ -1,41 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2014 Haris Amin. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="FayeSwiftDemo" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>
@@ -1,59 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="vXZ-lx-hvc">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6238"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="ufC-wZ-h7g">
<objects>
<viewController id="vXZ-lx-hvc" customClass="ViewController" customModule="FayeSwiftDemo" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="jyV-Pf-zRb"/>
<viewControllerLayoutGuide type="bottom" id="2fi-mo-0CV"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="kh9-bI-dsS">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="A5l-SM-JaF">
<rect key="frame" x="178" y="176" width="244" height="30"/>
<constraints>
<constraint firstAttribute="width" constant="244" id="a2K-B4-uYz"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" returnKeyType="send"/>
<connections>
<outlet property="delegate" destination="vXZ-lx-hvc" id="2is-GC-Xhp"/>
</connections>
</textField>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tgX-Ab-r7g">
<rect key="frame" x="180" y="283" width="240" height="128"/>
<color key="backgroundColor" red="0.2039215714" green="0.28627452250000002" blue="0.36862745879999997" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="width" constant="240" id="pb6-Yk-ZTr"/>
</constraints>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="2fi-mo-0CV" firstAttribute="top" secondItem="tgX-Ab-r7g" secondAttribute="bottom" constant="189" id="7rd-Hn-jxT"/>
<constraint firstItem="A5l-SM-JaF" firstAttribute="top" secondItem="jyV-Pf-zRb" secondAttribute="bottom" constant="156" id="A1O-zM-am6"/>
<constraint firstItem="A5l-SM-JaF" firstAttribute="centerX" secondItem="tgX-Ab-r7g" secondAttribute="centerX" id="TSF-Nu-Xdo"/>
<constraint firstItem="tgX-Ab-r7g" firstAttribute="top" secondItem="A5l-SM-JaF" secondAttribute="bottom" constant="77" id="hKI-Ji-3F4"/>
<constraint firstItem="A5l-SM-JaF" firstAttribute="centerX" secondItem="kh9-bI-dsS" secondAttribute="centerX" id="nl1-i1-8kd"/>
</constraints>
</view>
<connections>
<outlet property="textField" destination="A5l-SM-JaF" id="BAk-ys-uXO"/>
<outlet property="textView" destination="tgX-Ab-r7g" id="TiA-OI-MNC"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="x5A-6p-PRh" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
@@ -1,38 +0,0 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
-40
View File
@@ -1,40 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>HarisAmin.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
@@ -1,76 +0,0 @@
//
// ViewController.swift
// FayeSwiftDemo
//
// Created by Haris Amin on 10/1/14.
// Copyright (c) 2014 Haris Amin. All rights reserved.
//
import UIKit
class ViewController: UIViewController, UITextFieldDelegate, FayeClientDelegate {
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var textView: UITextView!
let client:FayeClient = FayeClient(aFayeURLString: "ws://localhost:5222/faye", channel: "/cool")
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
client.delegate = self;
client.connectToServer()
let channelBlock:ChannelSubscriptionBlock = {(messageDict) -> Void in
let text: AnyObject? = messageDict["text"]
println("Here is the Block message: \(text)")
}
client.subscribeToChannel("/awesome", block: channelBlock)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
client.sendMessage(["text": textField.text], channel: "/cool")
return false;
}
func connectedToServer() {
println("Connected to Faye server")
}
func connectionFailed() {
println("Failed to connect to Faye server!")
}
func disconnectedFromServer() {
println("Disconnected from Faye server")
}
func didSubscribeToChannel(channel: String) {
println("subscribed to channel \(channel)")
}
func didUnsubscribeFromChannel(channel: String) {
println("UNsubscribed from channel \(channel)")
}
func subscriptionFailedWithError(error: String) {
println("SUBSCRIPTION FAILED!!!!")
}
func messageReceived(messageDict: NSDictionary, channel: String) {
let text: AnyObject? = messageDict["text"]
println("Here is the message: \(text)")
// self.client.subscribeToChannel("/newchannelbaby")
// self.client.unsubscribeFromChannel(channel)
}
}
@@ -1,36 +0,0 @@
//
// FayeSwiftDemoTests.swift
// FayeSwiftDemoTests
//
// Created by Haris Amin on 10/1/14.
// Copyright (c) 2014 Haris Amin. All rights reserved.
//
import UIKit
import XCTest
class FayeSwiftDemoTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
XCTAssert(true, "Pass")
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measureBlock() {
// Put the code you want to measure the time of here.
}
}
}
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>HarisAmin.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
+2 -1
View File
@@ -1,6 +1,7 @@
The MIT License (MIT)
Copyright (c) 2014 Haris Amin
Copyright for portions of project Foo are held by Haris Amin, 2014 as part of project FayeSwift.
All other copyright for project Foo are held by Darcy Laycock, 2016.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+3 -28
View File
@@ -1,10 +1,6 @@
# FayeSwift
[![Join the chat at https://gitter.im/hamin/FayeSwift](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hamin/FayeSwift?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![swift](https://raw.githubusercontent.com/hamin/FayeSwift/master/swift-logo.png)
A simple Swift client library for the [Faye](http://faye.jcoglan.com/) publish-subscribe messaging server. FayeObjC is implemented atop the [Starscream](https://github.com/daltoniam/starscream) Swift web socket library and will work on both Mac (pending Xcode 6 Swift update) and iPhone projects.
It was heavily inspired by the Objective-C client found here: [FayeObjc](https://github.com/pcrawfor/FayeObjC)
@@ -13,7 +9,6 @@ It was heavily inspired by the Objective-C client found here: [FayeObjc](https:/
### Installation
For now, add the following files to your project: `FayeClient.swift`, `Websocket.swift`, and `SwiftyJSON.swift`.
### Initializing Client
@@ -127,26 +122,9 @@ You can call sendMessage to send a dictionary object to a channel
client.sendMessage(["text": textField.text], channel: "/cool")
```
## Example Server
There is a sample faye server using the NodeJS Faye library. If you have NodeJS installed just run the following commands to install the package:
```javascript
npm install
```
And then you can start the Faye server like so:
```javascript
node faye_server.js
```
## Example Project
Check out the FayeSwiftDemo project to see how to setup a simple connection to a Faye server.
## Requirements
FayeSwift requires at least iOS 7/OSX 10.10 or above.
FayeSwift requires at least iOS8 / tvOS9.
## TODOs
@@ -159,9 +137,6 @@ FayeSwift requires at least iOS 7/OSX 10.10 or above.
## License
BayeuxSwift is licensed under the MIT License and is a derivative of the [FayeSwift]() project.
FayeSwift is licensed under the MIT License.
## Libraries
* [Starscream](https://github.com/daltoniam)
* [SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON)
-76
View File
@@ -1,76 +0,0 @@
var http = require('http'),
faye = require('faye');
faye.Logging.logLevel = 'debug';
var bayeux = new faye.NodeAdapter({
mount: '/faye',
timeout: 45
});
// Handle non-Bayeux requests
var server = http.createServer(function(request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.write('Non-Bayeux request');
response.end();
});
serverLog = {
incoming: function(message, callback) {
console.log("SOMETTHING HAPPENDED!");
if (message.channel === '/meta/subscribe') {
logWithTimeStamp("CLIENT SUBSCRIBED Client ID: " + message.clientId);
}
if (message.channel.match(/\/users\/*/)) {
logWithTimeStamp("USER MESSAGE ON CHANNEL: " + message.channel);
}
return callback(message);
}
};
logWithTimeStamp = function(logMessage) {
var timestampedMessage;
timestampedMessage = "" + (Date()) + " | " + logMessage;
return console.log(timestampedMessage);
};
bayeux.bind('handshake', function(client_id) {
console.log("[handshake] - client: '"+ client_id +"'");
});
bayeux.bind('subscribe', function(client_id, channel) {
console.log("[subscribe] - client: '"+ client_id +"', channel: '"+ channel +"'");
});
bayeux.bind('unsubscribe', function(client_id, channel) {
console.log("[unsubscribe] - client: '"+ client_id +"', channel: '"+ channel +"'");
});
bayeux.bind('publish', function(client_id, channel, data) {
console.log("[publish] - client: '"+ client_id +"', channel: '"+ channel +"'");
console.log("[publish] - data:");
console.log(data);
});
bayeux.bind('connect', function(client_id) {
console.log("[connect] - client: '"+ client_id +"'");
});
bayeux.bind('disconnect', function(client_id) {
console.log("[disconnect] - client: '"+ client_id +"'");
});
bayeux.addExtension(serverLog);
bayeux.attach(server);
bayeux.getClient().subscribe('/cool', function(message){
console.log("OMG NEW MESSAGE CAME ***********");
console.log(JSON.stringify(message));
});
server.listen(5222);
console.log("Started Faye Server");
-1347
View File
File diff suppressed because it is too large Load Diff
-723
View File
@@ -1,723 +0,0 @@
//////////////////////////////////////////////////////////////////////////////////////////////////
//
// Websocket.swift
//
// Created by Dalton Cherry on 7/16/14.
//
//////////////////////////////////////////////////////////////////////////////////////////////////
import Foundation
import CoreFoundation
public protocol WebSocketDelegate: class {
func websocketDidConnect(socket: WebSocket)
func websocketDidDisconnect(socket: WebSocket, error: NSError?)
func websocketDidReceiveMessage(socket: WebSocket, text: String)
func websocketDidReceiveData(socket: WebSocket, data: NSData)
}
public class WebSocket : NSObject, NSStreamDelegate {
enum OpCode : UInt8 {
case ContinueFrame = 0x0
case TextFrame = 0x1
case BinaryFrame = 0x2
//3-7 are reserved.
case ConnectionClose = 0x8
case Ping = 0x9
case Pong = 0xA
//B-F reserved.
}
enum CloseCode : UInt16 {
case Normal = 1000
case GoingAway = 1001
case ProtocolError = 1002
case ProtocolUnhandledType = 1003
// 1004 reserved.
case NoStatusReceived = 1005
//1006 reserved.
case Encoding = 1007
case PolicyViolated = 1008
case MessageTooBig = 1009
}
enum InternalErrorCode : UInt16 {
// 0-999 WebSocket status codes not used
case OutputStreamWriteError = 1
}
//Where the callback is executed. It defaults to the main UI thread queue.
public var queue = dispatch_get_main_queue()
var optionalProtocols : Array<String>?
//Constant Values.
let headerWSUpgradeName = "Upgrade"
let headerWSUpgradeValue = "websocket"
let headerWSHostName = "Host"
let headerWSConnectionName = "Connection"
let headerWSConnectionValue = "Upgrade"
let headerWSProtocolName = "Sec-WebSocket-Protocol"
let headerWSVersionName = "Sec-WebSocket-Version"
let headerWSVersionValue = "13"
let headerWSKeyName = "Sec-WebSocket-Key"
let headerOriginName = "Origin"
let headerWSAcceptName = "Sec-WebSocket-Accept"
let BUFFER_MAX = 2048
let FinMask: UInt8 = 0x80
let OpCodeMask: UInt8 = 0x0F
let RSVMask: UInt8 = 0x70
let MaskMask: UInt8 = 0x80
let PayloadLenMask: UInt8 = 0x7F
let MaxFrameSize: Int = 32
class WSResponse {
var isFin = false
var code: OpCode = .ContinueFrame
var bytesLeft = 0
var frameCount = 0
var buffer: NSMutableData?
}
public weak var delegate: WebSocketDelegate?
private var url: NSURL
private var inputStream: NSInputStream?
private var outputStream: NSOutputStream?
private var isRunLoop = false
private var connected = false
private var isCreated = false
private var writeQueue: NSOperationQueue?
private var readStack = Array<WSResponse>()
private var inputQueue = Array<NSData>()
private var fragBuffer: NSData?
public var headers = Dictionary<String,String>()
public var voipEnabled = false
public var selfSignedSSL = false
private var connectedBlock: ((Void) -> Void)? = nil
private var disconnectedBlock: ((NSError?) -> Void)? = nil
private var receivedTextBlock: ((String) -> Void)? = nil
private var receivedDataBlock: ((NSData) -> Void)? = nil
public var isConnected :Bool {
return connected
}
//init the websocket with a url
public init(url: NSURL) {
self.url = url
}
//used for setting protocols.
public convenience init(url: NSURL, protocols: Array<String>) {
self.init(url: url)
optionalProtocols = protocols
}
//closure based instead of the delegate
public convenience init(url: NSURL, protocols: Array<String>, connect:((Void) -> Void), disconnect:((NSError?) -> Void), text:((String) -> Void), data:(NSData) -> Void) {
self.init(url: url, protocols: protocols)
connectedBlock = connect
disconnectedBlock = disconnect
receivedTextBlock = text
receivedDataBlock = data
}
//same as above, just shorter
public convenience init(url: NSURL, connect:((Void) -> Void), disconnect:((NSError?) -> Void), text:((String) -> Void)) {
self.init(url: url)
connectedBlock = connect
disconnectedBlock = disconnect
receivedTextBlock = text
}
//same as above, just shorter
public convenience init(url: NSURL, connect:((Void) -> Void), disconnect:((NSError?) -> Void), data:((NSData) -> Void)) {
self.init(url: url)
connectedBlock = connect
disconnectedBlock = disconnect
receivedDataBlock = data
}
///Connect to the websocket server on a background thread
public func connect() {
if isCreated {
return
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), {
self.isCreated = true
self.createHTTPRequest()
self.isCreated = false
})
}
///disconnect from the websocket server
public func disconnect() {
writeError(CloseCode.Normal.rawValue)
}
///write a string to the websocket. This sends it as a text frame.
public func writeString(str: String) {
dequeueWrite(str.dataUsingEncoding(NSUTF8StringEncoding)!, code: .TextFrame)
}
///write binary data to the websocket. This sends it as a binary frame.
public func writeData(data: NSData) {
dequeueWrite(data, code: .BinaryFrame)
}
//write a ping to the websocket. This sends it as a control frame.
//yodel a sound to the planet. This sends it as an astroid. http://youtu.be/Eu5ZJELRiJ8?t=42s
public func writePing(data: NSData) {
dequeueWrite(data, code: .Ping)
}
//private methods below!
//private method that starts the connection
private func createHTTPRequest() {
let str: NSString = url.absoluteString!
let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET",
url, kCFHTTPVersion1_1)
var port = url.port
if port == nil {
if url.scheme == "wss" || url.scheme == "https" {
port = 443
} else {
port = 80
}
}
self.addHeader(urlRequest, key: headerWSUpgradeName, val: headerWSUpgradeValue)
self.addHeader(urlRequest, key: headerWSConnectionName, val: headerWSConnectionValue)
if let protocols = optionalProtocols {
self.addHeader(urlRequest, key: headerWSProtocolName, val: ",".join(protocols))
}
self.addHeader(urlRequest, key: headerWSVersionName, val: headerWSVersionValue)
self.addHeader(urlRequest, key: headerWSKeyName, val: self.generateWebSocketKey())
self.addHeader(urlRequest, key: headerOriginName, val: url.absoluteString!)
self.addHeader(urlRequest, key: headerWSHostName, val: "\(url.host!):\(port!)")
for (key,value) in headers {
self.addHeader(urlRequest, key: key, val: value)
}
let serializedRequest: NSData = CFHTTPMessageCopySerializedMessage(urlRequest.takeUnretainedValue()).takeUnretainedValue()
self.initStreamsWithData(serializedRequest, Int(port!))
}
//Add a header to the CFHTTPMessage by using the NSString bridges to CFString
private func addHeader(urlRequest: Unmanaged<CFHTTPMessage>,key: String, val: String) {
let nsKey: NSString = key
let nsVal: NSString = val
CFHTTPMessageSetHeaderFieldValue(urlRequest.takeUnretainedValue(),
nsKey,
nsVal)
}
//generate a websocket key as needed in rfc
private func generateWebSocketKey() -> String {
var key = ""
let seed = 16
for (var i = 0; i < seed; i++) {
let uni = UnicodeScalar(UInt32(97 + arc4random_uniform(25)))
key += "\(Character(uni))"
}
var data = key.dataUsingEncoding(NSUTF8StringEncoding)
var baseKey = data?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(0))
return baseKey!
}
//Start the stream connection and write the data to the output stream
private func initStreamsWithData(data: NSData, _ port: Int) {
//higher level API we will cut over to at some point
//NSStream.getStreamsToHostWithName(url.host, port: url.port.integerValue, inputStream: &inputStream, outputStream: &outputStream)
var readStream: Unmanaged<CFReadStream>?
var writeStream: Unmanaged<CFWriteStream>?
let h: NSString = url.host!
CFStreamCreatePairWithSocketToHost(nil, h, UInt32(port), &readStream, &writeStream)
inputStream = readStream!.takeUnretainedValue()
outputStream = writeStream!.takeUnretainedValue()
inputStream!.delegate = self
outputStream!.delegate = self
if url.scheme == "wss" || url.scheme == "https" {
inputStream!.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, forKey: NSStreamSocketSecurityLevelKey)
outputStream!.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, forKey: NSStreamSocketSecurityLevelKey)
}
if self.voipEnabled {
inputStream!.setProperty(NSStreamNetworkServiceTypeVoIP, forKey: NSStreamNetworkServiceType)
outputStream!.setProperty(NSStreamNetworkServiceTypeVoIP, forKey: NSStreamNetworkServiceType)
}
if self.selfSignedSSL {
let settings: Dictionary<NSObject, NSObject> = [kCFStreamSSLValidatesCertificateChain: NSNumber(bool:false), kCFStreamSSLPeerName: kCFNull]
inputStream!.setProperty(settings, forKey: kCFStreamPropertySSLSettings as! String)
outputStream!.setProperty(settings, forKey: kCFStreamPropertySSLSettings as! String)
}
isRunLoop = true
inputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
outputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
inputStream!.open()
outputStream!.open()
let bytes = UnsafePointer<UInt8>(data.bytes)
outputStream!.write(bytes, maxLength: data.length)
while(isRunLoop) {
NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate.distantFuture() as! NSDate)
}
}
//delegate for the stream methods. Processes incoming bytes
public func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
if eventCode == .HasBytesAvailable {
if(aStream == inputStream) {
processInputStream()
}
} else if eventCode == .ErrorOccurred {
disconnectStream(aStream.streamError)
} else if eventCode == .EndEncountered {
disconnectStream(nil)
}
}
//disconnect the stream object
private func disconnectStream(error: NSError?) {
if writeQueue != nil {
writeQueue!.waitUntilAllOperationsAreFinished()
}
if let stream = inputStream {
stream.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
stream.close()
}
if let stream = outputStream {
stream.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
stream.close()
}
outputStream = nil
isRunLoop = false
connected = false
dispatch_async(queue,{
if let disconnectBlock = self.disconnectedBlock {
disconnectBlock(error)
}
self.delegate?.websocketDidDisconnect(self, error: error)
})
}
///handles the incoming bytes and sending them to the proper processing method
private func processInputStream() {
let buf = NSMutableData(capacity: BUFFER_MAX)
var buffer = UnsafeMutablePointer<UInt8>(buf!.bytes)
let length = inputStream!.read(buffer, maxLength: BUFFER_MAX)
if length > 0 {
if !connected {
connected = processHTTP(buffer, bufferLen: length)
if !connected {
dispatch_async(queue,{
//self.workaroundMethod()
let error = self.errorWithDetail("Invalid HTTP upgrade", code: 1)
if let disconnect = self.disconnectedBlock {
disconnect(error)
}
self.delegate?.websocketDidDisconnect(self, error: error)
})
}
} else {
var process = false
if inputQueue.count == 0 {
process = true
}
inputQueue.append(NSData(bytes: buffer, length: length))
if process {
dequeueInput()
}
}
}
}
///dequeue the incoming input so it is processed in order
private func dequeueInput() {
if inputQueue.count > 0 {
let data = inputQueue[0]
var work = data
if (fragBuffer != nil) {
var combine = NSMutableData(data: fragBuffer!)
combine.appendData(data)
work = combine
fragBuffer = nil
}
let buffer = UnsafePointer<UInt8>(work.bytes)
processRawMessage(buffer, bufferLen: work.length)
inputQueue = inputQueue.filter{$0 != data}
dequeueInput()
}
}
///Finds the HTTP Packet in the TCP stream, by looking for the CRLF.
private func processHTTP(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Bool {
let CRLFBytes = [UInt8(ascii: "\r"), UInt8(ascii: "\n"), UInt8(ascii: "\r"), UInt8(ascii: "\n")]
var k = 0
var totalSize = 0
for var i = 0; i < bufferLen; i++ {
if buffer[i] == CRLFBytes[k] {
k++
if k == 3 {
totalSize = i + 1
break
}
} else {
k = 0
}
}
if totalSize > 0 {
if validateResponse(buffer, bufferLen: totalSize) {
dispatch_async(queue,{
//self.workaroundMethod()
if let connectBlock = self.connectedBlock {
connectBlock()
}
self.delegate?.websocketDidConnect(self)
})
totalSize += 1 //skip the last \n
let restSize = bufferLen - totalSize
if restSize > 0 {
processRawMessage((buffer+totalSize),bufferLen: restSize)
}
return true
}
}
return false
}
///validates the HTTP is a 101 as per the RFC spec
private func validateResponse(buffer: UnsafePointer<UInt8>, bufferLen: Int) -> Bool {
let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, 0)
CFHTTPMessageAppendBytes(response.takeUnretainedValue(), buffer, bufferLen)
if CFHTTPMessageGetResponseStatusCode(response.takeUnretainedValue()) != 101 {
return false
}
let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response.takeUnretainedValue())
let headers: NSDictionary = cfHeaders.takeUnretainedValue()
let acceptKey = headers[headerWSAcceptName] as! NSString
if acceptKey.length > 0 {
return true
}
return false
}
///process the websocket data
private func processRawMessage(buffer: UnsafePointer<UInt8>, bufferLen: Int) {
var response = readStack.last
if response != nil && bufferLen < 2 {
fragBuffer = NSData(bytes: buffer, length: bufferLen)
return
}
if response != nil && response!.bytesLeft > 0 {
let resp = response!
var len = resp.bytesLeft
var extra = bufferLen - resp.bytesLeft
if resp.bytesLeft > bufferLen {
len = bufferLen
extra = 0
}
resp.bytesLeft -= len
resp.buffer?.appendData(NSData(bytes: buffer, length: len))
processResponse(resp)
var offset = bufferLen - extra
if extra > 0 {
processExtra((buffer+offset), bufferLen: extra)
}
return
} else {
let isFin = (FinMask & buffer[0])
let receivedOpcode = (OpCodeMask & buffer[0])
let isMasked = (MaskMask & buffer[1])
let payloadLen = (PayloadLenMask & buffer[1])
var offset = 2
if((isMasked > 0 || (RSVMask & buffer[0]) > 0) && receivedOpcode != OpCode.Pong.rawValue) {
let errCode = CloseCode.ProtocolError.rawValue
let error = self.errorWithDetail("masked and rsv data is not currently supported", code: errCode)
if let disconnect = self.disconnectedBlock {
disconnect(error)
}
self.delegate?.websocketDidDisconnect(self, error: error)
writeError(errCode)
return
}
let isControlFrame = (receivedOpcode == OpCode.ConnectionClose.rawValue || receivedOpcode == OpCode.Ping.rawValue)
if !isControlFrame && (receivedOpcode != OpCode.BinaryFrame.rawValue && receivedOpcode != OpCode.ContinueFrame.rawValue &&
receivedOpcode != OpCode.TextFrame.rawValue && receivedOpcode != OpCode.Pong.rawValue) {
let errCode = CloseCode.ProtocolError.rawValue
let error = self.errorWithDetail("unknown opcode: \(receivedOpcode)", code: errCode)
if let disconnect = self.disconnectedBlock {
disconnect(error)
}
self.delegate?.websocketDidDisconnect(self, error: error)
writeError(errCode)
return
}
if isControlFrame && isFin == 0 {
let errCode = CloseCode.ProtocolError.rawValue
let error = self.errorWithDetail("control frames can't be fragmented", code: errCode)
if let disconnect = self.disconnectedBlock {
disconnect(error)
}
self.delegate?.websocketDidDisconnect(self, error: error)
writeError(errCode)
return
}
if receivedOpcode == OpCode.ConnectionClose.rawValue {
var code = CloseCode.Normal.rawValue
if payloadLen == 1 {
code = CloseCode.ProtocolError.rawValue
} else if payloadLen > 1 {
var codeBuffer = UnsafePointer<UInt16>((buffer+offset))
code = codeBuffer[0].bigEndian
if code < 1000 || (code > 1003 && code < 1007) || (code > 1011 && code < 3000) {
code = CloseCode.ProtocolError.rawValue
}
offset += 2
}
if payloadLen > 2 {
let len = Int(payloadLen-2)
if len > 0 {
let bytes = UnsafePointer<UInt8>((buffer+offset))
var str: NSString? = NSString(data: NSData(bytes: bytes, length: len), encoding: NSUTF8StringEncoding)
if str == nil {
code = CloseCode.ProtocolError.rawValue
}
}
}
let error = self.errorWithDetail("connection closed by server", code: code)
if let disconnect = self.disconnectedBlock {
disconnect(error)
}
self.delegate?.websocketDidDisconnect(self, error: error)
writeError(code)
return
}
if isControlFrame && payloadLen > 125 {
writeError(CloseCode.ProtocolError.rawValue)
return
}
var dataLength = UInt64(payloadLen)
if dataLength == 127 {
let bytes = UnsafePointer<UInt64>((buffer+offset))
dataLength = bytes[0].bigEndian
offset += sizeof(UInt64)
} else if dataLength == 126 {
let bytes = UnsafePointer<UInt16>((buffer+offset))
dataLength = UInt64(bytes[0].bigEndian)
offset += sizeof(UInt16)
}
var len = dataLength
if dataLength > UInt64(bufferLen) {
len = UInt64(bufferLen-offset)
}
var data: NSData!
if len < 0 {
len = 0
data = NSData()
} else {
data = NSData(bytes: UnsafePointer<UInt8>((buffer+offset)), length: Int(len))
}
if receivedOpcode == OpCode.Pong.rawValue {
let step = Int(offset+numericCast(len))
let extra = bufferLen-step
if extra > 0 {
processRawMessage((buffer+step), bufferLen: extra)
}
return
}
var response = readStack.last
if isControlFrame {
response = nil //don't append pings
}
if isFin == 0 && receivedOpcode == OpCode.ContinueFrame.rawValue && response == nil {
let errCode = CloseCode.ProtocolError.rawValue
let error = self.errorWithDetail("continue frame before a binary or text frame", code: errCode)
if let disconnect = self.disconnectedBlock {
disconnect(error)
}
self.delegate?.websocketDidDisconnect(self, error: error)
writeError(errCode)
return
}
var isNew = false
if(response == nil) {
if receivedOpcode == OpCode.ContinueFrame.rawValue {
let errCode = CloseCode.ProtocolError.rawValue
let error = self.errorWithDetail("first frame can't be a continue frame",
code: errCode)
if let disconnect = self.disconnectedBlock {
disconnect(error)
}
self.delegate?.websocketDidDisconnect(self, error: error)
writeError(errCode)
return
}
isNew = true
response = WSResponse()
response!.code = OpCode(rawValue: receivedOpcode)!
response!.bytesLeft = Int(dataLength)
response!.buffer = NSMutableData(data: data)
} else {
if receivedOpcode == OpCode.ContinueFrame.rawValue {
response!.bytesLeft = Int(dataLength)
} else {
let errCode = CloseCode.ProtocolError.rawValue
let error = self.errorWithDetail("second and beyond of fragment message must be a continue frame",
code: errCode)
if let disconnect = self.disconnectedBlock {
disconnect(error)
}
self.delegate?.websocketDidDisconnect(self, error: error)
writeError(errCode)
return
}
response!.buffer!.appendData(data)
}
if response != nil {
response!.bytesLeft -= Int(len)
response!.frameCount++
response!.isFin = isFin > 0 ? true : false
if(isNew) {
readStack.append(response!)
}
processResponse(response!)
}
let step = Int(offset+numericCast(len))
let extra = bufferLen-step
if(extra > 0) {
processExtra((buffer+step), bufferLen: extra)
}
}
}
///process the extra of a buffer
private func processExtra(buffer: UnsafePointer<UInt8>, bufferLen: Int) {
if bufferLen < 2 {
fragBuffer = NSData(bytes: buffer, length: bufferLen)
} else {
processRawMessage(buffer, bufferLen: bufferLen)
}
}
///process the finished response of a buffer
private func processResponse(response: WSResponse) -> Bool {
if response.isFin && response.bytesLeft <= 0 {
if response.code == .Ping {
let data = response.buffer! //local copy so it is perverse for writing
dequeueWrite(data, code: OpCode.Pong)
} else if response.code == .TextFrame {
var str: NSString? = NSString(data: response.buffer!, encoding: NSUTF8StringEncoding)
if str == nil {
writeError(CloseCode.Encoding.rawValue)
return false
}
dispatch_async(queue,{
if let textBlock = self.receivedTextBlock{
textBlock(str! as! String)
}
self.delegate?.websocketDidReceiveMessage(self, text: str! as! String)
})
} else if response.code == .BinaryFrame {
let data = response.buffer! //local copy so it is perverse for writing
dispatch_async(queue,{
//self.workaroundMethod()
if let dataBlock = self.receivedDataBlock{
dataBlock(data)
}
self.delegate?.websocketDidReceiveData(self, data: data)
})
}
readStack.removeLast()
return true
}
return false
}
///Create an error
private func errorWithDetail(detail: String, code: UInt16) -> NSError {
var details = Dictionary<String,String>()
details[NSLocalizedDescriptionKey] = detail
return NSError(domain: "Websocket", code: Int(code), userInfo: details)
}
///write a an error to the socket
private func writeError(code: UInt16) {
let buf = NSMutableData(capacity: sizeof(UInt16))
var buffer = UnsafeMutablePointer<UInt16>(buf!.bytes)
buffer[0] = code.bigEndian
dequeueWrite(NSData(bytes: buffer, length: sizeof(UInt16)), code: .ConnectionClose)
}
///used to write things to the stream in a
private func dequeueWrite(data: NSData, code: OpCode) {
if writeQueue == nil {
writeQueue = NSOperationQueue()
writeQueue!.maxConcurrentOperationCount = 1
}
writeQueue!.addOperationWithBlock {
//stream isn't ready, let's wait
var tries = 0;
while self.outputStream == nil || !self.connected {
if(tries < 5) {
sleep(1);
} else {
break;
}
tries++;
}
if !self.connected {
return
}
var offset = 2
UINT16_MAX
let bytes = UnsafeMutablePointer<UInt8>(data.bytes)
let dataLength = data.length
let frame = NSMutableData(capacity: dataLength + self.MaxFrameSize)
let buffer = UnsafeMutablePointer<UInt8>(frame!.mutableBytes)
buffer[0] = self.FinMask | code.rawValue
if dataLength < 126 {
buffer[1] = CUnsignedChar(dataLength)
} else if dataLength <= Int(UInt16.max) {
buffer[1] = 126
var sizeBuffer = UnsafeMutablePointer<UInt16>((buffer+offset))
sizeBuffer[0] = UInt16(dataLength).bigEndian
offset += sizeof(UInt16)
} else {
buffer[1] = 127
var sizeBuffer = UnsafeMutablePointer<UInt64>((buffer+offset))
sizeBuffer[0] = UInt64(dataLength).bigEndian
offset += sizeof(UInt64)
}
buffer[1] |= self.MaskMask
var maskKey = UnsafeMutablePointer<UInt8>(buffer + offset)
SecRandomCopyBytes(kSecRandomDefault, Int(sizeof(UInt32)), maskKey)
offset += sizeof(UInt32)
for (var i = 0; i < dataLength; i++) {
buffer[offset] = bytes[i] ^ maskKey[i % sizeof(UInt32)]
offset += 1
}
var total = 0
while true {
if self.outputStream == nil {
break
}
let writeBuffer = UnsafePointer<UInt8>(frame!.bytes+total)
var len = self.outputStream?.write(writeBuffer, maxLength: offset-total)
if len == nil || len! < 0 {
var error: NSError?
if let streamError = self.outputStream?.streamError {
error = streamError
} else {
let errCode = InternalErrorCode.OutputStreamWriteError.rawValue
error = self.errorWithDetail("output stream error during write", code: errCode)
}
if let disconnect = self.disconnectedBlock {
disconnect(error)
}
self.delegate?.websocketDidDisconnect(self, error: error)
break
} else {
total += len!
}
if total >= offset {
break
}
}
}
}
}
-7
View File
@@ -1,7 +0,0 @@
{
"name" : "fayeswift-demo",
"version" : "1.0.0",
"dependencies" : {
"faye" : "1.0.3"
}
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB