dramatic naming refactor
This commit is contained in:
parent
b9dae4db1a
commit
fe2107e446
|
@ -1,10 +1,22 @@
|
|||
// Copyright (c) 2015 Peter Siegesmund <peter.siegesmund@icloud.com>
|
||||
//
|
||||
// CoreDataExtensions.swift
|
||||
// SwiftTodos
|
||||
// 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:
|
||||
//
|
||||
// Created by Peter Siegesmund on 10/29/15.
|
||||
// Copyright © 2015 Peter Siegesmund. All rights reserved.
|
||||
// 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
|
||||
import CoreData
|
||||
|
|
|
@ -32,351 +32,359 @@ import XCGLogger
|
|||
|
||||
let log = XCGLogger(identifier: "DDP")
|
||||
|
||||
public class DDP {
|
||||
|
||||
|
||||
public class Client: NSObject {
|
||||
|
||||
// included for storing login id and token
|
||||
let userData = NSUserDefaults.standardUserDefaults()
|
||||
|
||||
public let incomingData:NSOperationQueue = {
|
||||
let queue = NSOperationQueue()
|
||||
queue.name = "DDP Incoming Data Queue"
|
||||
queue.maxConcurrentOperationCount = 1
|
||||
return queue
|
||||
}()
|
||||
|
||||
// Calling methods on the server + their callbacks
|
||||
public let outgoingData:NSOperationQueue = {
|
||||
let queue = NSOperationQueue()
|
||||
queue.name = "DDP Outgoing Data Queue"
|
||||
// queue.maxConcurrentOperationCount = 1
|
||||
return queue
|
||||
}()
|
||||
|
||||
public let operation:NSOperationQueue = {
|
||||
let queue = NSOperationQueue()
|
||||
queue.name = "DDP Operation Queue"
|
||||
queue.maxConcurrentOperationCount = 1
|
||||
return queue
|
||||
}()
|
||||
|
||||
public let heartbeat:NSOperationQueue = {
|
||||
let queue = NSOperationQueue()
|
||||
queue.name = "DDP Heartbeat Queue"
|
||||
//queue.maxConcurrentOperationCount = 1
|
||||
return queue
|
||||
}()
|
||||
|
||||
public let mainQueue = NSOperationQueue.mainQueue()
|
||||
|
||||
private var socket:WebSocket!
|
||||
private var server:(ping:NSDate?, pong:NSDate?) = (nil, nil)
|
||||
|
||||
var resultCallbacks:[String:(result:AnyObject?, error:DDP.Error?) -> ()] = [:]
|
||||
var subCallbacks:[String:() -> ()] = [:]
|
||||
var unsubCallbacks:[String:() -> ()] = [:]
|
||||
|
||||
var url:String!
|
||||
var subscriptions = [String:(id:String, name:String, ready:Bool)]()
|
||||
|
||||
public var logLevel = XCGLogger.LogLevel.Debug
|
||||
public var events = DDP.Events()
|
||||
public var connection:(ddp:Bool, session:String?) = (false, nil)
|
||||
|
||||
public override init() {
|
||||
super.init()
|
||||
setLogLevel(logLevel)
|
||||
}
|
||||
|
||||
public func getId() -> String {
|
||||
let numbers = Set<Character>(["0","1","2","3","4","5","6","7","8","9"])
|
||||
let uuid = NSUUID().UUIDString.stringByReplacingOccurrencesOfString("-", withString: "")
|
||||
var id = ""
|
||||
for character in uuid.characters {
|
||||
if (!numbers.contains(character) && (round(Float(arc4random()) / Float(UINT32_MAX)) == 1)) {
|
||||
id += String(character).lowercaseString
|
||||
} else {
|
||||
id += String(character)
|
||||
}
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
public func connect(url:String, callback:((session:String)->())?) {
|
||||
|
||||
socket = WebSocket(url)
|
||||
|
||||
socket.event.close = {code, reason, clean in
|
||||
log.info("Web socket connection closed with code \(code). Clean: \(clean). \(reason)")
|
||||
let event = self.socket.event
|
||||
self.socket = WebSocket(url)
|
||||
self.socket.event = event
|
||||
self.ping()
|
||||
}
|
||||
|
||||
socket.event.error = events.onWebsocketError
|
||||
|
||||
socket.event.open = {
|
||||
self.heartbeat.addOperationWithBlock() {
|
||||
if let c = callback { self.events.onConnected = c }
|
||||
self.sendMessage(["msg":"connect", "version":"1", "support":["1"]])
|
||||
}
|
||||
}
|
||||
|
||||
socket.event.message = { message in
|
||||
self.operation.addOperationWithBlock() {
|
||||
if let text = message as? String {
|
||||
do { try self.ddpMessageHandler(DDP.Message(message: text)) }
|
||||
catch { log.debug("Message handling error. Raw message: \(text)")}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public func setLogLevel(logLevel:XCGLogger.LogLevel) {
|
||||
log.setup(logLevel, showLogIdentifier: true, showFunctionName: true, showThreadName: true, showLogLevel: true, showFileNames: false, showLineNumbers: true, showDate: false, writeToFile: nil, fileLogLevel: .None)
|
||||
}
|
||||
|
||||
func ping() {
|
||||
heartbeat.addOperationWithBlock() {
|
||||
self.sendMessage(["msg":"ping", "id":self.getId()])
|
||||
}
|
||||
}
|
||||
|
||||
// Respond to a server ping
|
||||
private func pong(ping: DDP.Message) {
|
||||
heartbeat.addOperationWithBlock() {
|
||||
self.server.ping = NSDate()
|
||||
log.debug("Ping")
|
||||
var response = ["msg":"pong"]
|
||||
if let id = ping.id { response["id"] = id }
|
||||
self.sendMessage(response)
|
||||
}
|
||||
}
|
||||
|
||||
// Parse DDP messages and dispatch to the appropriate function
|
||||
func ddpMessageHandler(message: DDP.Message) throws {
|
||||
|
||||
log.debug("Received message: \(message.json)")
|
||||
|
||||
switch message.type {
|
||||
|
||||
case .Connected:
|
||||
self.connection = (true, message.session!)
|
||||
self.events.onConnected(session:message.session!)
|
||||
|
||||
case .Result: incomingData.addOperationWithBlock() {
|
||||
if let id = message.id, // Message has id
|
||||
let callback = self.resultCallbacks[id], // There is a callback registered for the message
|
||||
let result = message.result {
|
||||
callback(result:result, error: message.error)
|
||||
self.resultCallbacks[id] = nil
|
||||
} else if let id = message.id,
|
||||
let callback = self.resultCallbacks[id] {
|
||||
callback(result:nil, error:message.error)
|
||||
self.resultCallbacks[id] = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Principal callbacks for managing data
|
||||
// Document was added
|
||||
case .Added: incomingData.addOperationWithBlock() {
|
||||
if let collection = message.collection,
|
||||
let id = message.id {
|
||||
self.documentWasAdded(collection, id: id, fields: message.fields)
|
||||
}
|
||||
}
|
||||
|
||||
// Document was changed
|
||||
case .Changed: incomingData.addOperationWithBlock() {
|
||||
if let collection = message.collection,
|
||||
let id = message.id {
|
||||
self.documentWasChanged(collection, id: id, fields: message.fields, cleared: message.cleared)
|
||||
}
|
||||
}
|
||||
|
||||
// Document was removed
|
||||
case .Removed: incomingData.addOperationWithBlock() {
|
||||
if let collection = message.collection,
|
||||
let id = message.id {
|
||||
self.documentWasRemoved(collection, id: id)
|
||||
}
|
||||
}
|
||||
|
||||
// Notifies you when the result of a method changes
|
||||
case .Updated: incomingData.addOperationWithBlock() {
|
||||
if let methods = message.methods {
|
||||
self.methodWasUpdated(methods)
|
||||
}
|
||||
}
|
||||
|
||||
// Callbacks for managing subscriptions
|
||||
case .Ready: incomingData.addOperationWithBlock() {
|
||||
if let subs = message.subs {
|
||||
self.ready(subs)
|
||||
}
|
||||
}
|
||||
|
||||
// Callback that fires when subscription has been completely removed
|
||||
//
|
||||
case .Nosub: incomingData.addOperationWithBlock() {
|
||||
if let id = message.id {
|
||||
self.nosub(id, error: message.error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
case .Ping: heartbeat.addOperationWithBlock() { self.pong(message) }
|
||||
|
||||
case .Pong: heartbeat.addOperationWithBlock() { self.server.pong = NSDate() }
|
||||
|
||||
case .Error: incomingData.addOperationWithBlock() {
|
||||
self.didReceiveErrorMessage(DDP.Error(json: message.json))
|
||||
}
|
||||
|
||||
default: log.error("Unhandled message: \(message.json)")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private func sendMessage(message:NSDictionary) {
|
||||
if let m = message.stringValue() {
|
||||
self.socket.send(m)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute a method on the Meteor server
|
||||
public func method(name: String, params: AnyObject?, callback: ((result:AnyObject?, error: DDP.Error?) -> ())?) -> String {
|
||||
let id = getId()
|
||||
let message = ["msg":"method", "method":name, "id":id] as NSMutableDictionary
|
||||
if let p = params { message["params"] = p }
|
||||
if let c = callback { resultCallbacks[id] = c }
|
||||
outgoingData.addOperationWithBlock() { self.sendMessage(message) }
|
||||
return id
|
||||
}
|
||||
|
||||
//
|
||||
// Subscribe
|
||||
//
|
||||
|
||||
public func sub(id: String, name: String, params: [AnyObject]?, callback: (() -> ())?) -> String {
|
||||
if let c = callback { subCallbacks[id] = c }
|
||||
subscriptions[id] = (id, name, false)
|
||||
let message = ["msg":"sub", "name":name, "id":id] as NSMutableDictionary
|
||||
if let p = params { message["params"] = p }
|
||||
outgoingData.addOperationWithBlock() { self.sendMessage(message) }
|
||||
return id
|
||||
}
|
||||
|
||||
// Subscribe to a Meteor collection
|
||||
public func sub(name: String, params: [AnyObject]?) -> String {
|
||||
let id = getId()
|
||||
return sub(id, name: name, params: params, callback:nil)
|
||||
}
|
||||
|
||||
public func sub(name:String, params: [AnyObject]?, callback: (() -> ())?) -> String {
|
||||
let id = getId()
|
||||
return sub(id, name: name, params: params, callback: callback)
|
||||
}
|
||||
|
||||
// Iterates over the Dictionary of subscriptions to find a subscription by name
|
||||
func findSubscription(name:String) -> (id:String, name:String, ready:Bool)? {
|
||||
for subscription in subscriptions.values {
|
||||
if (name == subscription.name) {
|
||||
return subscription
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//
|
||||
// Unsubscribe
|
||||
//
|
||||
|
||||
public func unsub(withName name: String) -> String? {
|
||||
return unsub(withName: name, callback: nil)
|
||||
}
|
||||
|
||||
public func unsub(withName name: String, callback:(()->())?) -> String? {
|
||||
if let sub = findSubscription(name) {
|
||||
unsub(withId: sub.id, callback: callback)
|
||||
outgoingData.addOperationWithBlock() { self.sendMessage(["msg":"unsub", "id":sub.id]) }
|
||||
return sub.id
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func unsub(withId id: String, callback: (() -> ())?) {
|
||||
if let c = callback { unsubCallbacks[id] = c }
|
||||
outgoingData.addOperationWithBlock() { self.sendMessage(["msg":"unsub", "id":id]) }
|
||||
}
|
||||
|
||||
//
|
||||
// Responding to server subscription messages
|
||||
//
|
||||
|
||||
private func ready(subs: [String]) {
|
||||
for id in subs {
|
||||
if let callback = subCallbacks[id] {
|
||||
callback() // Run the callback
|
||||
subCallbacks[id] = nil // Delete the callback after running
|
||||
} else { // If there is no callback, execute the method
|
||||
if var sub = subscriptions[id] {
|
||||
sub.ready = true
|
||||
subscriptions[id] = sub
|
||||
subscriptionIsReady(sub.id, subscriptionName: sub.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func nosub(id: String, error: DDP.Error?) {
|
||||
if let e = error where (e.isValid == true) {
|
||||
print(e)
|
||||
public class DDPClient: NSObject {
|
||||
|
||||
// included for storing login id and token
|
||||
let userData = NSUserDefaults.standardUserDefaults()
|
||||
|
||||
public let incomingData:NSOperationQueue = {
|
||||
let queue = NSOperationQueue()
|
||||
queue.name = "DDP Incoming Data Queue"
|
||||
queue.maxConcurrentOperationCount = 1
|
||||
return queue
|
||||
}()
|
||||
|
||||
// Calling methods on the server + their callbacks
|
||||
public let outgoingData:NSOperationQueue = {
|
||||
let queue = NSOperationQueue()
|
||||
queue.name = "DDP Outgoing Data Queue"
|
||||
// queue.maxConcurrentOperationCount = 1
|
||||
return queue
|
||||
}()
|
||||
|
||||
public let operation:NSOperationQueue = {
|
||||
let queue = NSOperationQueue()
|
||||
queue.name = "DDP Operation Queue"
|
||||
queue.maxConcurrentOperationCount = 1
|
||||
return queue
|
||||
}()
|
||||
|
||||
public let heartbeat:NSOperationQueue = {
|
||||
let queue = NSOperationQueue()
|
||||
queue.name = "DDP Heartbeat Queue"
|
||||
//queue.maxConcurrentOperationCount = 1
|
||||
return queue
|
||||
}()
|
||||
|
||||
public let mainQueue = NSOperationQueue.mainQueue()
|
||||
|
||||
private var socket:WebSocket!
|
||||
private var server:(ping:NSDate?, pong:NSDate?) = (nil, nil)
|
||||
|
||||
var resultCallbacks:[String:(result:AnyObject?, error:DDPError?) -> ()] = [:]
|
||||
var subCallbacks:[String:() -> ()] = [:]
|
||||
var unsubCallbacks:[String:() -> ()] = [:]
|
||||
|
||||
private var url:String!
|
||||
private var subscriptions = [String:(id:String, name:String, ready:Bool)]()
|
||||
|
||||
public var logLevel = XCGLogger.LogLevel.Debug
|
||||
public var events = DDPEvents()
|
||||
public var connection:(ddp:Bool, session:String?) = (false, nil)
|
||||
|
||||
public override init() {
|
||||
super.init()
|
||||
setLogLevel(logLevel)
|
||||
}
|
||||
|
||||
public func getId() -> String {
|
||||
let numbers = Set<Character>(["0","1","2","3","4","5","6","7","8","9"])
|
||||
let uuid = NSUUID().UUIDString.stringByReplacingOccurrencesOfString("-", withString: "")
|
||||
var id = ""
|
||||
for character in uuid.characters {
|
||||
if (!numbers.contains(character) && (round(Float(arc4random()) / Float(UINT32_MAX)) == 1)) {
|
||||
id += String(character).lowercaseString
|
||||
} else {
|
||||
if let callback = unsubCallbacks[id],
|
||||
let _ = subscriptions[id] {
|
||||
callback()
|
||||
unsubCallbacks[id] = nil
|
||||
subscriptions[id] = nil
|
||||
} else {
|
||||
if let subscription = subscriptions[id] {
|
||||
subscriptions[id] = nil
|
||||
subscriptionWasRemoved(subscription.id, subscriptionName: subscription.name)
|
||||
}
|
||||
id += String(character)
|
||||
}
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
public func connect(url:String, callback:((session:String)->())?) {
|
||||
|
||||
socket = WebSocket(url)
|
||||
|
||||
socket.event.close = {code, reason, clean in
|
||||
log.info("Web socket connection closed with code \(code). Clean: \(clean). \(reason)")
|
||||
let event = self.socket.event
|
||||
self.socket = WebSocket(url)
|
||||
self.socket.event = event
|
||||
self.ping()
|
||||
}
|
||||
|
||||
socket.event.error = events.onWebsocketError
|
||||
|
||||
socket.event.open = {
|
||||
self.heartbeat.addOperationWithBlock() {
|
||||
if let c = callback { self.events.onConnected = c }
|
||||
self.sendMessage(["msg":"connect", "version":"1", "support":["1"]])
|
||||
}
|
||||
}
|
||||
|
||||
socket.event.message = { message in
|
||||
self.operation.addOperationWithBlock() {
|
||||
if let text = message as? String {
|
||||
do { try self.ddpMessageHandler(DDPMessage(message: text)) }
|
||||
catch { log.debug("Message handling error. Raw message: \(text)")}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// public callbacks: should be overridden
|
||||
//
|
||||
|
||||
public func subscriptionIsReady(subscriptionId:String, subscriptionName:String) {}
|
||||
|
||||
public func subscriptionWasRemoved(subscriptionId:String, subscriptionName:String) {}
|
||||
|
||||
public func documentWasAdded(collection:String, id:String, fields:NSDictionary?) {
|
||||
if let added = events.onAdded { added(collection: collection, id: id, fields: fields) }
|
||||
}
|
||||
|
||||
public func setLogLevel(logLevel:XCGLogger.LogLevel) {
|
||||
log.setup(logLevel, showLogIdentifier: true, showFunctionName: true, showThreadName: true, showLogLevel: true, showFileNames: false, showLineNumbers: true, showDate: false, writeToFile: nil, fileLogLevel: .None)
|
||||
}
|
||||
|
||||
private func ping() {
|
||||
heartbeat.addOperationWithBlock() {
|
||||
self.sendMessage(["msg":"ping", "id":self.getId()])
|
||||
}
|
||||
|
||||
public func documentWasRemoved(collection:String, id:String) {
|
||||
if let removed = events.onRemoved { removed(collection: collection, id: id) }
|
||||
}
|
||||
|
||||
// Respond to a server ping
|
||||
private func pong(ping: DDPMessage) {
|
||||
heartbeat.addOperationWithBlock() {
|
||||
self.server.ping = NSDate()
|
||||
log.debug("Ping")
|
||||
var response = ["msg":"pong"]
|
||||
if let id = ping.id { response["id"] = id }
|
||||
self.sendMessage(response)
|
||||
}
|
||||
}
|
||||
|
||||
// Parse DDP messages and dispatch to the appropriate function
|
||||
func ddpMessageHandler(message: DDPMessage) throws {
|
||||
|
||||
public func documentWasChanged(collection:String, id:String, fields:NSDictionary?, cleared:[String]?) {
|
||||
if let changed = events.onChanged { changed(collection:collection, id:id, fields:fields, cleared:cleared) }
|
||||
}
|
||||
log.debug("Received message: \(message.json)")
|
||||
|
||||
public func methodWasUpdated(methods:[String]) {
|
||||
if let updated = events.onUpdated { updated(methods: methods) }
|
||||
switch message.type {
|
||||
|
||||
case .Connected:
|
||||
self.connection = (true, message.session!)
|
||||
self.events.onConnected(session:message.session!)
|
||||
|
||||
case .Result: incomingData.addOperationWithBlock() {
|
||||
if let id = message.id, // Message has id
|
||||
let callback = self.resultCallbacks[id], // There is a callback registered for the message
|
||||
let result = message.result {
|
||||
callback(result:result, error: message.error)
|
||||
self.resultCallbacks[id] = nil
|
||||
} else if let id = message.id,
|
||||
let callback = self.resultCallbacks[id] {
|
||||
callback(result:nil, error:message.error)
|
||||
self.resultCallbacks[id] = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Principal callbacks for managing data
|
||||
// Document was added
|
||||
case .Added: incomingData.addOperationWithBlock() {
|
||||
if let collection = message.collection,
|
||||
let id = message.id {
|
||||
self.documentWasAdded(collection, id: id, fields: message.fields)
|
||||
}
|
||||
}
|
||||
|
||||
// Document was changed
|
||||
case .Changed: incomingData.addOperationWithBlock() {
|
||||
if let collection = message.collection,
|
||||
let id = message.id {
|
||||
self.documentWasChanged(collection, id: id, fields: message.fields, cleared: message.cleared)
|
||||
}
|
||||
}
|
||||
|
||||
// Document was removed
|
||||
case .Removed: incomingData.addOperationWithBlock() {
|
||||
if let collection = message.collection,
|
||||
let id = message.id {
|
||||
self.documentWasRemoved(collection, id: id)
|
||||
}
|
||||
}
|
||||
|
||||
// Notifies you when the result of a method changes
|
||||
case .Updated: incomingData.addOperationWithBlock() {
|
||||
if let methods = message.methods {
|
||||
self.methodWasUpdated(methods)
|
||||
}
|
||||
}
|
||||
|
||||
// Callbacks for managing subscriptions
|
||||
case .Ready: incomingData.addOperationWithBlock() {
|
||||
if let subs = message.subs {
|
||||
self.ready(subs)
|
||||
}
|
||||
}
|
||||
|
||||
// Callback that fires when subscription has been completely removed
|
||||
//
|
||||
case .Nosub: incomingData.addOperationWithBlock() {
|
||||
if let id = message.id {
|
||||
self.nosub(id, error: message.error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
case .Ping: heartbeat.addOperationWithBlock() { self.pong(message) }
|
||||
|
||||
case .Pong: heartbeat.addOperationWithBlock() { self.server.pong = NSDate() }
|
||||
|
||||
case .Error: incomingData.addOperationWithBlock() {
|
||||
self.didReceiveErrorMessage(DDPError(json: message.json))
|
||||
}
|
||||
|
||||
default: log.error("Unhandled message: \(message.json)")
|
||||
|
||||
}
|
||||
|
||||
public func didReceiveErrorMessage(message: DDP.Error) {
|
||||
if let error = events.onError { error(message: message) }
|
||||
}
|
||||
|
||||
private func sendMessage(message:NSDictionary) {
|
||||
if let m = message.stringValue() {
|
||||
self.socket.send(m)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Executes a method on the server. If a callback is passed, the callback is asynchronously
|
||||
executed when the method has completed. The callback takes two arguments: result and error. It
|
||||
the method call is successful, result contains the return value of the method, if any. If the method fails,
|
||||
error contains information about the error.
|
||||
- parameter name: The name of the method.
|
||||
- parameter params: An object containing method arguments, if any.
|
||||
- parameter callback: The closure to be executed when the save operation completes.
|
||||
*/
|
||||
public func method(name: String, params: AnyObject?, callback: ((result:AnyObject?, error: DDPError?) -> ())?) -> String {
|
||||
let id = getId()
|
||||
let message = ["msg":"method", "method":name, "id":id] as NSMutableDictionary
|
||||
if let p = params { message["params"] = p }
|
||||
if let c = callback { resultCallbacks[id] = c }
|
||||
outgoingData.addOperationWithBlock() { self.sendMessage(message) }
|
||||
return id
|
||||
}
|
||||
|
||||
//
|
||||
// Subscribe
|
||||
//
|
||||
|
||||
public func sub(id: String, name: String, params: [AnyObject]?, callback: (() -> ())?) -> String {
|
||||
if let c = callback { subCallbacks[id] = c }
|
||||
subscriptions[id] = (id, name, false)
|
||||
let message = ["msg":"sub", "name":name, "id":id] as NSMutableDictionary
|
||||
if let p = params { message["params"] = p }
|
||||
outgoingData.addOperationWithBlock() { self.sendMessage(message) }
|
||||
return id
|
||||
}
|
||||
|
||||
// Subscribe to a Meteor collection
|
||||
public func sub(name: String, params: [AnyObject]?) -> String {
|
||||
let id = getId()
|
||||
return sub(id, name: name, params: params, callback:nil)
|
||||
}
|
||||
|
||||
public func sub(name:String, params: [AnyObject]?, callback: (() -> ())?) -> String {
|
||||
let id = getId()
|
||||
return sub(id, name: name, params: params, callback: callback)
|
||||
}
|
||||
|
||||
// Iterates over the Dictionary of subscriptions to find a subscription by name
|
||||
func findSubscription(name:String) -> (id:String, name:String, ready:Bool)? {
|
||||
for subscription in subscriptions.values {
|
||||
if (name == subscription.name) {
|
||||
return subscription
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//
|
||||
// Unsubscribe
|
||||
//
|
||||
|
||||
public func unsub(withName name: String) -> String? {
|
||||
return unsub(withName: name, callback: nil)
|
||||
}
|
||||
|
||||
public func unsub(withName name: String, callback:(()->())?) -> String? {
|
||||
if let sub = findSubscription(name) {
|
||||
unsub(withId: sub.id, callback: callback)
|
||||
outgoingData.addOperationWithBlock() { self.sendMessage(["msg":"unsub", "id":sub.id]) }
|
||||
return sub.id
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func unsub(withId id: String, callback: (() -> ())?) {
|
||||
if let c = callback { unsubCallbacks[id] = c }
|
||||
outgoingData.addOperationWithBlock() { self.sendMessage(["msg":"unsub", "id":id]) }
|
||||
}
|
||||
|
||||
//
|
||||
// Responding to server subscription messages
|
||||
//
|
||||
|
||||
private func ready(subs: [String]) {
|
||||
for id in subs {
|
||||
if let callback = subCallbacks[id] {
|
||||
callback() // Run the callback
|
||||
subCallbacks[id] = nil // Delete the callback after running
|
||||
} else { // If there is no callback, execute the method
|
||||
if var sub = subscriptions[id] {
|
||||
sub.ready = true
|
||||
subscriptions[id] = sub
|
||||
subscriptionIsReady(sub.id, subscriptionName: sub.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func nosub(id: String, error: DDPError?) {
|
||||
if let e = error where (e.isValid == true) {
|
||||
print(e)
|
||||
} else {
|
||||
if let callback = unsubCallbacks[id],
|
||||
let _ = subscriptions[id] {
|
||||
callback()
|
||||
unsubCallbacks[id] = nil
|
||||
subscriptions[id] = nil
|
||||
} else {
|
||||
if let subscription = subscriptions[id] {
|
||||
subscriptions[id] = nil
|
||||
subscriptionWasRemoved(subscription.id, subscriptionName: subscription.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// public callbacks: should be overridden
|
||||
//
|
||||
|
||||
public func subscriptionIsReady(subscriptionId:String, subscriptionName:String) {}
|
||||
|
||||
public func subscriptionWasRemoved(subscriptionId:String, subscriptionName:String) {}
|
||||
|
||||
public func documentWasAdded(collection:String, id:String, fields:NSDictionary?) {
|
||||
if let added = events.onAdded { added(collection: collection, id: id, fields: fields) }
|
||||
}
|
||||
|
||||
public func documentWasRemoved(collection:String, id:String) {
|
||||
if let removed = events.onRemoved { removed(collection: collection, id: id) }
|
||||
}
|
||||
|
||||
public func documentWasChanged(collection:String, id:String, fields:NSDictionary?, cleared:[String]?) {
|
||||
if let changed = events.onChanged { changed(collection:collection, id:id, fields:fields, cleared:cleared) }
|
||||
}
|
||||
|
||||
public func methodWasUpdated(methods:[String]) {
|
||||
if let updated = events.onUpdated { updated(methods: methods) }
|
||||
}
|
||||
|
||||
public func didReceiveErrorMessage(message: DDPError) {
|
||||
if let error = events.onError { error(message: message) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,27 +20,24 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
extension DDP {
|
||||
public struct DDPEvents {
|
||||
|
||||
public var onWebsocketClose: ((code:Int, reason:String, clean:Bool) -> ())?
|
||||
public var onWebsocketError: (error:ErrorType) -> () = {error in log.error("websocket error \(error)")}
|
||||
|
||||
public var onConnected: (session:String) -> () = {session in log.info("connected with session: \(session)")}
|
||||
public var onDisconnected: () -> () = {log.debug("disconnected")}
|
||||
public var onFailed: () -> () = {log.error("failed")}
|
||||
|
||||
// Data messages
|
||||
public var onAdded: ((collection:String, id:String, fields:NSDictionary?) -> ())?
|
||||
public var onChanged: ((collection:String, id:String, fields:NSDictionary?, cleared:NSArray?) -> ())?
|
||||
public var onRemoved: ((collection:String, id:String) -> ())?
|
||||
|
||||
// RPC Messages
|
||||
// public var onResult: (json: NSDictionary?, callback:(result:AnyObject?, error:AnyObject?) -> ()) -> () = {json, callback in callback(result: json, error:nil) }
|
||||
public var onUpdated: ((methods: [String]) -> ())?
|
||||
public var onError: ((message:DDPError) -> ())?
|
||||
|
||||
public struct Events {
|
||||
|
||||
public var onWebsocketClose: ((code:Int, reason:String, clean:Bool) -> ())?
|
||||
public var onWebsocketError: (error:ErrorType) -> () = {error in log.error("websocket error \(error)")}
|
||||
|
||||
public var onConnected: (session:String) -> () = {session in log.info("connected with session: \(session)")}
|
||||
public var onDisconnected: () -> () = {log.debug("disconnected")}
|
||||
public var onFailed: () -> () = {log.error("failed")}
|
||||
|
||||
// Data messages
|
||||
public var onAdded: ((collection:String, id:String, fields:NSDictionary?) -> ())?
|
||||
public var onChanged: ((collection:String, id:String, fields:NSDictionary?, cleared:NSArray?) -> ())?
|
||||
public var onRemoved: ((collection:String, id:String) -> ())?
|
||||
|
||||
// RPC Messages
|
||||
// public var onResult: (json: NSDictionary?, callback:(result:AnyObject?, error:AnyObject?) -> ()) -> () = {json, callback in callback(result: json, error:nil) }
|
||||
public var onUpdated: ((methods: [String]) -> ())?
|
||||
public var onError: ((message:DDP.Error) -> ())?
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,16 +21,16 @@
|
|||
import Foundation
|
||||
import CryptoSwift
|
||||
|
||||
let DDP_ID = "DDP_ID"
|
||||
let DDP_EMAIL = "DDP_EMAIL"
|
||||
let DDP_USERNAME = "DDP_USERNAME"
|
||||
let DDP_TOKEN = "DDP_TOKEN"
|
||||
let DDP_TOKEN_EXPIRES = "DDP_TOKEN_EXPIRES"
|
||||
let DDP_LOGGED_IN = "DDP_LOGGED_IN"
|
||||
private let DDP_ID = "DDP_ID"
|
||||
private let DDP_EMAIL = "DDP_EMAIL"
|
||||
private let DDP_USERNAME = "DDP_USERNAME"
|
||||
private let DDP_TOKEN = "DDP_TOKEN"
|
||||
private let DDP_TOKEN_EXPIRES = "DDP_TOKEN_EXPIRES"
|
||||
private let DDP_LOGGED_IN = "DDP_LOGGED_IN"
|
||||
|
||||
let SWIFT_DDP_CALLBACK_DISPATCH_TIME = DISPATCH_TIME_FOREVER
|
||||
private let SWIFT_DDP_CALLBACK_DISPATCH_TIME = DISPATCH_TIME_FOREVER
|
||||
|
||||
let syncWarning = {(name:String) -> Void in
|
||||
private let syncWarning = {(name:String) -> Void in
|
||||
if NSThread.isMainThread() {
|
||||
print("\(name) is running synchronously on the main thread. This will block the main thread and should be run on a background thread")
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ extension NSDictionary {
|
|||
}
|
||||
|
||||
// These are implemented as an extension because they're not a part of the DDP spec
|
||||
extension DDP.Client {
|
||||
extension DDPClient {
|
||||
|
||||
public func subscribe(name:String) -> String { return sub(name, params:nil) }
|
||||
|
||||
|
@ -70,7 +70,7 @@ extension DDP.Client {
|
|||
|
||||
// callback is optional. If present, called with an error object as the first argument and,
|
||||
// if no error, the _id as the second.
|
||||
public func insert(collection: String, document: NSArray, callback: ((result:AnyObject?, error:DDP.Error?) -> ())?) -> String {
|
||||
public func insert(collection: String, document: NSArray, callback: ((result:AnyObject?, error:DDPError?) -> ())?) -> String {
|
||||
let arg = "/\(collection)/insert"
|
||||
return self.method(arg, params: document, callback: callback)
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ extension DDP.Client {
|
|||
return serverResponse
|
||||
}
|
||||
|
||||
public func update(collection: String, document: NSArray, callback: ((result:AnyObject?, error:DDP.Error?) -> ())?) -> String {
|
||||
public func update(collection: String, document: NSArray, callback: ((result:AnyObject?, error:DDPError?) -> ())?) -> String {
|
||||
let arg = "/\(collection)/update"
|
||||
return method(arg, params: document, callback: callback)
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ extension DDP.Client {
|
|||
return serverResponse
|
||||
}
|
||||
|
||||
public func remove(collection: String, document: NSArray, callback: ((result:AnyObject?, error:DDP.Error?) -> ())?) -> String {
|
||||
public func remove(collection: String, document: NSArray, callback: ((result:AnyObject?, error:DDPError?) -> ())?) -> String {
|
||||
let arg = "/\(collection)/remove"
|
||||
return method(arg, params: document, callback: callback)
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ extension DDP.Client {
|
|||
return serverResponse
|
||||
}
|
||||
|
||||
private func login(params: NSDictionary, callback: ((result: AnyObject?, error: DDP.Error?) -> ())?) {
|
||||
private func login(params: NSDictionary, callback: ((result: AnyObject?, error: DDPError?) -> ())?) {
|
||||
method("login", params: NSArray(arrayLiteral: params)) { result, error in
|
||||
guard let e = error where (e.isValid == true) else {
|
||||
|
||||
|
@ -183,7 +183,7 @@ extension DDP.Client {
|
|||
}
|
||||
|
||||
// Login with email and password
|
||||
public func loginWithPassword(email: String, password: String, callback: ((result:AnyObject?, error:DDP.Error?) -> ())?) {
|
||||
public func loginWithPassword(email: String, password: String, callback: ((result:AnyObject?, error:DDPError?) -> ())?) {
|
||||
if !(loginWithToken(callback)) {
|
||||
let params = ["user": ["email": email], "password":["digest": password.sha256()!, "algorithm":"sha-256"]] as NSDictionary
|
||||
login(params, callback: callback)
|
||||
|
@ -191,7 +191,7 @@ extension DDP.Client {
|
|||
}
|
||||
|
||||
// Does the date comparison account for TimeZone?
|
||||
public func loginWithToken(callback:((result: AnyObject?, error: DDP.Error?) -> ())?) -> Bool {
|
||||
func loginWithToken(callback:((result: AnyObject?, error: DDPError?) -> ())?) -> Bool {
|
||||
if let token = userData.stringForKey(DDP_TOKEN),
|
||||
let tokenDate = userData.objectForKey(DDP_TOKEN_EXPIRES) {
|
||||
if (tokenDate.compare(NSDate()) == NSComparisonResult.OrderedDescending) {
|
||||
|
@ -203,7 +203,7 @@ extension DDP.Client {
|
|||
return false
|
||||
}
|
||||
|
||||
public func signup(params:NSDictionary, callback:((result: AnyObject?, error: DDP.Error?) -> ())?) {
|
||||
public func signup(params:NSDictionary, callback:((result: AnyObject?, error: DDPError?) -> ())?) {
|
||||
method("createUser", params: NSArray(arrayLiteral: params)) { result, error in
|
||||
guard let e = error where (e.isValid == true) else {
|
||||
|
||||
|
@ -232,12 +232,12 @@ extension DDP.Client {
|
|||
}
|
||||
}
|
||||
|
||||
public func signupWithEmail(email: String, password: String, callback: ((result:AnyObject?, error:DDP.Error?) -> ())?) {
|
||||
public func signupWithEmail(email: String, password: String, callback: ((result:AnyObject?, error:DDPError?) -> ())?) {
|
||||
let params = ["email":email, "password":["digest":password.sha256()!, "algorithm":"sha-256"]]
|
||||
signup(params, callback: callback)
|
||||
}
|
||||
|
||||
public func signupWithEmail(email: String, password: String, profile: NSDictionary, callback: ((result:AnyObject?, error:DDP.Error?) -> ())?) {
|
||||
public func signupWithEmail(email: String, password: String, profile: NSDictionary, callback: ((result:AnyObject?, error:DDPError?) -> ())?) {
|
||||
let params = ["email":email, "password":["digest":password.sha256()!, "algorithm":"sha-256"], "profile":profile]
|
||||
signup(params, callback: callback)
|
||||
}
|
||||
|
@ -255,11 +255,11 @@ extension DDP.Client {
|
|||
}
|
||||
}
|
||||
|
||||
public func logout(callback: ((result: AnyObject?, error: DDP.Error?) -> ())?) {
|
||||
public func logout(callback: ((result: AnyObject?, error: DDPError?) -> ())?) {
|
||||
method("logout", params: nil, callback: callback)
|
||||
}
|
||||
|
||||
public convenience init(url: String, email: String, password: String, callback: (result:AnyObject?, error:DDP.Error?) -> ()) {
|
||||
public convenience init(url: String, email: String, password: String, callback: (result:AnyObject?, error:DDPError?) -> ()) {
|
||||
self.init()
|
||||
connect(url) { session in
|
||||
self.loginWithPassword(email, password: password, callback:callback)
|
||||
|
|
|
@ -20,33 +20,32 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
extension DDP {
|
||||
|
||||
// Handled Message Types
|
||||
public enum DDPMessageType:String {
|
||||
|
||||
// Handled Message Types
|
||||
public enum MessageType:String {
|
||||
|
||||
// case Connect = "connect" // (client -> server)
|
||||
case Connected = "connected"
|
||||
case Failed = "failed"
|
||||
case Ping = "ping"
|
||||
case Pong = "pong"
|
||||
// case Sub = "sub" // (client -> server)
|
||||
// case Unsub = "unsub" // (client -> server)
|
||||
case Nosub = "nosub"
|
||||
case Added = "added"
|
||||
case Changed = "changed"
|
||||
case Removed = "removed"
|
||||
case Ready = "ready"
|
||||
case AddedBefore = "addedBefore"
|
||||
case MovedBefore = "movedBefore"
|
||||
// case Method = "method" // (client -> server)
|
||||
case Result = "result"
|
||||
case Updated = "updated"
|
||||
case Error = "error"
|
||||
case Unhandled = "unhandled"
|
||||
|
||||
}
|
||||
// case Connect = "connect" // (client -> server)
|
||||
case Connected = "connected"
|
||||
case Failed = "failed"
|
||||
case Ping = "ping"
|
||||
case Pong = "pong"
|
||||
// case Sub = "sub" // (client -> server)
|
||||
// case Unsub = "unsub" // (client -> server)
|
||||
case Nosub = "nosub"
|
||||
case Added = "added"
|
||||
case Changed = "changed"
|
||||
case Removed = "removed"
|
||||
case Ready = "ready"
|
||||
case AddedBefore = "addedBefore"
|
||||
case MovedBefore = "movedBefore"
|
||||
// case Method = "method" // (client -> server)
|
||||
case Result = "result"
|
||||
case Updated = "updated"
|
||||
case Error = "error"
|
||||
case Unhandled = "unhandled"
|
||||
|
||||
}
|
||||
|
||||
// Method or Nosub error
|
||||
// Such an Error is used to represent errors raised by the method or subscription,
|
||||
// as well as an attempt to subscribe to an unknown subscription or call an unknown method.
|
||||
|
@ -61,156 +60,158 @@ extension DDP {
|
|||
|
||||
// - reason: string describing the error
|
||||
// - offendingMessage: if the original message parsed properly, it is included here
|
||||
|
||||
|
||||
public struct DDPMessage {
|
||||
|
||||
public struct Error {
|
||||
// SwiftyJSON JSON Object
|
||||
public var json:NSDictionary!
|
||||
|
||||
public init(message:String) {
|
||||
|
||||
private var json:NSDictionary?
|
||||
|
||||
public var error:String? { return json?["error"] as? String } // Error code
|
||||
public var reason:String? { return json?["reason"] as? String }
|
||||
public var details:String? { return json?["details"] as? String }
|
||||
public var offendingMessage:String? { return json?["offendingMessage"] as? String }
|
||||
|
||||
var isValid:Bool {
|
||||
if let _ = error { return true }
|
||||
if let _ = reason { return true }
|
||||
return false
|
||||
}
|
||||
|
||||
init(json:AnyObject?) {
|
||||
self.json = json as? NSDictionary
|
||||
if let JSON = message.dictionaryValue() { json = JSON }
|
||||
else {
|
||||
json = ["msg":"error", "reason":"SwiftDDP JSON serialization error.",
|
||||
"details": "SwiftDDP JSON serialization error. JSON string was: \(message). Message will be handled as a DDP message error."]
|
||||
}
|
||||
}
|
||||
|
||||
public struct Message {
|
||||
|
||||
// SwiftyJSON JSON Object
|
||||
public var json:NSDictionary!
|
||||
|
||||
public init(message:String) {
|
||||
|
||||
if let JSON = message.dictionaryValue() { json = JSON }
|
||||
else {
|
||||
json = ["msg":"error", "reason":"SwiftDDP JSON serialization error.",
|
||||
"details": "SwiftDDP JSON serialization error. JSON string was: \(message). Message will be handled as a DDP message error."]
|
||||
}
|
||||
public init(message:[String:String]) {
|
||||
json = message as NSDictionary
|
||||
}
|
||||
|
||||
// Converts an NSDictionary to a JSON String
|
||||
public static func toString(json:AnyObject) -> String? {
|
||||
if let data = try? NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions(rawValue: 0)) {
|
||||
let message = NSString(data: data, encoding: NSASCIIStringEncoding) as String?
|
||||
return message
|
||||
}
|
||||
|
||||
public init(message:[String:String]) {
|
||||
json = message as NSDictionary
|
||||
return nil
|
||||
}
|
||||
|
||||
//
|
||||
// Computed variables
|
||||
//
|
||||
|
||||
// Returns the type of DDP message, or unhandled if it is not a DDP message
|
||||
public var type:DDPMessageType {
|
||||
if let msg = message,
|
||||
let type = DDPMessageType(rawValue: msg) {
|
||||
return type
|
||||
}
|
||||
|
||||
// Converts an NSDictionary to a JSON String
|
||||
public static func toString(json:AnyObject) -> String? {
|
||||
if let data = try? NSJSONSerialization.dataWithJSONObject(json, options: NSJSONWritingOptions(rawValue: 0)) {
|
||||
let message = NSString(data: data, encoding: NSASCIIStringEncoding) as String?
|
||||
return message
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//
|
||||
// Computed variables
|
||||
//
|
||||
|
||||
// Returns the type of DDP message, or unhandled if it is not a DDP message
|
||||
public var type:DDP.MessageType {
|
||||
if let msg = message,
|
||||
let type = DDP.MessageType(rawValue: msg) {
|
||||
return type
|
||||
}
|
||||
return DDP.MessageType(rawValue: "unhandled")!
|
||||
}
|
||||
|
||||
public var isError:Bool {
|
||||
if (self.type == .Error) { return true } // if message is a top level error ("msg"="error")
|
||||
if let _ = self.error { return true } // if message contains an error object, as in method or nosub
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns the root-level keys of the JSON object
|
||||
public var keys:[String] {
|
||||
return json.allKeys as! [String]
|
||||
}
|
||||
|
||||
public func hasProperty(name:String) -> Bool {
|
||||
if let property = json[name] where ((property as! NSObject) != NSNull()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public var message:String? {
|
||||
get { return json["msg"] as? String }
|
||||
}
|
||||
|
||||
public var session:String? {
|
||||
get { return json["session"] as? String }
|
||||
}
|
||||
|
||||
public var version:String? {
|
||||
get { return json["version"] as? String }
|
||||
}
|
||||
|
||||
public var support:String? {
|
||||
get { return json["support"] as? String }
|
||||
}
|
||||
|
||||
public var id:String? {
|
||||
get { return json["id"] as? String }
|
||||
}
|
||||
|
||||
public var name:String? {
|
||||
get { return json["name"] as? String }
|
||||
}
|
||||
|
||||
public var params:String? {
|
||||
get { return json["params"] as? String }
|
||||
}
|
||||
|
||||
public var error:DDP.Error? {
|
||||
get { if let e = json["error"] as? NSDictionary { return DDP.Error(json:e) } else { return nil }}
|
||||
}
|
||||
|
||||
public var collection:String? {
|
||||
get { return json["collection"] as? String }
|
||||
}
|
||||
|
||||
public var fields:NSDictionary? {
|
||||
get { return json["fields"] as? NSDictionary }
|
||||
}
|
||||
|
||||
public var cleared:[String]? {
|
||||
get { return json["cleared"] as? [String] }
|
||||
}
|
||||
|
||||
public var method:String? {
|
||||
get { return json["method"] as? String }
|
||||
}
|
||||
|
||||
public var randomSeed:String? {
|
||||
get { return json["randomSeed"] as? String }
|
||||
}
|
||||
|
||||
public var result:AnyObject? {
|
||||
get { return json["result"] }
|
||||
}
|
||||
|
||||
public var methods:[String]? {
|
||||
get { return json["methods"] as? [String] }
|
||||
}
|
||||
|
||||
public var subs:[String]? {
|
||||
get { return json["subs"] as? [String] }
|
||||
}
|
||||
|
||||
// Communication error properties
|
||||
public var reason:String? {
|
||||
get { return json["reason"] as? String }
|
||||
}
|
||||
|
||||
public var offendingMessage:String? {
|
||||
get { return json["offendingMessage"] as? String }
|
||||
return DDPMessageType(rawValue: "unhandled")!
|
||||
}
|
||||
|
||||
public var isError:Bool {
|
||||
if (self.type == .Error) { return true } // if message is a top level error ("msg"="error")
|
||||
if let _ = self.error { return true } // if message contains an error object, as in method or nosub
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns the root-level keys of the JSON object
|
||||
public var keys:[String] {
|
||||
return json.allKeys as! [String]
|
||||
}
|
||||
|
||||
public func hasProperty(name:String) -> Bool {
|
||||
if let property = json[name] where ((property as! NSObject) != NSNull()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public var message:String? {
|
||||
get { return json["msg"] as? String }
|
||||
}
|
||||
|
||||
public var session:String? {
|
||||
get { return json["session"] as? String }
|
||||
}
|
||||
|
||||
public var version:String? {
|
||||
get { return json["version"] as? String }
|
||||
}
|
||||
|
||||
public var support:String? {
|
||||
get { return json["support"] as? String }
|
||||
}
|
||||
|
||||
public var id:String? {
|
||||
get { return json["id"] as? String }
|
||||
}
|
||||
|
||||
public var name:String? {
|
||||
get { return json["name"] as? String }
|
||||
}
|
||||
|
||||
public var params:String? {
|
||||
get { return json["params"] as? String }
|
||||
}
|
||||
|
||||
public var error:DDPError? {
|
||||
get { if let e = json["error"] as? NSDictionary { return DDPError(json:e) } else { return nil }}
|
||||
}
|
||||
|
||||
public var collection:String? {
|
||||
get { return json["collection"] as? String }
|
||||
}
|
||||
|
||||
public var fields:NSDictionary? {
|
||||
get { return json["fields"] as? NSDictionary }
|
||||
}
|
||||
|
||||
public var cleared:[String]? {
|
||||
get { return json["cleared"] as? [String] }
|
||||
}
|
||||
|
||||
public var method:String? {
|
||||
get { return json["method"] as? String }
|
||||
}
|
||||
|
||||
public var randomSeed:String? {
|
||||
get { return json["randomSeed"] as? String }
|
||||
}
|
||||
|
||||
public var result:AnyObject? {
|
||||
get { return json["result"] }
|
||||
}
|
||||
|
||||
public var methods:[String]? {
|
||||
get { return json["methods"] as? [String] }
|
||||
}
|
||||
|
||||
public var subs:[String]? {
|
||||
get { return json["subs"] as? [String] }
|
||||
}
|
||||
|
||||
// Communication error properties
|
||||
public var reason:String? {
|
||||
get { return json["reason"] as? String }
|
||||
}
|
||||
|
||||
public var offendingMessage:String? {
|
||||
get { return json["offendingMessage"] as? String }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public struct DDPError {
|
||||
|
||||
private var json:NSDictionary?
|
||||
|
||||
public var error:String? { return json?["error"] as? String } // Error code
|
||||
public var reason:String? { return json?["reason"] as? String }
|
||||
public var details:String? { return json?["details"] as? String }
|
||||
public var offendingMessage:String? { return json?["offendingMessage"] as? String }
|
||||
|
||||
var isValid:Bool {
|
||||
if let _ = error { return true }
|
||||
if let _ = reason { return true }
|
||||
return false
|
||||
}
|
||||
|
||||
init(json:AnyObject?) {
|
||||
self.json = json as? NSDictionary
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,5 +22,5 @@ import Foundation
|
|||
|
||||
public struct Result {
|
||||
public var result:AnyObject?
|
||||
public var error:DDP.Error?
|
||||
public var error:DDPError?
|
||||
}
|
|
@ -53,7 +53,7 @@ public class Meteor {
|
|||
}
|
||||
}
|
||||
|
||||
public class Client: DDP.Client {
|
||||
public class Client: DDPClient {
|
||||
|
||||
typealias SubscriptionCallback = () -> ()
|
||||
let notifications = NSNotificationCenter.defaultCenter()
|
||||
|
@ -93,11 +93,11 @@ public class Meteor {
|
|||
}
|
||||
}
|
||||
|
||||
public class Collection: NSObject, MeteorCollectionType {
|
||||
public class MeteorCollection: NSObject, MeteorCollectionType {
|
||||
|
||||
internal var name:String
|
||||
internal let client = Meteor.client
|
||||
|
||||
public let client = Meteor.client
|
||||
public var name:String!
|
||||
var token: dispatch_once_t = 0
|
||||
// Can also set these closures to modify behavior on added, changed, removed
|
||||
public var onAdded:((collection:String, id:String, fields:NSDictionary?) -> ())?
|
||||
public var onChanged:((collection:String, id:String, fields:NSDictionary?, cleared:[String]?) -> ())?
|
||||
|
@ -105,8 +105,8 @@ public class Collection: NSObject, MeteorCollectionType {
|
|||
|
||||
// Must use the constructor function to create the collection
|
||||
public init(name:String) {
|
||||
super.init()
|
||||
self.name = name
|
||||
super.init()
|
||||
Meteor.collections[name] = self
|
||||
}
|
||||
|
||||
|
@ -114,35 +114,6 @@ public class Collection: NSObject, MeteorCollectionType {
|
|||
Meteor.collections[name] = nil
|
||||
}
|
||||
|
||||
// Because this class must inherit from NSObject (an Objective-C class) to use NSNotificationCenter, and Objective-C does not
|
||||
// support method overloading, these conflict with collection subclasses and have been commented out.
|
||||
|
||||
/*
|
||||
public func insert(doc:[NSDictionary]) -> String {
|
||||
return client.insert(name, doc: doc)
|
||||
}
|
||||
|
||||
public func insert(doc:NSArray, callback:((result:AnyObject?, error:DDP.Error?) -> ())?) -> String {
|
||||
return client.insert(name, doc:doc, callback:callback)
|
||||
}
|
||||
|
||||
public func update(doc:[NSDictionary]) -> String {
|
||||
return client.update(name, doc: doc)
|
||||
}
|
||||
|
||||
public func update(doc:[NSDictionary], callback:((result:AnyObject?, error:DDP.Error?) -> ())?) -> String {
|
||||
return client.update(name, doc:doc, callback:callback)
|
||||
}
|
||||
|
||||
public func remove(doc:[NSDictionary]) -> String {
|
||||
return client.remove(name, doc: doc)
|
||||
}
|
||||
|
||||
public func remove(doc:[NSDictionary], callback:((result:AnyObject?, error:DDP.Error?) -> ())?) -> String {
|
||||
return client.remove(name, doc:doc, callback:callback)
|
||||
}
|
||||
*/
|
||||
|
||||
// Override these methods to subclass Collection
|
||||
public func documentWasAdded(collection:String, id:String, fields:NSDictionary?) {
|
||||
if let added = onAdded { added(collection: collection, id: id, fields:fields) }
|
||||
|
|
|
@ -1,3 +1,22 @@
|
|||
// Copyright (c) 2015 Peter Siegesmund <peter.siegesmund@icloud.com>
|
||||
//
|
||||
// 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
|
||||
|
||||
|
|
|
@ -1,8 +1,27 @@
|
|||
// Copyright (c) 2015 Peter Siegesmund <peter.siegesmund@icloud.com>
|
||||
//
|
||||
// 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
|
||||
|
||||
public class MeteorCoreData {
|
||||
static let stack:MeteorCoreDataCollectionStack = {
|
||||
static let stack:MeteorCoreDataStack = {
|
||||
print("Initializing MeteorCoreDataStack")
|
||||
return MeteorCoreDataStackPersisted()
|
||||
}()
|
||||
|
|
|
@ -1,3 +1,22 @@
|
|||
// Copyright (c) 2015 Peter Siegesmund <peter.siegesmund@icloud.com>
|
||||
//
|
||||
// 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 UIKit
|
||||
import CoreData
|
||||
|
@ -8,7 +27,7 @@ public protocol MeteorCoreDataCollectionDelegate {
|
|||
func document(willBeUpdatedWith fields:NSDictionary?, cleared:[String]?, forObject object:NSManagedObject) -> NSManagedObject
|
||||
}
|
||||
|
||||
public class MeteorCoreDataCollection:Collection {
|
||||
public class MeteorCoreDataCollection:MeteorCollection {
|
||||
|
||||
private let entityName:String
|
||||
private let stack:MeteorCoreDataStack
|
||||
|
|
|
@ -1,3 +1,24 @@
|
|||
// Copyright (c) 2015 Peter Siegesmund <peter.siegesmund@icloud.com>
|
||||
//
|
||||
// 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
|
||||
import CoreData
|
||||
|
||||
|
|
|
@ -1,3 +1,22 @@
|
|||
// Copyright (c) 2015 Peter Siegesmund <peter.siegesmund@icloud.com>
|
||||
//
|
||||
// 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 UIKit
|
||||
import CoreData
|
||||
|
|
|
@ -15,36 +15,36 @@ let url = "ws://swiftddp.meteor.com/websocket"
|
|||
let user = "test@user.com"
|
||||
let pass = "swiftddp"
|
||||
|
||||
let ready = DDP.Message(message: "{\"msg\":\"ready\", \"subs\":[\"AllStates\"]}")
|
||||
let nosub = DDP.Message(message: ["msg":"nosub", "id":"AllStates"])
|
||||
let ready = DDPMessage(message: "{\"msg\":\"ready\", \"subs\":[\"AllStates\"]}")
|
||||
let nosub = DDPMessage(message: ["msg":"nosub", "id":"AllStates"])
|
||||
|
||||
let added = [DDP.Message(message: "{\"collection\" : \"test-collection\", \"id\" : \"2gAMzqvE8K8kBWK8F\", \"fields\" : {\"state\" : \"MA\", \"city\" : \"Boston\"}, \"msg\" : \"added\"}"),
|
||||
DDP.Message(message:"{\"collection\" : \"test-collection\", \"id\" : \"ByuwhKPGuLru8h4TT\", \"fields\" : {\"state\" : \"MA\", \"city\" : \"Truro\"}, \"msg\" : \"added\"}"),
|
||||
DDP.Message(message:"{\"collection\" : \"test-collection\", \"id\" : \"AGX6vyxCJtjqdxbFH\", \"fields\" : {\"state\" : \"TX\", \"city\" : \"Austin\"}, \"msg\" : \"added\"}")]
|
||||
let added = [DDPMessage(message: "{\"collection\" : \"test-collection\", \"id\" : \"2gAMzqvE8K8kBWK8F\", \"fields\" : {\"state\" : \"MA\", \"city\" : \"Boston\"}, \"msg\" : \"added\"}"),
|
||||
DDPMessage(message:"{\"collection\" : \"test-collection\", \"id\" : \"ByuwhKPGuLru8h4TT\", \"fields\" : {\"state\" : \"MA\", \"city\" : \"Truro\"}, \"msg\" : \"added\"}"),
|
||||
DDPMessage(message:"{\"collection\" : \"test-collection\", \"id\" : \"AGX6vyxCJtjqdxbFH\", \"fields\" : {\"state\" : \"TX\", \"city\" : \"Austin\"}, \"msg\" : \"added\"}")]
|
||||
|
||||
let removed = [DDP.Message(message: ["msg" : "removed", "id" : "2gAMzqvE8K8kBWK8F","collection" : "test-collection"]),
|
||||
DDP.Message(message: ["msg" : "removed", "id" : "ByuwhKPGuLru8h4TT", "collection" : "test-collection"]),
|
||||
DDP.Message(message:["msg" : "removed", "id" : "AGX6vyxCJtjqdxbFH", "collection" : "test-collection"])]
|
||||
let removed = [DDPMessage(message: ["msg" : "removed", "id" : "2gAMzqvE8K8kBWK8F","collection" : "test-collection"]),
|
||||
DDPMessage(message: ["msg" : "removed", "id" : "ByuwhKPGuLru8h4TT", "collection" : "test-collection"]),
|
||||
DDPMessage(message:["msg" : "removed", "id" : "AGX6vyxCJtjqdxbFH", "collection" : "test-collection"])]
|
||||
|
||||
let changed = [DDP.Message(message: "{\"collection\" : \"test-collection\", \"id\" : \"2gAMzqvE8K8kBWK8F\",\"cleared\" : [\"city\"], \"fields\" : {\"state\" : \"MA\", \"city\" : \"Amherst\"}, \"msg\" : \"changed\"}"),
|
||||
DDP.Message(message:"{\"collection\" : \"test-collection\", \"id\" : \"ByuwhKPGuLru8h4TT\", \"fields\" : {\"state\" : \"MA\", \"city\" : \"Cambridge\"}, \"msg\" : \"changed\"}"),
|
||||
DDP.Message(message:"{\"collection\" : \"test-collection\", \"id\" : \"AGX6vyxCJtjqdxbFH\", \"fields\" : {\"state\" : \"TX\", \"city\" : \"Houston\"}, \"msg\" : \"changed\"}")]
|
||||
let changed = [DDPMessage(message: "{\"collection\" : \"test-collection\", \"id\" : \"2gAMzqvE8K8kBWK8F\",\"cleared\" : [\"city\"], \"fields\" : {\"state\" : \"MA\", \"city\" : \"Amherst\"}, \"msg\" : \"changed\"}"),
|
||||
DDPMessage(message:"{\"collection\" : \"test-collection\", \"id\" : \"ByuwhKPGuLru8h4TT\", \"fields\" : {\"state\" : \"MA\", \"city\" : \"Cambridge\"}, \"msg\" : \"changed\"}"),
|
||||
DDPMessage(message:"{\"collection\" : \"test-collection\", \"id\" : \"AGX6vyxCJtjqdxbFH\", \"fields\" : {\"state\" : \"TX\", \"city\" : \"Houston\"}, \"msg\" : \"changed\"}")]
|
||||
|
||||
let userAddedWithPassword = DDP.Message(message: "{\"collection\" : \"users\", \"id\" : \"123456abcdefg\", \"fields\" : {\"roles\" : [\"admin\"], \"emails\" : [{\"address\" : \"test@user.com\", \"verified\" : false}], \"username\" : \"test\"}, \"msg\" : \"added\"}")
|
||||
let userAddedWithPassword = DDPMessage(message: "{\"collection\" : \"users\", \"id\" : \"123456abcdefg\", \"fields\" : {\"roles\" : [\"admin\"], \"emails\" : [{\"address\" : \"test@user.com\", \"verified\" : false}], \"username\" : \"test\"}, \"msg\" : \"added\"}")
|
||||
|
||||
|
||||
|
||||
let addedRealm = [DDP.Message(message: "{\"collection\" : \"Cities\", \"id\" : \"2gAMzqvE8K8kBWK8F\", \"fields\" : {\"state\" : \"MA\", \"city\" : \"Boston\"}, \"msg\" : \"added\"}"),
|
||||
DDP.Message(message:"{\"collection\" : \"Cities\", \"id\" : \"ByuwhKPGuLru8h4TT\", \"fields\" : {\"state\" : \"MA\", \"city\" : \"Truro\"}, \"msg\" : \"added\"}"),
|
||||
DDP.Message(message:"{\"collection\" : \"Cities\", \"id\" : \"AGX6vyxCJtjqdxbFH\", \"fields\" : {\"state\" : \"TX\", \"city\" : \"Austin\"}, \"msg\" : \"added\"}")]
|
||||
let addedRealm = [DDPMessage(message: "{\"collection\" : \"Cities\", \"id\" : \"2gAMzqvE8K8kBWK8F\", \"fields\" : {\"state\" : \"MA\", \"city\" : \"Boston\"}, \"msg\" : \"added\"}"),
|
||||
DDPMessage(message:"{\"collection\" : \"Cities\", \"id\" : \"ByuwhKPGuLru8h4TT\", \"fields\" : {\"state\" : \"MA\", \"city\" : \"Truro\"}, \"msg\" : \"added\"}"),
|
||||
DDPMessage(message:"{\"collection\" : \"Cities\", \"id\" : \"AGX6vyxCJtjqdxbFH\", \"fields\" : {\"state\" : \"TX\", \"city\" : \"Austin\"}, \"msg\" : \"added\"}")]
|
||||
|
||||
let removedRealm = [DDP.Message(message: ["msg" : "removed", "id" : "2gAMzqvE8K8kBWK8F","collection" : "Cities"]),
|
||||
DDP.Message(message: ["msg" : "removed", "id" : "ByuwhKPGuLru8h4TT", "collection" : "Cities"]),
|
||||
DDP.Message(message:["msg" : "removed", "id" : "AGX6vyxCJtjqdxbFH", "collection" : "Cities"])]
|
||||
let removedRealm = [DDPMessage(message: ["msg" : "removed", "id" : "2gAMzqvE8K8kBWK8F","collection" : "Cities"]),
|
||||
DDPMessage(message: ["msg" : "removed", "id" : "ByuwhKPGuLru8h4TT", "collection" : "Cities"]),
|
||||
DDPMessage(message:["msg" : "removed", "id" : "AGX6vyxCJtjqdxbFH", "collection" : "Cities"])]
|
||||
|
||||
|
||||
let changedRealm = [DDP.Message(message: "{\"collection\" : \"Cities\", \"id\" : \"2gAMzqvE8K8kBWK8F\",\"cleared\" : [\"city\"], \"fields\" : {\"state\" : \"MA\", \"city\" : \"Amherst\"}, \"msg\" : \"changed\"}"),
|
||||
DDP.Message(message:"{\"collection\" : \"Cities\", \"id\" : \"ByuwhKPGuLru8h4TT\", \"fields\" : {\"state\" : \"MA\", \"city\" : \"Cambridge\"}, \"msg\" : \"changed\"}"),
|
||||
DDP.Message(message:"{\"collection\" : \"Cities\", \"id\" : \"AGX6vyxCJtjqdxbFH\", \"fields\" : {\"state\" : \"TX\", \"city\" : \"Houston\"}, \"msg\" : \"changed\"}")]
|
||||
let changedRealm = [DDPMessage(message: "{\"collection\" : \"Cities\", \"id\" : \"2gAMzqvE8K8kBWK8F\",\"cleared\" : [\"city\"], \"fields\" : {\"state\" : \"MA\", \"city\" : \"Amherst\"}, \"msg\" : \"changed\"}"),
|
||||
DDPMessage(message:"{\"collection\" : \"Cities\", \"id\" : \"ByuwhKPGuLru8h4TT\", \"fields\" : {\"state\" : \"MA\", \"city\" : \"Cambridge\"}, \"msg\" : \"changed\"}"),
|
||||
DDPMessage(message:"{\"collection\" : \"Cities\", \"id\" : \"AGX6vyxCJtjqdxbFH\", \"fields\" : {\"state\" : \"TX\", \"city\" : \"Houston\"}, \"msg\" : \"changed\"}")]
|
||||
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class DDPMessageTest:QuickSpec {
|
|||
describe ("DDPMessage") {
|
||||
|
||||
it ("can be created from a Dictionary") {
|
||||
let message = DDP.Message(message: ["msg":"test", "id":"test100"])
|
||||
let message = DDPMessage(message: ["msg":"test", "id":"test100"])
|
||||
expect(message.hasProperty("msg")).to(beTrue())
|
||||
expect(message.hasProperty("id")).to(beTruthy())
|
||||
expect(message.id!).to(equal("test100"))
|
||||
|
@ -22,7 +22,7 @@ class DDPMessageTest:QuickSpec {
|
|||
}
|
||||
|
||||
it ("can be created from a String") {
|
||||
let message = DDP.Message(message: "{\"msg\":\"test\", \"id\":\"test100\"}")
|
||||
let message = DDPMessage(message: "{\"msg\":\"test\", \"id\":\"test100\"}")
|
||||
expect(message.hasProperty("msg")).to(beTruthy())
|
||||
expect(message.hasProperty("id")).to(beTruthy())
|
||||
expect(message.id!).to(equal("test100"))
|
||||
|
@ -31,18 +31,18 @@ class DDPMessageTest:QuickSpec {
|
|||
|
||||
|
||||
it ("handles malformed json without crashing") {
|
||||
let message = DDP.Message(message: "{\"msg\":\"test\", \"id\"test100\"}")
|
||||
let message = DDPMessage(message: "{\"msg\":\"test\", \"id\"test100\"}")
|
||||
expect(message.isError).to(beTrue())
|
||||
expect(message.reason!).to(equal("SwiftDDP JSON serialization error."))
|
||||
}
|
||||
|
||||
it ("Sends malformed json to the error handler callback") {
|
||||
|
||||
var error:DDP.Error!
|
||||
var error:DDPError!
|
||||
|
||||
let client = DDP.Client()
|
||||
let client = DDPClient()
|
||||
client.events.onError = {e in error = e }
|
||||
let message = DDP.Message(message: "{\"msg\":\"test\", \"id\"test100\"}")
|
||||
let message = DDPMessage(message: "{\"msg\":\"test\", \"id\"test100\"}")
|
||||
try! client.ddpMessageHandler(message)
|
||||
|
||||
expect(message.isError).to(beTrue())
|
||||
|
@ -58,7 +58,7 @@ class DDPMessageTest:QuickSpec {
|
|||
describe ("DDPMessageHandler routing") {
|
||||
|
||||
it ("can handle an 'added' message"){
|
||||
let client = DDP.Client()
|
||||
let client = DDPClient()
|
||||
client.events.onAdded = {collection, id, fields in
|
||||
expect(collection).to(equal("test-collection"))
|
||||
expect(id).to(equal("2gAMzqvE8K8kBWK8F"))
|
||||
|
@ -69,7 +69,7 @@ class DDPMessageTest:QuickSpec {
|
|||
}
|
||||
|
||||
it ("can handle a 'removed' message") {
|
||||
let client = DDP.Client()
|
||||
let client = DDPClient()
|
||||
client.events.onRemoved = {collection, id in
|
||||
expect(collection).to(equal("test-collection"))
|
||||
expect(id).to(equal("2gAMzqvE8K8kBWK8F"))
|
||||
|
@ -80,16 +80,16 @@ class DDPMessageTest:QuickSpec {
|
|||
it ("can handle a result message that returns a value") {
|
||||
var value:String!
|
||||
var r:AnyObject?
|
||||
var e:DDP.Error?
|
||||
var e:DDPError?
|
||||
|
||||
let client = DDP.Client()
|
||||
client.resultCallbacks["1"] = {(result:AnyObject?, error:DDP.Error?) -> () in
|
||||
let client = DDPClient()
|
||||
client.resultCallbacks["1"] = {(result:AnyObject?, error:DDPError?) -> () in
|
||||
value = result as! String
|
||||
r = result
|
||||
e = error
|
||||
}
|
||||
|
||||
try! client.ddpMessageHandler(DDP.Message(message: ["id":"1", "msg":"result", "result":"test123"]))
|
||||
try! client.ddpMessageHandler(DDPMessage(message: ["id":"1", "msg":"result", "result":"test123"]))
|
||||
expect(r).toEventuallyNot(beNil())
|
||||
expect(e).to(beNil())
|
||||
expect(value).toEventually(equal("test123"))
|
||||
|
@ -99,16 +99,16 @@ class DDPMessageTest:QuickSpec {
|
|||
it ("can handle a result message that does not return a value") {
|
||||
var value:String!
|
||||
var r:AnyObject?
|
||||
var e:DDP.Error?
|
||||
var e:DDPError?
|
||||
|
||||
let client = DDP.Client()
|
||||
client.resultCallbacks["1"] = {(result:AnyObject?, error:DDP.Error?) -> ()
|
||||
let client = DDPClient()
|
||||
client.resultCallbacks["1"] = {(result:AnyObject?, error:DDPError?) -> ()
|
||||
in if let v = result as? String { value = v }
|
||||
r = result
|
||||
e = error
|
||||
}
|
||||
|
||||
try! client.ddpMessageHandler(DDP.Message(message: ["id":"1", "msg":"result"]))
|
||||
try! client.ddpMessageHandler(DDPMessage(message: ["id":"1", "msg":"result"]))
|
||||
expect(value).to(beNil())
|
||||
expect(r).to(beNil())
|
||||
expect(e).to(beNil())
|
||||
|
@ -125,7 +125,7 @@ class DDPServerTests:QuickSpec {
|
|||
|
||||
it ("can connect to a DDP server"){
|
||||
var testSession:String?
|
||||
let client = DDP.Client()
|
||||
let client = DDPClient()
|
||||
client.connect(url) { session in testSession = session }
|
||||
expect(client.connection.ddp).toEventually(beTrue(), timeout:5)
|
||||
expect(client.connection.session).toEventually(equal(testSession), timeout:5)
|
||||
|
@ -145,7 +145,7 @@ class DDPServerTests:QuickSpec {
|
|||
var testResult:NSDictionary!
|
||||
var testSession:String!
|
||||
|
||||
let client = DDP.Client()
|
||||
let client = DDPClient()
|
||||
client.connect(url) { session in
|
||||
testSession = session
|
||||
client.loginWithPassword(user, password: pass) { result, e in
|
||||
|
@ -167,7 +167,7 @@ class DDPServerTests:QuickSpec {
|
|||
it ("can add and remove a document on the server"){
|
||||
var added = [NSDictionary]()
|
||||
var removed = [String]()
|
||||
let client = DDP.Client()
|
||||
let client = DDPClient()
|
||||
let _id = client.getId()
|
||||
|
||||
client.events.onAdded = { collection, id, fields in if ((collection == "test-collection2") && (_id == id)) { added.append(fields!) } }
|
||||
|
@ -200,7 +200,7 @@ class DDPServerTests:QuickSpec {
|
|||
it ("can update a document in a collection") {
|
||||
var added = [NSDictionary]()
|
||||
var updated = [NSDictionary]()
|
||||
let client = DDP.Client()
|
||||
let client = DDPClient()
|
||||
|
||||
let _id = client.getId()
|
||||
|
||||
|
@ -236,7 +236,7 @@ class DDPServerTests:QuickSpec {
|
|||
|
||||
it ("can execute a method on the server that returns a value") {
|
||||
var response:String!
|
||||
let client = DDP.Client()
|
||||
let client = DDPClient()
|
||||
|
||||
client.connect(url) { session in
|
||||
client.loginWithPassword(user, password: pass) { result, error in
|
||||
|
@ -268,7 +268,7 @@ class DDPServerTests:QuickSpec {
|
|||
it ("can subscribe and unsubscribe to a collection") {
|
||||
var added = [String]()
|
||||
var removed = [String]()
|
||||
let client = DDP.Client()
|
||||
let client = DDPClient()
|
||||
client.connect(url) {session in
|
||||
client.loginWithPassword(user, password: pass) {result, error in
|
||||
client.events.onAdded = {collection, id, fields in added.append(id) }
|
||||
|
|
|
@ -8,7 +8,7 @@ class MeteorTest: QuickSpec {
|
|||
override func spec() {
|
||||
|
||||
let client = Meteor.client
|
||||
let collection = Collection(name: "test-collection")
|
||||
let collection = MeteorCollection(name: "test-collection")
|
||||
|
||||
describe("Collections") {
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue