This code provides a framework for creating cloud functions by defining a generic handler and a function to generate specialized handlers from code snippets.
npm run import -- "generic gcloud function handler"
var importer = require('../Core')
var {selectAst} = importer.import("select ast")
var {
niceName, getExports, getParameters
} = importer.import("nice name",
"get exports",
"get parameters")
async function handler(req, res) {
if(!req && process.stdout.isTTY) {
res = {}
req = {query: {}, body: {}, form: {}}
Array.from(process.argv).forEach(arg => {
req.query[arg.split('=')[0]] = arg.split('=').slice(1).join('=')
})
}
res.set('Access-Control-Allow-Origin', '*')
var parameters = Object.values(req.query || {})
.concat(Object.values(req.body || {}))
.concat(Object.values(req.form || {}))
var func = require('./entry.js')
return await func(...parameters)
.then(r => !res ? console.log(r) : res.status(200).send(r))
.catch(e => !res ? console.log(e) : res.status(500).send(e))
}
// use syntax to alter the function handler above
// to pull out parameters and call the requested function
// slightly simpler code than including the entire library
function makeHandler(entry) {
var thisCell = importer.interpret('generic cloud function handler')
if(!Array.isArray(entry)) {
entry = [entry]
}
var exports = []
var interpret = importer.interpret(entry)
var handlers = interpret.map(cell => {
// replace the require statement
// TODO: make this part generic, moving vars to parameters
var doc = selectAst('.', handler.toString())
var exportsName = getExports(cell.code)[0]
exports.push(exportsName + 'Handler')
var functionStmt = selectAst(`
//FunctionDeclaration/Identifier[@name="handler"]`, doc)
functionStmt.setAttribute('name', exportsName + 'Handler')
var parameters = getParameters(cell.code).slice(1)
// replace the parameters with names
var replaceParams = selectAst('//VariableDeclaration', `
var parameters = [${parameters
.map(p => `(req.body || {})['${p}'] || (req.form || {})['${p}'] || (req.query || {})['${p}']`)
.join(',\n')}]`)
var assignmentStmt = selectAst([`//VariableDeclaration[./*/*[@name = "parameters"]]`], doc)
assignmentStmt[0].replaceWith(replaceParams)
var requireStmt = selectAst(`//VariableDeclaration[./*/*[@name = "func"]]`, doc)
var replaceRequire = selectAst('//VariableDeclaration', `
var ${exportsName} = require('./${niceName(cell)}')`)
requireStmt.replaceWith(replaceRequire)
// replace function call with new named
var callStmt = selectAst(`//CallExpression/Identifier[@name = "func"]`, doc)
callStmt.setAttribute('name', exportsName)
return doc.ownerDocument.toString()
}).join('\n\n')
return `${handlers}
module.exports = {
${exports.join(',\n ')}
}`
}
module.exports = {
makeHandler,
handler
}
const importer = require('../Core');
const { selectAst, niceName, getExports, getParameters } = importer.import([
'select ast',
'nice name',
'get exports',
'get parameters',
]);
async function handler(req, res) {
if (!req && process.stdout.isTTY) {
req = { query: {}, body: {}, form: {} };
Object.assign(req.query, process.argv.slice(2).reduce((acc, arg) => {
const [key, value] = arg.split('=');
acc[key] = value;
return acc;
}, {}));
}
res.set('Access-Control-Allow-Origin', '*');
const query = Object.values(req.query || {});
const body = Object.values(req.body || {});
const form = Object.values(req.form || {});
const parameters = [...query,...body,...form];
const entry = require('./entry.js');
return await entry(...parameters)
.then((r) => res.status(200).send(r))
.catch((e) => res.status(500).send(e));
}
function makeHandler(entry) {
if (!Array.isArray(entry)) {
entry = [entry];
}
const handlers = entry.map((cell) => {
const exportsName = getExports(cell.code)[0];
const funcName = niceName(cell);
const parameters = getParameters(cell.code).slice(1);
const reqAccess = `req.${parameters.map((p) => p).join('.')}`;
const funcCall = `require('./${funcName}')(${parameters.map((p) => reqAccess).join(', ')})`;
const newFunc = `
function ${exportsName}Handler(req, res) {
try {
return ${funcCall}
.then((r) => res.status(200).send(r))
.catch((e) => res.status(500).send(e));
} catch (e) {
console.error(e);
res.status(500).send(e);
}
}`;
return newFunc;
}).join('\n\n');
return `${handlers}
module.exports = {
${Object.keys(entry)
.map((cell) => getExports(cell.code)[0] + 'Handler')
.join(',\n ')},
}`;
}
module.exports = {
makeHandler,
handler,
};
This code defines a generic cloud function handler and a function makeHandler
to create specialized handlers from code snippets.
Here's a breakdown:
Imports:
handler
Function:
req
) and responses (res
).req
and res
objects.Access-Control-Allow-Origin
header to allow requests from any origin.entry.js
file, which likely contains the code for the specific function to be executed.res
is not provided (likely in a TTY environment), it logs the result to the console.res
is provided, it sends the result as a response with a 200 status code.res
is not provided, it logs the error to the console.res
is provided, it sends the error as a response with a 500 status code.makeHandler
Function:
entry
) as input and generates a specialized handler function.importer.interpret
.