WIP rpc framework
This commit is contained in:
7
www/assert/frame/frame.html
Normal file
7
www/assert/frame/frame.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script src="respond.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
147
www/assert/frame/frame.js
Normal file
147
www/assert/frame/frame.js
Normal file
@@ -0,0 +1,147 @@
|
||||
(function () {
|
||||
|
||||
var Frame = {};
|
||||
|
||||
var uid = function () {
|
||||
return Number(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER))
|
||||
.toString(32).replace(/\./g, '');
|
||||
};
|
||||
|
||||
// create an invisible iframe with a given source
|
||||
// append it to a parent element
|
||||
// execute a callback when it has loaded
|
||||
Frame.create = function (parent, src, onload, timeout) {
|
||||
var iframe = document.createElement('iframe');
|
||||
|
||||
timeout = timeout || 10000;
|
||||
var to = window.setTimeout(function () {
|
||||
onload('[timeoutError] could not load iframe at ' + src);
|
||||
}, timeout);
|
||||
|
||||
iframe.setAttribute('id', 'cors-store');
|
||||
|
||||
iframe.onload = function (e) {
|
||||
onload(void 0, iframe, e);
|
||||
window.clearTimeout(to);
|
||||
};
|
||||
// We must pass a unique parameter here to avoid cache problems in Firefox with
|
||||
// the NoScript plugin: if the iframe's content is taken from the cache, the JS
|
||||
// is not executed with NoScript....
|
||||
iframe.setAttribute('src', src + '?t=' + new Date().getTime());
|
||||
|
||||
iframe.style.display = 'none';
|
||||
parent.appendChild(iframe);
|
||||
};
|
||||
|
||||
/* given an iframe with an rpc script loaded, create a frame object
|
||||
with an asynchronous 'send' method */
|
||||
Frame.open = function (e, A, timeout) {
|
||||
var win = e.contentWindow;
|
||||
|
||||
var frame = {};
|
||||
frame.id = uid();
|
||||
|
||||
var listeners = {};
|
||||
var timeouts = {};
|
||||
|
||||
timeout = timeout || 5000;
|
||||
|
||||
frame.accepts = function (o) {
|
||||
return A.some(function (e) {
|
||||
switch (typeof(e)) {
|
||||
case 'string': return e === o;
|
||||
case 'object': return e.test(o);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var changeHandlers = frame.changeHandlers = [];
|
||||
|
||||
frame.change = function (f) {
|
||||
if (typeof(f) !== 'function') {
|
||||
throw new Error('[Frame.change] expected callback');
|
||||
}
|
||||
changeHandlers.push(f);
|
||||
};
|
||||
|
||||
var _listener = function (e) {
|
||||
if (!frame.accepts(e.origin)) {
|
||||
console.log("message from %s rejected!", e.origin);
|
||||
return;
|
||||
}
|
||||
var message = JSON.parse(e.data);
|
||||
var uid = message._uid;
|
||||
var error = message.error;
|
||||
var data = message.data;
|
||||
|
||||
if (!uid) {
|
||||
console.log("No uid!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (uid === 'change' && changeHandlers.length) {
|
||||
changeHandlers.forEach(function (f) {
|
||||
f(data);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeouts[uid]) {
|
||||
window.clearTimeout(timeouts[uid]);
|
||||
}
|
||||
if (listeners[uid]) {
|
||||
listeners[uid](error, data, e);
|
||||
delete listeners[uid];
|
||||
}
|
||||
};
|
||||
window.addEventListener('message', _listener);
|
||||
|
||||
frame.close = function () {
|
||||
window.removeEventListener('message', _listener);
|
||||
};
|
||||
|
||||
/* method (string): (set|get|remove)
|
||||
key (string)
|
||||
data (string)
|
||||
cb (function) */
|
||||
frame.send = function (method, content, cb) {
|
||||
var req = {
|
||||
method: method,
|
||||
//key: key,
|
||||
data: content, //data,
|
||||
};
|
||||
|
||||
var id = req._uid = uid();
|
||||
// uid must not equal 'change'
|
||||
while(id === 'change') {
|
||||
id = req._uid = uid();
|
||||
}
|
||||
|
||||
if (typeof(cb) === 'function') {
|
||||
//console.log("setting callback!");
|
||||
listeners[id] = cb;
|
||||
//console.log("setting timeout of %sms", timeout);
|
||||
timeouts[id] = window.setTimeout(function () {
|
||||
// when the callback is executed it will clear this timeout
|
||||
cb('[TimeoutError] request timed out after ' + timeout + 'ms');
|
||||
}, timeout);
|
||||
} else {
|
||||
console.log(typeof(cb));
|
||||
}
|
||||
|
||||
win.postMessage(JSON.stringify(req), '*');
|
||||
};
|
||||
|
||||
return frame;
|
||||
};
|
||||
|
||||
if (typeof(module) !== 'undefined' && module.exports) {
|
||||
module.exports = Frame;
|
||||
} else if (typeof(define) === 'function' && define.amd) {
|
||||
define(['jquery'], function () {
|
||||
return Frame;
|
||||
});
|
||||
} else {
|
||||
window.Frame = Frame;
|
||||
}
|
||||
}());
|
||||
32
www/assert/frame/respond.js
Normal file
32
www/assert/frame/respond.js
Normal file
@@ -0,0 +1,32 @@
|
||||
var validDomains = [ /.*/i, ];
|
||||
var isValidDomain = function (o) {
|
||||
return validDomains.some(function (e) {
|
||||
switch (typeof(e)) {
|
||||
case 'string': return e === o;
|
||||
case 'object': return e.test(o);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener('message', function(e) {
|
||||
if (!isValidDomain(e.origin)) { return; }
|
||||
var payload = JSON.parse(e.data);
|
||||
var parent = window.parent;
|
||||
var respond = function (error, data) {
|
||||
var res = {
|
||||
_uid: payload._uid,
|
||||
error: error,
|
||||
data: data,
|
||||
};
|
||||
parent.postMessage(JSON.stringify(res), '*');
|
||||
};
|
||||
|
||||
//console.error(payload);
|
||||
switch(payload.method) {
|
||||
case undefined:
|
||||
return respond('No method supplied');
|
||||
default:
|
||||
return respond(void 0, "EHLO");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -249,7 +249,6 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var evt = Util.mkEvent();
|
||||
var respond = function (e, out) {
|
||||
evt.fire(e, out);
|
||||
@@ -259,9 +258,8 @@ define([
|
||||
try {
|
||||
var parsed = JSON.parse(raw);
|
||||
var txid = parsed.txid;
|
||||
var message = parsed.message;
|
||||
setTimeout(function () {
|
||||
service(message.command, message.content, function (e, result) {
|
||||
service(parsed.q, parsed.content, function (e, result) {
|
||||
respond(JSON.stringify({
|
||||
txid: txid,
|
||||
error: e,
|
||||
@@ -285,33 +283,56 @@ define([
|
||||
});
|
||||
}, "Test rpc factory");
|
||||
|
||||
/*
|
||||
assert(function (cb) {
|
||||
var getBlob = function (url, cb) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", url, true);
|
||||
xhr.responseType = "blob";
|
||||
xhr.onload = function () {
|
||||
cb(void 0, this.response);
|
||||
};
|
||||
xhr.send();
|
||||
};
|
||||
require([
|
||||
'/assert/frame/frame.js',
|
||||
], function (Frame) {
|
||||
Frame.create(document.body, '/assert/frame/frame.html', function (e, frame) {
|
||||
if (e) { return cb(false); }
|
||||
|
||||
var $img = $('img#thumb-orig');
|
||||
getBlob($img.attr('src'), function (e, blob) {
|
||||
console.log(e, blob);
|
||||
Thumb.fromImageBlob(blob, function (e, thumb) {
|
||||
console.log(thumb);
|
||||
var th = new Image();
|
||||
th.src = URL.createObjectURL(thumb);
|
||||
th.onload = function () {
|
||||
$(document.body).append($(th).addClass('thumb'));
|
||||
cb(th.width === Thumb.dimension && th.height === Thumb.dimension);
|
||||
};
|
||||
var channel = Frame.open(frame, [
|
||||
/.*/i,
|
||||
], 5000);
|
||||
|
||||
channel.send('HELO', null, function (e, res) {
|
||||
if (res === 'EHLO') { return cb(true); }
|
||||
cb(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
*/
|
||||
}, "PEWPEW");
|
||||
|
||||
(function () {
|
||||
var guid = Wire.uid();
|
||||
|
||||
var t = Wire.tracker({
|
||||
timeout: 1000,
|
||||
hook: function (txid, q, content) {
|
||||
console.info(JSON.stringify({
|
||||
guid: guid,
|
||||
txid: txid,
|
||||
q: q,
|
||||
content: content,
|
||||
}));
|
||||
},
|
||||
});
|
||||
|
||||
assert(function (cb) {
|
||||
t.call('SHOULD_TIMEOUT', null, function (e) {
|
||||
if (e === 'TIMEOUT') { return cb(true); }
|
||||
cb(false);
|
||||
});
|
||||
}, 'tracker should timeout');
|
||||
|
||||
assert(function (cb) {
|
||||
var id = t.call('SHOULD_NOT_TIMEOUT', null, function (e, out) {
|
||||
if (e) { return cb(false); }
|
||||
if (out === 'YES') { return cb(true); }
|
||||
cb(false);
|
||||
});
|
||||
t.respond(id, void 0, 'YES');
|
||||
}, "tracker should not timeout");
|
||||
}());
|
||||
|
||||
Drive.test(assert);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user