Created
May 11, 2018 15:56
-
-
Save cr0ybot/001c5aafcfd35251304961670287ee21 to your computer and use it in GitHub Desktop.
Parse JS SDK modifications for Titanium SDK
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"global": { | |
"parse": { | |
"applicationId": "com.example.parseAppID", | |
"javascriptKey": "XXXX", | |
"clientKey": "YYYY", | |
"restAPIKey": "ZZZZ", | |
"serverURL": "https://example.com/parse/" | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* File: lib/ti.parse.js | |
* | |
* Parse JS SDK modifications for Titanium | |
* | |
* Tested with: | |
* Parse JS SDK 1.11.1 | |
* Titanium SDK 7.1.1.GA | |
* | |
* Based on https://github.com/aaronksaunders/TiParseTestApp/blob/master/app/lib/ti.parse_mine.js | |
* | |
* @author Cory Hughart | |
* | |
* @requires parse.js | |
* @requires websocket.js | |
*/ | |
/** | |
* TiParse Parse wrapper | |
* | |
* This object becomes your stand-in for the Parse object | |
* | |
* Usage: | |
* var tiParse = require('ti.parse'); | |
* tiParse.Foo(); | |
*/ | |
var TiParse = function(options) { | |
this.options = (typeof options == 'object') ? _.extendOwn({}, Alloy.CFG.parse, options) : Alloy.CFG.parse; | |
// Define global WebSocket object for Parse to find with _getWebSocketImplementation() | |
WebSocket = require('websocket'); | |
// Download parse.js from https://github.com/parse-community/Parse-SDK-JS/releases | |
var Parse = require('parse'); | |
Parse._ = _.noConflict(); | |
/** | |
* Overwrite Parse local storage so it works in Titanium | |
*/ | |
var StorageController = { | |
async: 0, | |
getItem : function(key) { | |
return Ti.App.Properties.getObject(this.fixKey(key)); | |
}, | |
setItem : function(key, value) { | |
return Ti.App.Properties.setObject(this.fixKey(key), value); | |
}, | |
removeItem : function(key, value) { | |
return Ti.App.Properties.removeProperty(this.fixKey(key)); | |
}, | |
/** | |
* Fix Parse Keys. | |
* Parse uses a Key containing slashes "/"; this is invalid for | |
* Titanium Android. We'll replace those slashes with underscores "_". | |
*/ | |
fixKey : function(key) { | |
return key.split("/").join("_"); | |
} | |
}; | |
Parse.CoreManager.setStorageController(StorageController); | |
/** | |
* Save Eventually | |
* https://github.com/francimedia/parse-js-local-storage | |
*/ | |
Parse.saveEventually = { | |
localStorageKey: "Parse.saveEventually.Queue", | |
initialize: function () { | |
}, | |
save: function (objectType, object) { | |
this.addToQueue('save', objectType, object); | |
}, | |
addToQueue: function (action, objectType, object) { | |
var queueData = this.getQueue(); | |
// create queueId to avoid duplicates. Maintain previously saved data. | |
var queueId = ([objectType, object.id, object.get('hash')]).join('_'); | |
var i = this.queueItemExists(queueData, queueId); | |
if (i > -1) { | |
for (var prop in queueData[i].data) { | |
if (object.get(prop) == 'undefined') { | |
object.set(prop, queueData[i].data[prop]); | |
} | |
} | |
} | |
else { | |
i = queueData.length; | |
} | |
queueData[i] = { | |
queueId: queueId, | |
type: objectType, | |
action: action, | |
id: object.id, | |
hash: object.get('hash'), | |
createdAt: new Date(), | |
data: object | |
}; | |
this.setQueue(queueData); | |
}, | |
getQueue: function () { | |
var q = Parse.getStorageController().getItem(this.localStorageKey) || null; | |
if(q && (typeof JSON.parse(q) == 'object')) | |
return JSON.parse(q); | |
else | |
return []; | |
}, | |
setQueue: function (queueData) { | |
Parse.getStorageController().setItem(this.localStorageKey, JSON.stringify(queueData)); | |
}, | |
clearQueue: function () { | |
Parse.getStorageController().setItem(this.localStorageKey, JSON.stringify([])); | |
}, | |
queueItemExists: function(queueData, queueId) { | |
for (var i = 0; i < queueData.length; i++) { | |
if(queueData[i].queueId == queueId) { | |
return i; | |
} | |
} | |
return -1; | |
}, | |
countQueue: function(){ | |
return this.getQueue().length; | |
}, | |
sendQueue: function () { | |
var queueData = this.getQueue(); | |
if(queueData.length < 1) | |
return false; | |
for (var i = 0; i < queueData.length; i++) { | |
var myObjectType = Parse.Object.extend(queueData[i].type); | |
// if object has a parse data id, update existing object | |
if (queueData[i].id) { | |
this.reprocess.byId(myObjectType, queueData[i]); | |
} | |
// if object has no id but a unique identifier, look for existing object, update or create new | |
else if (queueData[i].hash) { | |
this.reprocess.byHash(myObjectType, queueData[i]); | |
} | |
// else create a new object | |
else { | |
this.reprocess.create(myObjectType, queueData[i]); | |
} | |
} | |
return true; | |
// empty queue - 2do: verify queue has been sent | |
// this.clearQueue(); | |
}, | |
sendQueueCallback: function (myObject, queueObject) { | |
switch (queueObject.action) { | |
case 'save': | |
// queued update was overwritten by other request > do not save | |
if (typeof myObject.updatedAt != 'undefined' && myObject.updatedAt > new Date(queueObject.createdAt)) { | |
return false; | |
} | |
myObject.save(queueObject.data, { | |
success: function (object) { | |
console.log(object); | |
}, | |
error: function (model, error) { | |
console.log(error); | |
} | |
}); | |
break; | |
case 'delete': | |
// 2do: code to delete queued objects | |
break; | |
} | |
}, | |
reprocess: { | |
create: function (myObjectType, queueObject) { | |
var myObject = new myObjectType(); | |
Parse.saveEventually.sendQueueCallback(myObject, queueObject); | |
}, | |
byId: function (myObjectType, queueObject) { | |
var query = new Parse.Query(myObjectType); | |
query.get(queueObject.id, { | |
success: function (myObject) { | |
// The object was retrieved successfully. | |
Parse.saveEventually.sendQueueCallback(myObject, queueObject); | |
}, | |
error: function (myObject, error) { | |
// The object was not retrieved successfully. | |
// error is a Parse.Error with an error code and description. | |
} | |
}); | |
}, | |
byHash: function (myObjectType, queueObject) { | |
var query = new Parse.Query(myObjectType); | |
query.equalTo("hash", queueObject.hash); | |
query.find({ | |
success: function (results) { | |
// The object was retrieved successfully. | |
if(results.length > 0) { | |
Parse.saveEventually.sendQueueCallback(results[0], queueObject); | |
} | |
// The object was not found, create a new one | |
else { | |
Parse.saveEventually.reprocess.create(myObjectType, queueObject); | |
} | |
}, | |
error: function (myObject, error) { | |
// The object was not retrieved successfully. | |
// error is a Parse.Error with an error code and description. | |
} | |
}); | |
} | |
} | |
}; | |
/** | |
* Overwrite Parse XHR Client to use Titanium HTTPClient | |
* | |
* Titanium XHR clients must be created with the createHTTPClient method, | |
* so we replace the Parse XHR object with this function that returns the | |
* created Titanium HTTPClient. | |
*/ | |
var XHR = function() { | |
return Ti.Network.createHTTPClient({ | |
timeout : 5e3, | |
onload: function() { | |
Ti.API.debug('Parse XHR response: '+this.responseText); | |
}, | |
onerror : function(e) { | |
Ti.API.error('Parse XHR error: '+this.responseText); | |
} | |
}); | |
}; | |
Parse.CoreManager.getRESTController()._setXHR(XHR); | |
/** | |
* Enter appropriate parameters for initializing Parse | |
* | |
* options.applicationId, options.javascriptKey, options.serverURL | |
*/ | |
Parse.initialize(this.options.applicationId, this.options.javascriptKey); | |
Parse.serverURL = this.options.serverURL; | |
/** | |
* Parse LiveQuery monitor | |
*/ | |
Parse.LiveQuery.on('open', function(e) { | |
Ti.API.debug('Parse LiveQuery socket established'); | |
}); | |
Parse.LiveQuery.on('close', function(e) { | |
Ti.API.debug('Parse LiveQuery socket closed'); | |
}); | |
Parse.LiveQuery.on('error', function(e) { | |
Ti.API.debug('Parse LiveQuery error: '+JSON.stringify(e)); | |
}); | |
/** | |
* Add method to send data with the Parse REST API if needed. | |
* | |
* @param {string} method GET or POST | |
* @param {string} endpoint API endpoint with no slashes (ie 'installations') | |
* @param {object} data Data to send | |
* @param {function} onload Callback for success | |
* @param {function} onerror Callback for error | |
*/ | |
Parse.restAPI = function(method, endpoint, data, onload, onerror) { | |
var url = Alloy.CFG.parse.serverURL+endpoint; | |
if (typeof data === 'undefined' || data == null) data = {}; | |
if (typeof data !== 'object') data = {'data': data}; | |
if (typeof onload !== 'function') { | |
onload = function(e) { | |
Ti.API.debug(JSON.stringify(e)); | |
}; | |
} | |
if (typeof onerror !== 'function') { | |
onerror = function(e) { | |
Ti.API.debug('request failed: '+url); | |
Ti.API.debug("STATUS: " + this.status); | |
Ti.API.debug("TEXT: " + this.responseText); | |
Ti.API.debug("ERROR: " + e.error); | |
}; | |
} | |
var xhr = Ti.Network.createHTTPClient({ | |
onload : function(e) { | |
onload(e); | |
}, | |
onerror : function(e) { | |
onerror(e); | |
}, | |
timeout : 10000 | |
}); | |
xhr.open(method, url, true); | |
xhr.setRequestHeader('X-Parse-Application-Id', Alloy.CFG.parse.applicationId); | |
//xhr.setRequestHeader('X-Parse-REST-API-Key', Alloy.CFG.parse.restAPIKey); | |
xhr.setRequestHeader('X-Parse-Client-Key', Alloy.CFG.parse.clientKey); | |
xhr.setRequestHeader('Content-Type', 'application/json'); | |
xhr.send(JSON.stringify(data)); | |
}; | |
// Return our modified Parse object | |
return Parse; | |
}; | |
module.exports = new TiParse(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* File: lib/websocket.js | |
* | |
* Parse-compatible WebSocket implementation with tiws | |
* @requires net.iamyellow.tiws https://github.com/omorandi/tiws | |
*/ | |
var WebSocket = function(url) { | |
Ti.API.debug('Creating WebSocket for '+url); | |
var self = this; | |
var TiWS = require('net.iamyellow.tiws'); | |
this.ws = TiWS.createWS(); | |
// Default listeners with debug messages | |
this.ws.addEventListener('open', function() { | |
Ti.API.debug('WebSocket open'); | |
self.onopen(); | |
}); | |
this.ws.addEventListener('message', function(e) { | |
Ti.API.debug('WebSocket message: '+JSON.stringify(e)); | |
self.onmessage(e); | |
}); | |
this.ws.addEventListener('close', function(e) { | |
Ti.API.debug('WebSocket closed: '+JSON.stringify(e)); | |
self.onclose(e); | |
}); | |
this.ws.addEventListener('error', function(error) { | |
Ti.API.debug('WebSocket error: '+JSON.stringify(error)); | |
self.onerror(error); | |
}); | |
this.ws.open(url); | |
Ti.API.debug('WebSocket created'); | |
}; | |
// These should be overridden when creating an instance | |
WebSocket.prototype.onopen = function() {}; | |
WebSocket.prototype.onmessage = function(e) {}; | |
WebSocket.prototype.onclose = function(e) {}; | |
WebSocket.prototype.onerror = function(error) {}; | |
WebSocket.prototype.send = function(string) { | |
Ti.API.debug('WebSocket sending: '+string); | |
this.ws.send(string); | |
}; | |
WebSocket.prototype.close = function() { | |
Ti.API.debug('Websocket closing'); | |
this.ws.close(); | |
}; | |
module.exports = WebSocket; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment