UNPKG

antfarm

Version:

File automation framework for ants.

278 lines (228 loc) 7.99 kB
import {Environment} from "./environment"; import {WebhookNest} from "../nest/webhookNest"; import {WebhookJob} from "../job/webhookJob"; import * as express from "express"; import {InterfaceManager} from "../ui/interfaceManager"; import {Logger, LogQueryOptions} from "./logger"; const cors = require("cors"), multer = require("multer"), path = require("path"), tmp = require("tmp"), async = require("async"); /** * Webhook and logging server. */ export class Server { protected server: express.Application; protected e: Environment; protected hookRoutes = []; protected hookInterfaceRoutes = []; protected upload; protected config = { hooks_prefix: "/hooks", hooks_ui_prefix: "/hooks-ui", log_prefix: "/log" }; constructor(e: Environment) { let s = this; s.e = e; s.server = express(); s.createServer(); // let tmpDir = tmp.dirSync()._name; let tmpDir = "./example"; s.upload = multer({ destination: tmpDir, storage: multer.diskStorage({ filename: function (req, file, cb) { cb(null, file.fieldname + "-" + Date.now()); } }) }); } /** * Creates the server. */ protected createServer() { let s = this; let port = s.e.options.port; s.server.use(cors()); // Add index routes s.server.get(s.config.hooks_prefix, function(req, res){ res.json(s.hookRoutes); }); s.server.get(s.config.hooks_ui_prefix, function(req, res){ res.json(s.hookInterfaceRoutes); }); // Prevent duplicate listening for tests // if (!module.parent) { // s.server.listen(port, () => s.e.log(1, `Server up and listening on port ${port}.`, s)); // } s.server.listen(port, () => s.e.log(1, `Server up and listening on port ${port}.`, s)) .on("error", (err) => { s.e.log(3, `Server listen error: "${err.message}".`, s); }); } public createLogServer(logger: Logger) { let s = this; let options = { order: "desc", fields: ["message"] } as LogQueryOptions; // Add index routes s.server.get(s.config.log_prefix, (req, res) => { logger.query(options, results => { res.json(results); }); }); } /** * Log _name * @returns {string} */ public toString() { return "Server"; } /** * Adds a webhook to the server. * @param nest {WebhookNest} */ public addWebhook(nest: WebhookNest) { let s = this; let e = s.e; let httpMethod = nest.httpMethod; let hook_path = s.config.hooks_prefix + nest.path; let hook_ui_path; let im = nest.interfaceManager; let wi = im.getInterface(); hook_ui_path = s.config.hooks_ui_prefix + im.path; s.e.log(1, `Watching webhook ${httpMethod.toUpperCase()} ${hook_path}`, s); s.hookRoutes.push({ id: nest.id, path: hook_path, nest: nest.name, tunnel: nest.tunnel.name, method: httpMethod, interface_path: hook_ui_path }); s.server[httpMethod](hook_path, s.upload.any(), function (req, res) { let customHandler = nest.customHandleRequest; s.handleHookRequest(nest, req, res, customHandler); }); } /** * Handles request and response of the web hook, creates a new job, as well as calling the nest's arrive. * @param nest {WebhookNest} * @param req {express.Request} * @param res {express.Response} * @param customHandler Custom request handler. */ protected handleHookRequest (nest: WebhookNest, req, res, customHandler?: any) { let s = this; // Job arrive let job = new WebhookJob(s.e, req, res); nest.arrive(job); s.sendHookResponse(nest.holdResponse, job, nest, req, res, customHandler); }; /** * Sends the actual hook response. * @param holdResponse Flag to bypass sending now for held responses. * @param job Webhook job * @param nest Webhook nest * @param req * @param res * @param customHandler * @param message */ public sendHookResponse (holdResponse: boolean, job: WebhookJob, nest: WebhookNest, req, res, customHandler?: any, message?: string) { if (holdResponse === true) { // do nothing } else if (customHandler) { job.responseSent = true; customHandler(req, res, job, nest); } else { job.responseSent = true; let response = { message: message || `Job ${job.id} was created!`, job: { id: job.id, name: job.name }, nest: { name: nest.name } }; res.json(response); } } /** * Adds a webhook interface to the webhook server. * @param im {InterfaceManager} */ public addWebhookInterface(im: InterfaceManager) { let s = this; let nest = im.nest; let hook_path = s.config.hooks_prefix + nest.path; let hook_ui_path = s.config.hooks_ui_prefix + im.path; s.e.log(1, `Watching webhook interface GET ${hook_ui_path}`, s); this.hookInterfaceRoutes.push({ id: nest.id, path: hook_ui_path, nest: nest.name, target: hook_path // tunnel: nest.getTunnel().name }); s.server.get(hook_ui_path, function (req, res) { let customHandler = im.customHandleRequest; s.handleHookInterfaceRequest(im, req, res, customHandler); }); } /** * Handles request and response of the web hook interface. * @param im {InterfaceManager} * @param req {express.Request} * @param res {express.Response} * @param customHandler Custom request handler. */ protected handleHookInterfaceRequest = function(im: InterfaceManager, req, res, customHandler?: any) { let s = this; // Job arrive let job = new WebhookJob(s.e, req, res); // Fill in default values let params = job.getQueryStringValues(); // If session not set, return a fresh ui somehow let sessionId = params["sessionId"] || job.getFormDataValue("sessionId"); let ui = im.getInterface(sessionId); if (ui.sessionId === sessionId) { // Fill in default values ui.fields.forEach(field => { if (field.id in params && params[field.id] !== "undefined") { field.value = params[field.id]; } }); // Do steps async.each(ui.steps, (step, cb) => { s.e.log(0, `Running UI step "${step.name}".`, s); step.callback(job, ui, step, () => { cb(); }); }, (err) => { if (err) { s.e.log(3, `Error running UI steps. ${err}`, s); } else { s.e.log(0, `Done running all UI steps.`, s); } if (customHandler) { customHandler(req, res, ui); } else { res.json(ui.getTransportInterface()); } }); } else { if (customHandler) { customHandler(req, res, ui); } else { res.json(ui.getTransportInterface()); } } }; }