merged documentation updates from CoreData branch

This commit is contained in:
Peter 2015-11-01 14:00:56 -05:00
parent 692a8c6968
commit eb4fcdd6b1
6 changed files with 268 additions and 29 deletions

View File

@ -35,6 +35,10 @@ let log = XCGLogger(identifier: "DDP")
public typealias DDPMethodCallback = (result:AnyObject?, error:DDPError?) -> ()
public typealias DDPCallback = () -> ()
/**
DDPClient is the base class for communicating with a server using the DDP protocol
*/
public class DDPClient: NSObject {
// included for storing login id and token

View File

@ -20,23 +20,103 @@
import Foundation
/**
DDPEvents is a struct holder for callback closures that execute in response to
websocket and Meteor lifecyle events. New closures can be assigned to public
closures to modify the clients behavior in response to the trigger event.
*/
public struct DDPEvents {
public var onWebsocketClose: ((code:Int, reason:String, clean:Bool) -> ())?
public var onWebsocketError: (error:ErrorType) -> () = {error in log.error("websocket error \(error)")}
/**
onWebsocketClose executes when the websocket connection has closed
- parameter code: An integer value that provides the reason code for closing the websocket connection
- parameter reason: A string describing the reason that the websocket was closed
- parameter clean: A boolean value indicating if the websocket connection was closed cleanly
*/
internal var onWebsocketClose: ((code:Int, reason:String, clean:Bool) -> ())?
/**
onWebsocketError executes when the websocket connection returns an error.
- parameter error: An ErrorType object describing the error
*/
internal var onWebsocketError: (error:ErrorType) -> () = {error in log.error("websocket error \(error)")}
/**
onConnected executes when the client makes a DDP connection
- parameter session: A string session id
*/
public var onConnected: (session:String) -> () = {session in log.info("connected with session: \(session)")}
/**
onDisconnected executes when the client is disconnected
*/
public var onDisconnected: () -> () = {log.debug("disconnected")}
/**
onFailed executes when an attempt to make a DDP connection fails
*/
public var onFailed: () -> () = {log.error("failed")}
// Data messages
/**
onAdded executes when a document has been added to a local collection
- parameter collection: the string name of the collection to which the document belongs
- parameter id: the string unique id that identifies the document on the server
- parameter fields: an optional NSDictionary with the documents properties
*/
public var onAdded: ((collection:String, id:String, fields:NSDictionary?) -> ())?
/**
onChanged executes when the server sends an instruction to modify a local document
- parameter collection: the string name of the collection to which the document belongs
- parameter id: the string unique id that identifies the document on the server
- parameter fields: an optional NSDictionary with the documents properties
- parameter cleared: an optional array of string property names to delete
*/
public var onChanged: ((collection:String, id:String, fields:NSDictionary?, cleared:NSArray?) -> ())?
/**
onRemoved executes when the server sends an instruction to remove a document from the local collection
- parameter collection: the string name of the collection to which the document belongs
- parameter id: the string unique id that identifies the document on the server
*/
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) }
/**
onUpdated executes when the server sends a notification that all the consequences of a method call have
been communicated to the client
- parameter methods: An array of method id strings
*/
public var onUpdated: ((methods: [String]) -> ())?
/**
onError executes when the client receives a DDP error message
- parameter message: A DDPError message describing the error
*/
public var onError: ((message:DDPError) -> ())?
}

View File

