libkernel
Advanced tools
Comparing version 0.0.43 to 0.0.44
@@ -1,2 +0,2 @@ | ||
export { init, postKernelQuery } from './init'; | ||
export { init, newKernelQuery } from './init'; | ||
export { testMessage, callModule, upload, padAndEncrypt } from './messages'; |
@@ -1,2 +0,2 @@ | ||
export { init, postKernelQuery } from './init'; | ||
export { init, newKernelQuery } from './init'; | ||
export { testMessage, callModule, upload, padAndEncrypt } from './messages'; |
export declare function log(...inputs: any): void; | ||
export declare function logErr(...inputs: any): void; | ||
export declare function postKernelQuery(queryData: any): Promise<any>; | ||
export declare function composeErr(...inputs: any): string; | ||
export declare function newKernelQuery(data: any, update: Function): [Function, Promise<any>]; | ||
export declare function init(): Promise<string>; |
113
dist/init.js
@@ -10,5 +10,36 @@ // log provides a wrapper for console.log that prefixes 'libkernel'. | ||
} | ||
// composeErr takes a series of inputs and composes them into a single string. | ||
// Each element will be separated by a newline. If the input is not a string, | ||
// it will be transformed into a string with JSON.stringify. | ||
// | ||
// Any object that cannot be stringified will be skipped, though an error will | ||
// be logged. | ||
export function composeErr(...inputs) { | ||
let result = ""; | ||
for (let i = 0; i < inputs.length; i++) { | ||
// Prepend a newline if this isn't the first element. | ||
if (i !== 0) { | ||
result += "\n"; | ||
} | ||
// Strings can be added without modification. | ||
if (typeof inputs[i] === "string") { | ||
result += inputs[i]; | ||
continue; | ||
} | ||
// Everything else needs to be stringified, log an error if it | ||
// fails. | ||
try { | ||
let str = JSON.stringify(inputs[i]); | ||
result += str; | ||
} | ||
catch (_a) { | ||
logErr("unable to stringify input to composeErr"); | ||
} | ||
} | ||
return result; | ||
} | ||
// Establish a hashmap for matching queries to their responses by their nonces. | ||
// nextNonce needs to start at '1' because '0' is reserved for the bridgeTest | ||
// method performed at init. | ||
const namespace = "libkernel-v0"; | ||
var nextNonce = 1; | ||
@@ -36,2 +67,13 @@ var queries = new Object(); | ||
} | ||
// Establish a system to test if the bridge script is running. bridgeExists is | ||
// a boolean which establishes whether or not we have already determinied if | ||
// the bridge eixsts, bridgeAvailable is the {resolve, reject} object for a | ||
// promise, and the blockForBridge will resolve/reject when we have determined | ||
// if the bridge exists. | ||
// | ||
// The init() function will use a timeout to decide that the bridge does not | ||
// exist, the hanelMessage function will look for a method called | ||
// "bridgeTestResponse" to determine that the bridge does exist. The init | ||
// script needs to send the bridge a "bridgeTestQuery" message so the bridge | ||
// knows to respond. | ||
var initialized; | ||
@@ -41,21 +83,36 @@ var bridgeExists; | ||
var blockForBridge = new Promise((resolve, reject) => { | ||
bridgeAvailable = { resolve, reject, handle: handleBridgeResponse }; | ||
bridgeAvailable = { resolve, reject, update: null, handle: handleBridgeResponse }; | ||
}); | ||
// postKernelQuery will send a postMessage to the kernel, handling details like | ||
// the nonce and the resolve/reject upon receiving a response. The inputs are a | ||
// resolve and reject function of a promise that should be resolved when the | ||
// response is received, and the message that is going to the kernel itself. | ||
export function postKernelQuery(queryData) { | ||
return new Promise((resolve, reject) => { | ||
let nonce = nextNonce; | ||
nextNonce++; | ||
queries[nonce] = { resolve, reject, handle: handleKernelResponse }; | ||
// newKernelQuery will send a postMessage to the kernel, handling details like | ||
// the nonce and the resolve/reject upon receiving a response. | ||
// | ||
// The first return value is a function that can be called to send a | ||
// 'queryUpdate' to the kernel for that nonce. | ||
export function newKernelQuery(data, update) { | ||
let nonce = nextNonce; | ||
nextNonce++; | ||
let sendUpdate = function (data) { | ||
queryUpdate(nonce, data); | ||
}; | ||
let p = new Promise((resolve, reject) => { | ||
queries[nonce] = { resolve, reject, update, handle: handleKernelResponse }; | ||
window.postMessage({ | ||
namespace: "libkernel", | ||
namespace, | ||
method: "newKernelQuery", | ||
nonce, | ||
queryData, | ||
data, | ||
}); | ||
}); | ||
return [sendUpdate, p]; | ||
} | ||
// queryUpdate is a function that can be called to send a queryUpdate to an | ||
// existing query. | ||
function queryUpdate(nonce, data) { | ||
window.postMessage({ | ||
namespace, | ||
method: "queryUpdate", | ||
nonce, | ||
data, | ||
}); | ||
} | ||
// handleKernelResponse will parse the kernel's response from the bridge and | ||
@@ -80,9 +137,11 @@ // resolve/reject the promise associated with the nonce. | ||
// Check that this message is a response targeting libkernel. | ||
if (!("data" in event) || !("method" in event.data) || event.data.namespace !== "libkernel") { | ||
if (event.data.namespace !== namespace) { | ||
return; | ||
} | ||
if (typeof event.data.method !== "string") { | ||
if (!("method" in event.data) || typeof event.data.method !== "string") { | ||
logErr("received message targeting our namespace with malformed method", event.data); | ||
return; | ||
} | ||
if (event.data.method !== "response" && event.data.method !== "responseUpdate") { | ||
logErr("received message targeting our namespace with unknown method", event.data); | ||
return; | ||
@@ -95,3 +154,18 @@ } | ||
} | ||
// Check that there is data for this nonce. | ||
// If this is a responseUpdate, pass the data to the update handler. | ||
if (event.data.method === "responseUpdate") { | ||
let handler = queries[event.data.nonce]; | ||
if (!("update" in handler) || typeof handler.update !== "function") { | ||
logErr("responseUpdate received, but no update method defined in handler"); | ||
return; | ||
} | ||
if (!("data" in event.data)) { | ||
logErr("responseUpdate received, but no data provided: " + JSON.stringify(event.data)); | ||
return; | ||
} | ||
handler.update(event.data.data); | ||
return; | ||
} | ||
// The method is "response", meaning the query is closed out can can be | ||
// deleted. | ||
let handler = queries[event.data.nonce]; | ||
@@ -107,8 +181,7 @@ delete queries[event.data.nonce]; | ||
} | ||
if ("data" in event.data) { | ||
handler.handle(handler.resolve, handler.reject, event.data.data); | ||
} | ||
else { | ||
if (!("data" in event.data)) { | ||
handler.reject("no data field provided in query: " + JSON.stringify(event.data)); | ||
return; | ||
} | ||
handler.handle(handler.resolve, handler.reject, event.data.data); | ||
} | ||
@@ -130,3 +203,3 @@ // init will add an event listener for messages from the kernel bridge. It is | ||
window.postMessage({ | ||
namespace: "libkernel", | ||
namespace, | ||
nonce: 0, | ||
@@ -133,0 +206,0 @@ method: "test", |
@@ -1,2 +0,3 @@ | ||
import { logErr, init, postKernelQuery } from './init'; | ||
import { logErr, composeErr, init, newKernelQuery } from './init'; | ||
const noBridge = "the bridge failed to initialize (do you have the Skynet browser extension?)"; | ||
// testMessage will send a test message to the kernel, ensuring that basic | ||
@@ -17,12 +18,27 @@ // kernel communications are working. The promise will resolve to the version | ||
.then(x => { | ||
// Send a 'requestTest' message to the kernel. The | ||
// request test message uniquely doesn't have any other | ||
// parameters. | ||
postKernelQuery({ | ||
kernelMethod: "requestTest", | ||
}) | ||
// We use nested promises instead of promise chaining | ||
// because promise chaining didn't provide enough | ||
// control over handling the error. | ||
.then(response => { | ||
// Send a 'test' message to the kernel, which is a | ||
// method with no parameters. | ||
// | ||
// The first return value of newKernelQuery is ignored | ||
// because it is an update function that we can call if | ||
// we wish to provide new information to the query via | ||
// a 'queryUpdate'. The 'test' method does not support | ||
// any queryUpdates. | ||
// | ||
// The second input of newKernelQuery is passed as | ||
// null, it's usually a handler function to accept | ||
// 'responseUpdate' messages from the kernel related to | ||
// the query. The 'test' method doesn't have any | ||
// 'responseUpdates', so there is no need to create an | ||
// updateHandler. | ||
let [_, query] = newKernelQuery({ | ||
method: "test", | ||
}, null); | ||
// We use nested promises instead of promise chaining | ||
// because promise chaining didn't provide enough | ||
// control over handling the error. We like wrapping | ||
// our errors to help indicate exactly which part of | ||
// the code has gone wrong, and that nuance gets lost | ||
// with promise chaining. | ||
query.then(response => { | ||
if (!("version" in response)) { | ||
@@ -35,3 +51,4 @@ resolve("kernel did not report a version"); | ||
.catch(err => { | ||
reject(err); | ||
let cErr = composeErr("newKernelQuery failed", err); | ||
reject(cErr); | ||
}); | ||
@@ -43,4 +60,5 @@ }) | ||
// the browser extension. | ||
logErr("bridge is not initialized:", err); | ||
reject(err); | ||
let cErr = composeErr(noBridge, err); | ||
logErr(cErr); | ||
reject(cErr); | ||
}); | ||
@@ -56,17 +74,15 @@ }); | ||
.then(x => { | ||
return postKernelQuery({ | ||
kernelMethod: "moduleCall", | ||
let [_, query] = newKernelQuery({ | ||
method: "moduleCall", | ||
module, | ||
moduleMethod, | ||
moduleInput, | ||
}) | ||
.then(response => { | ||
}, null); | ||
query.then(response => { | ||
resolve(response); | ||
}) | ||
.catch(response => { | ||
.catch(err => { | ||
// Consumer doesn't care about the reponse or | ||
// the query status. | ||
delete response.nonce; | ||
delete response.queryStatus; | ||
reject(response); | ||
reject(err); | ||
}); | ||
@@ -92,3 +108,3 @@ }) | ||
.then(x => { | ||
return postKernelQuery({ | ||
let [_, query] = newKernelQuery({ | ||
kernelMethod: "moduleCall", | ||
@@ -101,4 +117,4 @@ module: "AQCS3RHbDlk00IdICFEI1rKZp-VNsnsKWC0n7K-taoAuog", | ||
}, | ||
}) | ||
.then(response => { | ||
}, null); | ||
query.then(response => { | ||
resolve(response.output); | ||
@@ -126,3 +142,3 @@ }) | ||
.then(x => { | ||
postKernelQuery({ | ||
let [_, query] = newKernelQuery({ | ||
kernelMethod: "moduleCall", | ||
@@ -135,4 +151,4 @@ module: "AQAs00kS6OKUd-FIWj9qdJLArCiEDMVgYBSkaetuTF-MsQ", | ||
}, | ||
}) | ||
.then(response => { | ||
}, null); | ||
query.then(response => { | ||
resolve(response.output); | ||
@@ -139,0 +155,0 @@ }) |
{ | ||
"name": "libkernel", | ||
"version": "0.0.43", | ||
"version": "0.0.44", | ||
"description": "helper library to interact with the skynet kernel", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
15232
381