Skip to content

Commit

Permalink
Merge pull request #9 from Holo-Host/B-03763-signals
Browse files Browse the repository at this point in the history
B-03763 - handle signals
  • Loading branch information
robbiecarlton authored Feb 4, 2021
2 parents c4a7002 + 422a7ed commit c5b1ca7
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 53 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Both the parent window and iFrame must load COMB.
<script type="text/javascript" src="./holo_hosting_comb.js"></script>
<script type="text/javascript">
(async () => {
const child = await comb.connect( url );
const child = await comb.connect( url, 5000, signal => console.log('comb got signal', signal) );
await child.set("development_mode", true );
await child.set("welcome_greeting", "Hello" );
Expand Down
56 changes: 29 additions & 27 deletions html/chaperone/index.html
Original file line number Diff line number Diff line change
@@ -1,35 +1,37 @@

<script src="/comb/holo_hosting_comb.js"></script>

<h1>Chaperone!</h1>

<script type="text/javascript">
(async function () {
(async function () {

function HolochainTestError(message) {
this.name = "HolochainTestError";
this.message = (message || "");
}
HolochainTestError.prototype = Error.prototype;
function HolochainTestError(message) {
this.name = "HolochainTestError";
this.message = (message || "");
}
HolochainTestError.prototype = Error.prototype;

try {
COMB.debug();
const parent = await COMB.listen({
"test": async function ( ...args ) {
return "Hello World: " + JSON.stringify(args);
},
"test_synchronous": function () {
return "Hello World";
},
"test_error": function ( ...args ) {
return new HolochainTestError("Method did not succeed\n" + JSON.stringify(args));
},
"test_synchronous_error": function () {
return new HolochainTestError("Method did not succeed");
}
});
} catch ( err ) {
console.error( String(err) );
}
})();
try {
COMB.debug();
const parent = await COMB.listen({
"test": async function (...args) {
return "Hello World: " + JSON.stringify(args);
},
"test_synchronous": function () {
return "Hello World";
},
"test_signal": function (signal) {
return parent.sendSignal(signal)
},
"test_error": function (...args) {
return new HolochainTestError("Method did not succeed\n" + JSON.stringify(args));
},
"test_synchronous_error": function () {
return new HolochainTestError("Method did not succeed");
}
});
} catch (err) {
console.error(String(err));
}
})();
</script>
77 changes: 52 additions & 25 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ const COMB = {
* @example
* const child = await COMB.connect( "http://localhost:8002" );
*/
async connect(url, timeout) {
const child = new ChildAPI(url, timeout);
async connect(url, timeout, signalCb) {
const child = new ChildAPI(url, timeout, signalCb);
await child.connect();
return child;
},
Expand Down Expand Up @@ -115,21 +115,23 @@ class ChildAPI {
handshake: any;
class_name: string;
loaded: boolean;
signalCb: any;

/**
* Initialize a child frame using the given URL.
*
* @class ChildAPI
*
* @param {string} url - URL that is used as 'src' for the iframe
* @param {string} url - URL that is used as 'src' for the iframe
*
* @prop {string} url - iFrame URL
* @prop {number} msg_count - Incrementing message ID
* @prop {object} responses - Dictionary of request Promises waiting for their responses
* @prop {object} msg_bus - Postmate instance
* @prop {promise} handshake - Promise that is waiting for connection confirmation
* @prop {string} class_name - iFrame's unique class name
* @prop {boolean} loaded - Indicates if iFrame successfully loaded
* @prop {string} url - iFrame URL
* @prop {number} msg_count - Incrementing message ID
* @prop {object} responses - Dictionary of request Promises waiting for their responses
* @prop {object} msg_bus - Postmate instance
* @prop {promise} handshake - Promise that is waiting for connection confirmation
* @prop {string} class_name - iFrame's unique class name
* @prop {boolean} loaded - Indicates if iFrame successfully loaded
* @prop {any} signalCb - A callback that's run when we receive a signal
*
* @example
* const child = new ChildAPI( url );
Expand All @@ -138,12 +140,14 @@ class ChildAPI {
* await child.set("mode", mode );
* let response = await child.run("signIn");
*/
constructor(url, timeout = 5_000) {
constructor(url, timeout = 5_000, signalCb) {
this.url = url;
this.msg_count = 0;
this.responses = {};
this.loaded = false;

this.signalCb = signalCb;

this.class_name = "comb-frame-" + ChildAPI.frame_count++;
this.handshake = async_with_timeout(async () => {
// log.info("Init Postmate handshake");
Expand Down Expand Up @@ -186,8 +190,7 @@ class ChildAPI {
if (this.loaded) {
// log.error("iFrame loaded but could not communicate with COMB");
throw new TimeoutError("Failed to complete COMB handshake", err.timeout);
}
else {
} else {
// log.error("iFrame did not trigger load event");
throw new TimeoutError("Failed to load iFrame", err.timeout);
}
Expand All @@ -212,6 +215,10 @@ class ChildAPI {
delete this.responses[k];
});

if (this.signalCb) {
child.on('signal', this.signalCb)
}

this.msg_bus = child;

return this;
Expand All @@ -223,9 +230,9 @@ class ChildAPI {
* @async
* @private
*
* @param {string} method - Internally consistent Postmate method
* @param {string} name - Function name or property name
* @param {*} data - Variable input that is handled by child API
* @param {string} method - Internally consistent Postmate method
* @param {string} name - Function name or property name
* @param {*} data - Variable input that is handled by child API
*
* @return {*} Response from child
*/
Expand Down Expand Up @@ -256,8 +263,8 @@ class ChildAPI {
*
* @async
*
* @param {string} key - Property name
* @param {*} value - Property value
* @param {string} key - Property name
* @param {*} value - Property value
*
* @return {boolean} Success status
*
Expand Down Expand Up @@ -303,13 +310,13 @@ class ParentAPI {
*
* @class ParentAPI
*
* @param {object} methods - Functions that are available for the parent to call.
* @param {object} properties - Properties to memorize in the instance for later use, optional
* @param {object} methods - Functions that are available for the parent to call.
* @param {object} properties - Properties to memorize in the instance for later use, optional
*
* @prop {promise} listener - Promise that is waiting for parent to connect
* @prop {object} msg_bus - Postmate instance
* @prop {object} methods - Method storage
* @prop {object} properties - Set properties storage
* @prop {promise} listener - Promise that is waiting for parent to connect
* @prop {object} msg_bus - Postmate instance
* @prop {object} methods - Method storage
* @prop {object} properties - Set properties storage
*
* @example
* const parent = new ParentAPI({
Expand All @@ -320,6 +327,7 @@ class ParentAPI {
* await parent.connect();
*/
constructor(methods, properties = {}) {

this.methods = methods;
this.properties = properties;

Expand Down Expand Up @@ -367,12 +375,31 @@ class ParentAPI {
* });
* await parent.connect();
*/
async connect() {
async connect () {
this.msg_bus = await this.listener;

return this;
}

/**
* Send holochain conductor signal to parent.
*
* @async
*
* @param {object} signal - The signal
*
* @example
* const parent = new ParentAPI({
* "hello": async function () {
* return "Hello world";
* }
* });
* await parent.sendSignal(signal);
*/
async sendSignal (signal) {
this.msg_bus.emit('signal', signal)
}

}

export {
Expand Down
22 changes: 22 additions & 0 deletions tests/integration/test_comb.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,28 @@ describe("Testing COMB", function () {
}
});

it("should call the provided signalCb when sendSignal is called on the parent", async function () {
try {
// have to setup our spy function in the puppeteer evaluation context
await page.evaluate(() => {
window.signalCb = function(signal) {
window.signalCbCalledWith = signal
}
});

const expectedSignal = "Hello COMB";

const signalCbCalledWith = await page.evaluate(async function (chap_url, expectedSignal) {
window.child = await COMB.connect(chap_url, 5000, window.signalCb);
await child.run("test_signal", expectedSignal);
return window.signalCbCalledWith
}, chap_url, expectedSignal);

expect(signalCbCalledWith).to.equal(expectedSignal);
} finally {
}
});

it("should timeout because of wrong frame URL", async function () {
try {
const result = await page.evaluate(async function () {
Expand Down

0 comments on commit c5b1ca7

Please sign in to comment.