Add postmessage api and move functions in to class

This commit is contained in:
Richard Lewis 2017-12-15 15:24:22 +00:00
parent f410112983
commit c234e209fb
2 changed files with 286 additions and 163 deletions

101
src/MatrixPostMessageApi.js Normal file
View file

@ -0,0 +1,101 @@
import Promise from "bluebird";
function defer() {
let resolve, reject;
let isPending = true;
let promise = new Promise(function(...args) {
resolve = args[0];
reject = args[1];
});
return {
resolve: function(...args) {
if (!isPending) {
return;
}
isPending = false;
resolve(args[0]);
},
reject: function(...args) {
if (!isPending) {
return;
}
isPending = false;
reject(args[0]);
},
isPending: function() {
return isPending;
},
promise: promise,
};
}
// NOTE: PostMessageApi only handles message events with a data payload with a
// response field
export default class PostMessageApi {
constructor(targetWindow, timeoutMs) {
this._window = targetWindow || window.parent; // default to parent window
this._timeoutMs = timeoutMs || 5000; // default to 5s timer
this._counter = 0;
this._pending = {
// $ID: Deferred
};
}
start() {
addEventListener('message', this.getOnMessageCallback());
}
stop() {
removeEventListener('message', this.getOnMessageCallback());
}
// Somewhat convoluted so we can successfully capture the PostMessageApi 'this' instance.
getOnMessageCallback() {
if (this._onMsgCallback) {
return this._onMsgCallback;
}
let self = this;
this._onMsgCallback = function(ev) {
// THIS IS ALL UNSAFE EXECUTION.
// We do not verify who the sender of `ev` is!
let payload = ev.data;
// NOTE: Workaround for running in a mobile WebView where a
// postMessage immediately triggers this callback even though it is
// not the response.
if (payload.response === undefined) {
return;
}
let deferred = self._pending[payload._id];
if (!deferred) {
return;
}
if (!deferred.isPending()) {
return;
}
delete self._pending[payload._id];
deferred.resolve(payload);
};
return this._onMsgCallback;
}
exec(action, target) {
this._counter += 1;
target = target || "*";
action._id = Date.now() + "-" + Math.random().toString(36) + "-" + this._counter;
let d = defer();
this._pending[action._id] = d;
this._window.postMessage(action, target);
if (this._timeoutMs > 0) {
setTimeout(function() {
if (!d.isPending()) {
return;
}
console.error("postMessage request timed out. Sent object: " + JSON.stringify(action));
d.reject(new Error("Timed out"));
}, this._timeoutMs);
}
return d.promise;
}
}