From f2917c33558a6471e157c7b11577e7c1e8819082 Mon Sep 17 00:00:00 2001 From: Jermolene Date: Sun, 14 Oct 2018 18:34:55 +0100 Subject: [PATCH] Add support for remote commands Makes it possible to invoke any of TW5's Node.js commands from the browser. Useful for the new pipe command, but also handy for e.g. rendering tiddlers on the server, fetching remote files, or importing local files etc Docs to come. --- core/modules/server/routes/post-commands.js | 57 +++++++++++++++++++ core/modules/syncer.js | 5 ++ .../tiddlywiki/tiddlyweb/tiddlywebadaptor.js | 40 +++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 core/modules/server/routes/post-commands.js diff --git a/core/modules/server/routes/post-commands.js b/core/modules/server/routes/post-commands.js new file mode 100644 index 000000000..1bd2137e5 --- /dev/null +++ b/core/modules/server/routes/post-commands.js @@ -0,0 +1,57 @@ +/*\ +title: $:/core/modules/server/routes/post-commands.js +type: application/javascript +module-type: route + +POST /commands/ + +\*/ +(function() { + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +exports.method = "POST"; + +exports.path = /^\/commands\/$/; + +exports.handler = function(request,response,state) { + // Check we're enabled + +console.log("wikiInfo",$tw.boot.wikiInfo) + if(!($tw.boot.wikiInfo.config || {})["allow-remote-commands"]) { + response.writeHead(404); + response.end(); + return; + } + // Get the job descriptor + var jobDescriptor = JSON.parse(state.data); + console.log("JOB START:",jobDescriptor) + // Respond OK + response.writeHead(204, "OK",{ + "Content-Type": "application/json" + }); + // Maintain status + var setStatus = function(status,message) { + if(jobDescriptor.statusTitle) { + state.wiki.addTiddler(new $tw.Tiddler({title: jobDescriptor.statusTitle,text: status,message: message})); + } + } + setStatus("started"); + // Initiate the commands + var commander = new $tw.Commander( + jobDescriptor.commands || [], + function(err) { + setStatus(err ? "error" : "ok",err ? err : undefined); + console.log("JOB END:",err) + }, + state.wiki, + {output: process.stdout, error: process.stderr} + ); + commander.execute(); + // Return results + response.end(JSON.stringify({}),"utf8"); // Nothing useful for us to return +}; + +}()); diff --git a/core/modules/syncer.js b/core/modules/syncer.js index e6d86ea61..3a0743b6e 100644 --- a/core/modules/syncer.js +++ b/core/modules/syncer.js @@ -84,6 +84,11 @@ function Syncer(options) { $tw.rootWidget.addEventListener("tm-server-refresh",function() { self.handleRefreshEvent(); }); + $tw.rootWidget.addEventListener("tm-execute-job",function(event) { + if(self.syncadaptor && self.syncadaptor.executeJob) { + self.syncadaptor.executeJob(event); + } + }); } // Listen out for lazyLoad events if(!this.disableUI) { diff --git a/plugins/tiddlywiki/tiddlyweb/tiddlywebadaptor.js b/plugins/tiddlywiki/tiddlyweb/tiddlywebadaptor.js index 492909324..f5c064027 100644 --- a/plugins/tiddlywiki/tiddlyweb/tiddlywebadaptor.js +++ b/plugins/tiddlywiki/tiddlyweb/tiddlywebadaptor.js @@ -140,6 +140,46 @@ TiddlyWebAdaptor.prototype.getCsrfToken = function() { return csrf; }; +/* +*/ +TiddlyWebAdaptor.prototype.executeJob = function(event,callback) { + var paramObject = event.paramObject || {}; + // Collect the commands + var commands; + if(paramObject.commands) { + commands = $tw.utils.parseStringArray(paramObject.commands); + } else { + // Get the values of the numeric parameters and sort them by their numeric name + commands = Object.keys(paramObject).filter(function(name) { + // We just include parameters that are identical to their numeric representation + return (parseInt(name,10) + "") === name; + }).map(function(name) { + return parseInt(name,10); + }).sort().map(function(index) { + return paramObject[index + ""]; + }); + } + // Compose the request + var options = { + url: this.host + "commands/", + type: "POST", + data: JSON.stringify({ + commands: commands, + statusTitle: paramObject.statusTitle, + outputTitle: paramObject.outputTitle, + errorTitle: paramObject.errorTitle + }), + callback: function(err,data) { + if(callback) { + callback(err,data); + } + } + }; + // Send the request + this.logger.log("Executing job:",options); + $tw.utils.httpRequest(options); +}; + /* Get an array of skinny tiddler fields from the server */