@ -58,7 +58,7 @@ extension NSDictionary {
}
/**
Extensions that provide core Meteor functionality and a cleaner API
Extensions that provide an api for interacting with basic Meteor server-side services
*/
extension DDPClient {

View File

@ -71,10 +71,13 @@ A struct to parse, encapsulate and facilitate handling of DDP message strings
public struct DDPMessage {
/**
The message properties in an NSDictionary
The message's properties, stored as an NSDictionary
*/
public var json:NSDictionary!
/**
Initialize a message struct, with a Json string
*/
public init(message:String) {
if let JSON = message.dictionaryValue() { json = JSON }
@ -84,6 +87,9 @@ public struct DDPMessage {
}
}
/**
Initialize a message struct, with a dictionary of strings
*/
public init(message:[String:String]) {
json = message as NSDictionary
}
@ -101,7 +107,9 @@ public struct DDPMessage {
// Computed variables
//
// Returns the type of DDP message, or unhandled if it is not a DDP message
/**
Returns the DDP message type, of type DDPMessageType enum
*/
public var type:DDPMessageType {
if let msg = message,
let type = DDPMessageType(rawValue: msg) {
@ -110,6 +118,9 @@ public struct DDPMessage {
return DDPMessageType(rawValue: "unhandled")!
}
/**
Returns a boolean value indicating if the message is an error message or not
*/
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
@ -117,7 +128,7 @@ public struct DDPMessage {
}
// Returns the root-level keys of the JSON object
public var keys:[String] {
internal var keys:[String] {
return json.allKeys as! [String]
}
@ -128,91 +139,165 @@ public struct DDPMessage {
return false
}
/**
The optional DDP message
*/
public var message:String? {
get { return json["msg"] as? String }
}
/**
The optional DDP session string
*/
public var session:String? {
get { return json["session"] as? String }
}
/**
The optional DDP version string
*/
public var version:String? {
get { return json["version"] as? String }
}
/**
The optional DDP support string
*/
public var support:String? {
get { return json["support"] as? String }
}
/**
The optional DDP message id string
*/
public var id:String? {
get { return json["id"] as? String }
}
/**
The optional DDP name string
*/
public var name:String? {
get { return json["name"] as? String }
}
/**
The optional DDP param string
*/
public var params:String? {
get { return json["params"] as? String }
}
/**
The optional DDP error object
*/
public var error:DDPError? {
get { if let e = json["error"] as? NSDictionary { return DDPError(json:e) } else { return nil }}
}
/**
The optional DDP collection name string
*/
public var collection:String? {
get { return json["collection"] as? String }
}
/**
The optional DDP fields dictionary
*/
public var fields:NSDictionary? {
get { return json["fields"] as? NSDictionary }
}
/**
The optional DDP cleared array. Contains an array of fields that should be removed
*/
public var cleared:[String]? {
get { return json["cleared"] as? [String] }
}
/**
The optional method name
*/
public var method:String? {
get { return json["method"] as? String }
}
/**
The optional random seed JSON value (an arbitrary client-determined seed for pseudo-random generators)
*/
public var randomSeed:String? {
get { return json["randomSeed"] as? String }
}
/**
The optional result object, containing the result of a method call
*/
public var result:AnyObject? {
get { return json["result"] }
}
/**
The optional array of ids passed to 'method', all of whose writes have been reflected in data messages)
*/
public var methods:[String]? {
get { return json["methods"] as? [String] }
}
/**
The optional array of id strings passed to 'sub' which have sent their initial batch of data
*/
public var subs:[String]? {
get { return json["subs"] as? [String] }
}
// Communication error properties
/**
The optional reason given for an error returned from the server
*/
public var reason:String? {
get { return json["reason"] as? String }
}
/**
The optional original error message
*/
public var offendingMessage:String? {
get { return json["offendingMessage"] as? String }
}
}
public struct DDPError {
/**
A struct encapsulating a DDP error message
*/
public struct DDPError: ErrorType {
private var json:NSDictionary?
/**
The string error code
*/
public var error:String? { return json?["error"] as? String } // Error code
/**
The detailed message given for an error returned from the server
*/
public var reason:String? { return json?["reason"] as? String }
/**
The string providing error details
*/
public var details:String? { return json?["details"] as? String }
/**
If the original message parsed properly, it is included here
*/
public var offendingMessage:String? { return json?["offendingMessage"] as? String }
/**
Helper variable that returns true if the struct has both an error code and a reason
*/
var isValid:Bool {
if let _ = error { return true }
if let _ = reason { return true }

View File

@ -20,7 +20,18 @@
import Foundation
/**
Struct to encapsulate the result of a Meteor method call
*/
public struct Result {
/**
The result of the method call
*/
public var result:AnyObject?
/**
An error object describing the server-side error, or nil if the method completed successfully
*/
public var error:DDPError?
}

View File

@ -26,8 +26,18 @@ protocol MeteorCollectionType {
func documentWasRemoved(collection:String, id:String)
}
/**
Meteor is a class to simplify communicating with and consuming MeteorJS server services
*/
public class Meteor {
/**
client is a singleton instance of DDPClient
*/
public static let client = Meteor.Client() // Client is a singleton object
private static var collections = [String:Any]()
@ -74,6 +84,13 @@ public class Meteor {
//public static func unsubscribe(
/**
Call a single function to establish a DDP connection, and login with email and password
- parameter url: The url to connect to
- parameter email: A string email address associated with a Meteor account
- parameter password: A string password
*/
public static func connect(url:String, email:String, password:String) {
client.connect(url) { session in
client.loginWithPassword(email, password: password) { result, error in
@ -87,6 +104,9 @@ public class Meteor {
}
}
/**
Meteor.Client is a subclass of DDPClient that facilitates interaction with the MeteorCollection class
*/
public class Client: DDPClient {
typealias SubscriptionCallback = () -> ()
@ -96,7 +116,15 @@ public class Meteor {
self.init()
}
// Posts a notification when a document is added
/**
Calls the documentWasAdded method in the MeteorCollection subclass instance associated with the document
collection
- parameter collection: the string name of the collection to which the document belongs
- parameter id: the string unique id that identifies the document on the server
- parameter fields: an optional NSDictionary with the documents properties
*/
public override func documentWasAdded(collection:String, id:String, fields:NSDictionary?) {
if let meteorCollection = Meteor.collections[collection] as? MeteorCollectionType {
NSOperationQueue.mainQueue().addOperationWithBlock() {
@ -105,18 +133,16 @@ public class Meteor {
}
}
// Posts a notification when a document is removed
public override func documentWasRemoved(collection:String, id:String) {
// let message = NSDictionary(dictionary:["collection":collection, "id":id])
// let userInfo = ["message":message]
if let meteorCollection = Meteor.collections[collection] as? MeteorCollectionType {
NSOperationQueue.mainQueue().addOperationWithBlock() {
meteorCollection.documentWasRemoved(collection, id: id)
}
}
}
/**
Calls the documentWasChanged method in the MeteorCollection subclass instance associated with the document
collection
- parameter collection: the string name of the collection to which the document belongs
- parameter id: the string unique id that identifies the document on the server
- parameter fields: an optional NSDictionary with the documents properties
- parameter cleared: an optional array of string property names to delete
*/
// Posts a notification when a document is changed
public override func documentWasChanged(collection:String, id:String, fields:NSDictionary?, cleared:[String]?) {
if let meteorCollection = Meteor.collections[collection] as? MeteorCollectionType {
NSOperationQueue.mainQueue().addOperationWithBlock() {
@ -124,20 +150,46 @@ public class Meteor {
}
}
}
/**
Calls the documentWasRemoved method in the MeteorCollection subclass instance associated with the document
collection
- parameter collection: the string name of the collection to which the document belongs
- parameter id: the string unique id that identifies the document on the server
*/
public override func documentWasRemoved(collection:String, id:String) {
if let meteorCollection = Meteor.collections[collection] as? MeteorCollectionType {
NSOperationQueue.mainQueue().addOperationWithBlock() {
meteorCollection.documentWasRemoved(collection, id: id)
}
}
}
}
}
/**
MeteorCollection is a class created to provide a base class and api for integrating SwiftDDP with persistence stores. MeteorCollection
should generally be subclassed, with the methods documentWasAdded, documentWasChanged and documentWasRemoved facilitating communicating
with the datastore.
*/
public class MeteorCollection: NSObject, MeteorCollectionType {
internal var name:String
internal let client = Meteor.client
// Alternative API to subclassing
// 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]?) -> ())?
public var onRemoved:((collection:String, id:String) -> ())?
// public var onAdded:((collection:String, id:String, fields:NSDictionary?) -> ())?
// public var onChanged:((collection:String, id:String, fields:NSDictionary?, cleared:[String]?) -> ())?
// public var onRemoved:((collection:String, id:String) -> ())?
// Must use the constructor function to create the collection
/**
Initializes a MeteorCollection object
- parameter name: The string name of the collection (must match the name of the collection on the server)
*/
public init(name:String) {
self.name = name
super.init()
@ -148,17 +200,24 @@ public class MeteorCollection: NSObject, MeteorCollectionType {
Meteor.collections[name] = nil
}
// Override these methods to subclass Collection
/**
Called when a document has been sent from the server. Always executes on the main queue
- parameter collection: the string name of the collection to which the document belongs
- parameter id: the string unique id that identifies the document on the server
- parameter fields: an optional NSDictionary with the documents properties
*/
public func documentWasAdded(collection:String, id:String, fields:NSDictionary?) {
if let added = onAdded { added(collection: collection, id: id, fields:fields) }
// if let added = onAdded { added(collection: collection, id: id, fields:fields) }
}
public func documentWasChanged(collection:String, id:String, fields:NSDictionary?, cleared:[String]?) {
if let changed = onChanged { changed(collection:collection, id:id, fields:fields, cleared:cleared) }
// if let changed = onChanged { changed(collection:collection, id:id, fields:fields, cleared:cleared) }
}
public func documentWasRemoved(collection:String, id:String) {
if let removed = onRemoved { removed(collection:collection, id:id) }
// if let removed = onRemoved { removed(collection:collection, id:id) }
}
}