Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React-native #280

Closed
mattheworiordan opened this issue Jun 3, 2016 · 6 comments
Closed

React-native #280

mattheworiordan opened this issue Jun 3, 2016 · 6 comments
Labels
enhancement New feature or improved functionality.

Comments

@mattheworiordan
Copy link
Member

Can we support React Native using our ably-js lib, or do we need to use the native libraries under the hood.

Given async HTTP requests and WebSockets are supported https://facebook.github.io/react-native/docs/network.html, it should, in theory, be quite straightforward to add react native support.

One to review.

@mattheworiordan mattheworiordan added the enhancement New feature or improved functionality. label Jun 3, 2016
@tcard
Copy link
Contributor

tcard commented Jun 8, 2016

Just confirmed it works if I remove some JSONPTransport object, which has a hard dependency on document and isn't even referenced anywhere else in the library.

Can it be removed? Or should I instead define it iff document is defined?

@paddybyers
Copy link
Member

isn't even referenced anywhere else in the library

It is referenced here: https://github.com/ably/ably-js/blob/master/browser/lib/transport/jsonptransport.js#L21

and therefore elsewhere obtained either by name (jsonp), or by enumeration of all transports.

should I instead define it iff document is defined?

I think at the top we should have something like

var isSupported = (typeof(document) !== 'undefined');
var head = isSupported && ....

then

JSONPTransport.isAvailable = function() { return isSupported; };

tcard added a commit that referenced this issue Jun 8, 2016
This makes the library compatible with React Native. Fixes #280.
@tcard
Copy link
Contributor

tcard commented Jun 8, 2016

Oh right, didn't notice the function was manipulating a global from within. Done that at #283.

@tcard tcard reopened this Nov 8, 2016
@tcard
Copy link
Contributor

tcard commented Nov 8, 2016

Apparently this stopped working at some point.

Just importing import Ably from 'ably' doesn't work because it goes here and those Node.js modules don't exist in React Native.

Importing browser/static/ably-commonjs.js works if we remove all conditional requires. Conditional requires don't work in React Native. There also a few references to the window and document object that should be removed.

I've put together a version of ably-commonjs.js that works with React Native. This is the diff:

