var rp = require('request-promise'); var fs = require("fs"); var auth = require('./config').auth; var api = require('./config').api; //========================================================= //utilities let options = {uri: api,headers: {"Authorization":auth}}; var cstr = function(ob){console.log(JSON.stringify(ob,null,4))} var reldir = "./functions/"; var getFuncs = function(funcName) { return new Promise(function(done,fail) { fs.readFile(reldir + funcName+ '.js','utf8', (err, file) => { if (err) {fail(err)} done(file); }) }) }; //========================================================= /** * @method importDeploy * @desc Update an existing or create a new eventing function using the CB eventing API * @param funcName Name of a function in <root>/functions * @param update Boolean */ //function (and file) name, and flag for update versus create var myArgs = process.argv.slice(2); console.log('functionName: ', myArgs[0]); console.log('update: ', myArgs[1]); importDeploy(myArgs[0],myArgs[1]) .then(r =>{console.log("importDeploy finished!");}) .catch(e =>{ console.error("importDeploy failed!"); console.error(e); }) async function importDeploy(funcName,update) { //get the server cached functions //when we submit our import request, we need to submit //a object describing the function those being returned here (lots of settings and stuff) var op1 = Object.assign({},options); op1.uri += "/functions";op1.method = "GET"; var funcs = await rp(op1);funcs = JSON.parse(funcs); console.log(funcs.length + " functions present"); if(update){ console.log("updating",funcName + ".js"); //find the one we're updating var f = funcs.filter(fu =>{return fu.appname === funcName}) //grab the contents of the file of the function we're updating //and replace just the code part of it f[0].appcode = await getFuncs(funcName) var op2 = Object.assign({},options) op2.uri += "/import";op2.method = "POST"; //import expects an array of objects describing functions to import op2.json = [f[0]]; /** * @method waitStatus * @desc Just keeps checking to see if your deployment or undeployment has finished * @param funcName String * @param operation Boolean */ var waitStatus = function(funcName,operation){ return new Promise(function(done, fail) { console.log("waitStatus resolving on a deployment_status of: ",operation); var id = setInterval(function(){ //console.log("checking..."); var op1 = Object.assign({},options); op1.uri += "/functions";op1.method = "GET"; rp(op1).then(funcs =>{ funcs = JSON.parse(funcs); var f = funcs.filter(fu =>{return fu.appname === funcName}) var t = (f[0].settings.deployment_status) && (f[0].settings.processing_status); if(operation === t){ clearInterval(id); done(true) } }) },3000) }) }; //if we're currently deployed, stop that if(f[0].settings.deployment_status){ var op3 = Object.assign({},options) op3.uri += "/functions/" + f[0].appname + "/settings"; op3.method = "POST"; op3.json = {"deployment_status":false,"processing_status":false}; //console.log(op3); console.log("undeploy..."); await rp(op3); //note: on successes, the response here is undefined? //this always works, but why don't I get a response here? //on failure we'll just catch it outside //var undeploy = await rp(op3); //console.log("undeploy:",undeploy === undefined); var newStatus = await waitStatus(funcName,false); console.log("undeployment complete"); } console.log("posting import...",{appname:op2.json[0].appname,appcodeLength:op2.json[0].appcode.length}); var postUpdate = await rp(op2); //console.log(postUpdate); //feature: check trip conditions //you can put trash in your functions, you can mis-label them... //not really sure what exactly could trigger a warning here yet if(postUpdate[0].info.warnings){ var err = "import failure"; console.log(err); throw new Error(err); } console.log("import success"); var op4 = Object.assign({},options) op4.uri += "/functions/" + f[0].appname + "/settings"; op4.method = "POST"; op4.json = {"deployment_status":true,"processing_status":true}; console.log("deploying..."); await rp(op4); await waitStatus(funcName,true); console.log("deployment complete"); } else{ //todo: creation code //probably like just copy settings from the default config? } }