diff --git a/browser/static/ably-commonjs.js b/browser/static/ably-commonjs.js
index cdc55b5..c2c3e0b 100644
--- a/browser/static/ably-commonjs.js
+++ b/browser/static/ably-commonjs.js
@@ -7018,7 +7018,6 @@ var Transport = (function() {

 var WebSocketTransport = (function() {
    var isBrowser = (typeof(window) == 'object');
-   var WebSocket = isBrowser ? (window.WebSocket || window.MozWebSocket) : require('ws');
    var binaryType = isBrowser ? 'arraybuffer' : 'nodebuffer';
    var shortName = 'web_socket';

@@ -7784,7 +7783,7 @@ var PaginatedResource = (function() {

 var Auth = (function() {
    var isBrowser = (typeof(window) == 'object');
-   var crypto = isBrowser ? null : require('crypto');
+   var crypto = null;
    var msgpack = (typeof require !== 'function') ? Ably.msgpack : require('msgpack-js');
    function noop() {}
    function random() { return ('000000' + Math.floor(Math.random() * 1E16)).slice(-16); }
@@ -9924,191 +9923,6 @@ var RealtimePresence = (function() {
    return RealtimePresence;
 })();

-var JSONPTransport = (function() {
-   var noop = function() {};
-   /* Can't just use windows.Ably, as that won't exist if using the commonjs version. */
-   var _ = window._ablyjs_jsonp = {};
-
-   /* express strips out parantheses from the callback!
-    * Kludge to still alow its responses to work, while not keeping the
-    * function form for normal use and not cluttering window.Ably
-    * https://github.com/strongloop/express/blob/master/lib/response.js#L305
-    */
-   _._ = function(id) { return _['_' + id] || noop; };
-   var idCounter = 1;
-   var isSupported = (typeof(document) !== 'undefined');
-   var head = isSupported ? document.getElementsByTagName('head')[0] : null;
-   var shortName = 'jsonp';
-
-   /* public constructor */
-   function JSONPTransport(connectionManager, auth, params) {
-       params.stream = false;
-       CometTransport.call(this, connectionManager, auth, params);
-       this.shortName = shortName;
-   }
-   Utils.inherits(JSONPTransport, CometTransport);
-
-   JSONPTransport.isAvailable = function() { return isSupported; };
-   if(isSupported) {
-       ConnectionManager.supportedTransports[shortName] = JSONPTransport;
-   }
-
-   /* connectivity check; since this has a hard-coded callback id,
-    * we just make sure that we handle concurrent requests (but the
-    * connectionmanager should ensure this doesn't happen anyway */
-   var checksInProgress = null;
-   JSONPTransport.checkConnectivity = function(callback) {
-       var upUrl = Defaults.internetUpUrlWithoutExtension + '.js';
-
-       if(checksInProgress) {
-           checksInProgress.push(callback);
-           return;
-       }
-       checksInProgress = [callback];
-       Logger.logAction(Logger.LOG_MICRO, 'JSONPTransport.checkConnectivity()', 'Sending; ' + upUrl);
-
-       var req = new Request('isTheInternetUp', upUrl, null, null, null, CometTransport.REQ_SEND, Defaults.TIMEOUTS);
-       req.once('complete', function(err, response) {
-           var result = !err && response;
-           Logger.logAction(Logger.LOG_MICRO, 'JSONPTransport.checkConnectivity()', 'Result: ' + result);
-           for(var i = 0; i < checksInProgress.length; i++) checksInProgress[i](null, result);
-           checksInProgress = null;
-       });
-       Utils.nextTick(function() {
-           req.exec();
-       });
-   };
-
-   JSONPTransport.tryConnect = function(connectionManager, auth, params, callback) {
-       var transport = new JSONPTransport(connectionManager, auth, params);
-       var errorCb = function(err) { callback(err); };
-       transport.on('failed', errorCb);
-       transport.on('preconnect', function() {
-           Logger.logAction(Logger.LOG_MINOR, 'JSONPTransport.tryConnect()', 'viable transport ' + transport);
-           transport.off('failed', errorCb);
-           callback(null, transport);
-       });
-       transport.connect();
-   };
-
-   JSONPTransport.prototype.toString = function() {
-       return 'JSONPTransport; uri=' + this.baseUri + '; isConnected=' + this.isConnected;
-   };
-
-   var createRequest = JSONPTransport.prototype.createRequest = function(uri, headers, params, body, requestMode, timeouts) {
-       /* JSONP requests are used either with the context being a realtime
-        * transport, or with timeouts passed in (for when used by a rest client),
-        * or completely standalone.  Use the appropriate timeouts in each case */
-       timeouts = (this && this.timeouts) || timeouts || Defaults.TIMEOUTS;
-       return new Request(undefined, uri, headers, Utils.copy(params), body, requestMode, timeouts);
-   };
-
-   function Request(id, uri, headers, params, body, requestMode, timeouts) {
-       EventEmitter.call(this);
-       if(id === undefined) id = idCounter++;
-       this.id = id;
-       this.uri = uri;
-       this.params = params || {};
-       this.params.rnd = Utils.randStr();
-       this.body = body;
-       this.requestMode = requestMode;
-       this.timeouts = timeouts;
-       this.requestComplete = false;
-   }
-   Utils.inherits(Request, EventEmitter);
-
-   Request.prototype.exec = function() {
-       var id = this.id,
-           body = this.body,
-           uri = this.uri,
-           params = this.params,
-           self = this;
-
-       params.callback = '_ablyjs_jsonp._(' + id + ')';
-
-       params.envelope = 'jsonp';
-       if(body)
-           params.body = body;
-
-       var script = this.script = document.createElement('script');
-       script.src = uri + Utils.toQueryString(params);
-       script.async = true;
-       script.type = 'text/javascript';
-       script.charset = 'UTF-8';
-       script.onerror = function(err) {
-           err.code = 80000;
-           self.complete(err);
-       };
-
-       _['_' + id] = function(message) {
-           if(message.statusCode) {
-               /* Handle as enveloped jsonp, as all jsonp transport uses should be */
-               var response = message.response;
-               if(message.statusCode == 204) {
-                   self.complete();
-               } else if(!response) {
-                   self.complete(new ErrorInfo('Invalid server response: no envelope detected', 50000, 500));
-               } else if(message.statusCode < 400) {
-                   self.complete(null, response, message.headers);
-               } else {
-                   var err = response.error || new ErrorInfo('Error response received from server', 50000, message.statusCode);
-                   self.complete(err);
-               }
-           } else {
-               /* Handle as non-enveloped -- as will be eg from a customer's authUrl server */
-               self.complete(null, message);
-           }
-       };
-
-       var timeout = (this.requestMode == CometTransport.REQ_SEND) ? this.timeouts.httpRequestTimeout : this.timeouts.recvTimeout;
-       this.timer = setTimeout(function() { self.abort(); }, timeout);
-       head.insertBefore(script, head.firstChild);
-   };
-
-   Request.prototype.complete = function(err, body, headers) {
-       headers = headers || {};
-       if(!this.requestComplete) {
-           this.requestComplete = true;
-           var contentType;
-           if(body) {
-               contentType = (typeof(body) == 'string') ? 'text/plain' : 'application/json';
-               headers['content-type'] = contentType;
-               this.emit('data', body);
-           }
-
-           this.emit('complete', err, body, headers, /* unpacked: */ true);
-           this.dispose();
-       }
-   };
-
-   Request.prototype.abort = function() {
-       this.dispose();
-   };
-
-   Request.prototype.dispose = function() {
-       var timer = this.timer;
-       if(timer) {
-           clearTimeout(timer);
-           this.timer = null;
-       }
-       var script = this.script;
-       if(script.parentNode) script.parentNode.removeChild(script);
-       delete _[this.id];
-       this.emit('disposed');
-   };
-
-   Http.Request = function(rest, uri, headers, params, body, callback) {
-       var req = createRequest(uri, headers, params, body, CometTransport.REQ_SEND, rest && rest.options.timeouts);
-       req.once('complete', callback);
-       Utils.nextTick(function() {
-           req.exec();
-       });
-       return req;
-   };
-
-   return JSONPTransport;
-})();
-
 var XHRRequest = (function() {
    var noop = function() {};
    var idCounter = 0;
@@ -10127,7 +9941,7 @@ var XHRRequest = (function() {
    var xhrSupported;
    var isIE = window.XDomainRequest;
    function isAvailable() {
-       return (xhrSupported = window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest());
+       return (xhrSupported = true);
    };

    function ieVersion() {
@@ -10393,16 +10207,15 @@ var XHRRequest = (function() {
    };

   if(isAvailable()) {
-          DomEvent.addUnloadListener(clearPendingRequests);
-          if(typeof(Http) !== 'undefined') {
-                  Http.supportsAuthHeaders = xhrSupported;
-                  Http.Request = function(rest, uri, headers, params, body, callback) {
-                          var req = createRequest(uri, headers, params, body, REQ_SEND, rest && rest.options.timeouts);
-                          req.once('complete', callback);
-                          req.exec();
-                          return req;
-                  };
-          }
+         if(typeof(Http) !== 'undefined') {
+                 Http.supportsAuthHeaders = xhrSupported;
+                 Http.Request = function(rest, uri, headers, params, body, callback) {
+                         var req = createRequest(uri, headers, params, body, REQ_SEND, rest && rest.options.timeouts);
+                         req.once('complete', callback);
+                         req.exec();
+                         return req;
+                 };
+         }
   }

    return XHRRequest;

@mattheworiordan
Copy link
Member Author

@tcard can we close this now?

@tcard tcard closed this as completed Nov 17, 2016
@tcard
Copy link
Contributor

tcard commented Nov 17, 2016

Yes, working again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or improved functionality.
Development

No branches or pull requests

3 participants