From 19f5c70e2dbf751da37c734ca7b0832a4cd8b906 Mon Sep 17 00:00:00 2001 From: Marisa DeMeglio Date: Wed, 27 Sep 2017 17:25:22 -0700 Subject: [PATCH] feat(http): completed initial http api - Unified output URLs - created command-line interface - added report json download option. Closes #9 --- package-lock.json | 530 ++++++++++++++++++++++++++++++++++++++++++++- package.json | 7 +- src/cli/cli.js | 9 +- src/core/ace.js | 29 +-- src/core/logger.js | 27 +++ src/http/http.js | 159 +++++++++++++- 6 files changed, 717 insertions(+), 44 deletions(-) create mode 100644 src/core/logger.js diff --git a/package-lock.json b/package-lock.json index 61231d72..60b6d314 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,30 @@ "integrity": "sha1-uB3l9ydOxOdW15fNg08wNkJyTl0=", "dev": true }, + "accepts": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", + "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", + "requires": { + "mime-types": "2.1.17", + "negotiator": "0.6.1" + }, + "dependencies": { + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + } + } + }, "acorn": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.1.tgz", @@ -116,6 +140,11 @@ "resolved": "https://registry.npmjs.org/app-module-path/-/app-module-path-2.2.0.tgz", "integrity": "sha1-ZBqlXft9am8KgUHEucCqULbCTdU=" }, + "append-field": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-0.1.0.tgz", + "integrity": "sha1-bdxY+gg8e8VF08WZWygwzCNm1Eo=" + }, "append-transform": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", @@ -125,6 +154,19 @@ "default-require-extensions": "1.0.0" } }, + "archiver-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz", + "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=", + "requires": { + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "lazystream": "1.0.0", + "lodash": "4.17.4", + "normalize-path": "2.1.1", + "readable-stream": "2.3.1" + } + }, "argly": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/argly/-/argly-1.2.0.tgz", @@ -165,6 +207,11 @@ "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", @@ -662,6 +709,11 @@ "node-int64": "0.4.0" } }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, "buffers": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", @@ -672,6 +724,38 @@ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" }, + "busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "requires": { + "dicer": "0.2.5", + "readable-stream": "1.1.14" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, "bytes": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.5.0.tgz", @@ -879,6 +963,17 @@ "resolved": "https://registry.npmjs.org/complain/-/complain-1.0.0.tgz", "integrity": "sha1-18y740LfPr83IBss89iLbwDm9fU=" }, + "compress-commons": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.0.tgz", + "integrity": "sha1-WFhwku8g03y1i68AARLJJ4/3O58=", + "requires": { + "buffer-crc32": "0.2.13", + "crc32-stream": "2.0.0", + "normalize-path": "2.1.1", + "readable-stream": "2.3.1" + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -900,6 +995,16 @@ "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", "dev": true }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, "content-type-parser": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.1.tgz", @@ -912,6 +1017,16 @@ "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", "dev": true }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, "core-js": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", @@ -922,6 +1037,20 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "crc": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.5.0.tgz", + "integrity": "sha1-mLi6fUiWZbo5efWbITgTdBAaGWQ=" + }, + "crc32-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz", + "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=", + "requires": { + "crc": "3.5.0", + "readable-stream": "2.3.1" + } + }, "cryptiles": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", @@ -1088,6 +1217,11 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + }, "deresolve": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/deresolve/-/deresolve-1.1.2.tgz", @@ -1098,11 +1232,48 @@ "resolve-from": "1.0.1" } }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, "detect-indent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=" }, + "dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "requires": { + "readable-stream": "1.1.14", + "streamsearch": "0.1.2" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, "diff": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.0.tgz", @@ -1139,6 +1310,11 @@ "jsbn": "0.1.1" } }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, "electron": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/electron/-/electron-1.7.5.tgz", @@ -1192,6 +1368,11 @@ } } }, + "encodeurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", + "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" + }, "end-of-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz", @@ -1312,6 +1493,11 @@ "es6-symbol": "3.1.1" } }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -1614,6 +1800,11 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, "event-emitter": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", @@ -1670,6 +1861,75 @@ "fill-range": "2.2.3" } }, + "express": { + "version": "4.15.5", + "resolved": "https://registry.npmjs.org/express/-/express-4.15.5.tgz", + "integrity": "sha1-ZwI1ypWYiQpa6BcLg9tyK4Qu2Sc=", + "requires": { + "accepts": "1.3.4", + "array-flatten": "1.1.1", + "content-disposition": "0.5.2", + "content-type": "1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "1.1.1", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.0.6", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "1.1.5", + "qs": "6.5.0", + "range-parser": "1.2.0", + "send": "0.15.6", + "serve-static": "1.12.6", + "setprototypeof": "1.0.3", + "statuses": "1.3.1", + "type-is": "1.6.15", + "utils-merge": "1.0.0", + "vary": "1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "qs": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz", + "integrity": "sha512-fjVFjW9yhqMhVGwRExCXLhJKrLlkYSaxNWdyc9rmHlrVZbk35YHH312dFd7191uQeXkI3mKLZTIbSvIeFwFemg==" + } + } + }, + "express-easy-zip": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/express-easy-zip/-/express-easy-zip-1.1.4.tgz", + "integrity": "sha1-OT/4tr96nExqGJNtLqiEkOiHNp4=", + "requires": { + "es6-promise": "3.3.1", + "file-exists-promise": "1.0.2", + "fs-readdir-recursive": "1.0.0", + "var-clean": "1.0.1", + "zip-stream": "1.2.0" + }, + "dependencies": { + "es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=" + } + } + }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", @@ -1788,6 +2048,21 @@ "object-assign": "4.1.1" } }, + "file-exists-promise": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/file-exists-promise/-/file-exists-promise-1.0.2.tgz", + "integrity": "sha1-N8EKVJSJIKqYe6XgzS5Uun5E8rQ=", + "requires": { + "es6-promise": "3.3.1" + }, + "dependencies": { + "es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=" + } + } + }, "file-js": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/file-js/-/file-js-0.3.0.tgz", @@ -1853,6 +2128,30 @@ "repeat-string": "1.6.1" } }, + "finalhandler": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz", + "integrity": "sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8=", + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", @@ -1904,6 +2203,16 @@ "mime-types": "2.1.15" } }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, "fs-extra": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", @@ -1914,6 +2223,11 @@ "universalify": "0.1.1" } }, + "fs-readdir-recursive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz", + "integrity": "sha1-jNF0XItPiinIyuw5JHaSG6GV9WA=" + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2244,6 +2558,17 @@ "complain": "1.0.0" } }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": "1.3.1" + } + }, "http-signature": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", @@ -2339,6 +2664,11 @@ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, + "ipaddr.js": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz", + "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA=" + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -3119,6 +3449,14 @@ "dev": true, "optional": true }, + "lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "requires": { + "readable-stream": "2.3.1" + } + }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -3307,6 +3645,11 @@ } } }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, "meow": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", @@ -3386,6 +3729,16 @@ "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=", "dev": true }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, "micromatch": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", @@ -3407,6 +3760,11 @@ "regex-cache": "0.4.3" } }, + "mime": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", + "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" + }, "mime-db": { "version": "1.27.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", @@ -3474,6 +3832,28 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "multer": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.3.0.tgz", + "integrity": "sha1-CSsmcPaEb6SRSWXvyM+Uwg/sbNI=", + "requires": { + "append-field": "0.1.0", + "busboy": "0.2.14", + "concat-stream": "1.6.0", + "mkdirp": "0.5.1", + "object-assign": "3.0.0", + "on-finished": "2.3.0", + "type-is": "1.6.15", + "xtend": "4.0.1" + }, + "dependencies": { + "object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=" + } + } + }, "mute-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", @@ -3490,6 +3870,11 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, "nightmare": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/nightmare/-/nightmare-2.10.0.tgz", @@ -3558,7 +3943,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, "requires": { "remove-trailing-separator": "1.1.0" } @@ -3625,6 +4009,14 @@ "is-extendable": "0.1.1" } }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, "once": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", @@ -3749,6 +4141,11 @@ "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=", "dev": true }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, "path": { "version": "0.12.7", "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", @@ -3783,6 +4180,11 @@ "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", "dev": true }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, "path-type": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", @@ -3970,6 +4372,15 @@ "resolved": "https://registry.npmjs.org/property-handlers/-/property-handlers-1.1.1.tgz", "integrity": "sha1-yyDTIqq32U//rCj0bJGGvVlHtLQ=" }, + "proxy-addr": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz", + "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg=", + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.4.0" + } + }, "prr": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", @@ -4105,6 +4516,11 @@ } } }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, "raptor-async": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/raptor-async/-/raptor-async-1.1.3.tgz", @@ -4293,8 +4709,7 @@ "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" }, "repeat-element": { "version": "1.1.2", @@ -4507,6 +4922,47 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" }, + "send": { + "version": "0.15.6", + "resolved": "https://registry.npmjs.org/send/-/send-0.15.6.tgz", + "integrity": "sha1-IPI6nJJbdiq4JwX+L52yUqzkfjQ=", + "requires": { + "debug": "2.6.9", + "depd": "1.1.1", + "destroy": "1.0.4", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.2", + "mime": "1.3.4", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.3.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "serve-static": { + "version": "1.12.6", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.6.tgz", + "integrity": "sha1-uXN3P2NEmTTaVOW+ul4x2fQhFXc=", + "requires": { + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.15.6" + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -4518,6 +4974,16 @@ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + }, + "sha-1": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/sha-1/-/sha-1-0.1.1.tgz", + "integrity": "sha1-KjkwS/QburEd2e+3R07CWxqSwlc=" + }, "shelljs": { "version": "0.7.8", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", @@ -4716,11 +5182,21 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, "stream-shift": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, "string_decoder": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.2.tgz", @@ -5034,6 +5510,15 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=" }, + "type-is": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.15" + } + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -5077,6 +5562,11 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, "unzip": { "version": "0.1.11", "resolved": "https://registry.npmjs.org/unzip/-/unzip-0.1.11.tgz", @@ -5142,11 +5632,24 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "utils-merge": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", + "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" + }, "uuid": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" }, + "uuidv4": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/uuidv4/-/uuidv4-0.5.0.tgz", + "integrity": "sha1-pTe26n8FVsNq01mICVx9XaarU7o=", + "requires": { + "sha-1": "0.1.1" + } + }, "v8-compile-cache": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-1.1.0.tgz", @@ -5161,6 +5664,16 @@ "spdx-expression-parse": "1.0.4" } }, + "var-clean": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/var-clean/-/var-clean-1.0.1.tgz", + "integrity": "sha1-36mSDfGad68rr4qktm9/wCne3yM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, "verror": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", @@ -5543,6 +6056,17 @@ "requires": { "fd-slicer": "1.0.1" } + }, + "zip-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz", + "integrity": "sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ=", + "requires": { + "archiver-utils": "1.3.0", + "compress-commons": "1.2.0", + "lodash": "4.17.4", + "readable-stream": "2.3.1" + } } } } diff --git a/package.json b/package.json index 7809962a..3a1f14c2 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,8 @@ }, "main": "dist/index.js", "bin": { - "ace": "dist/cli/cli.js" + "ace": "dist/cli/cli.js", + "ace-http": "dist/http/http.js" }, "files": [ "LICENCE.txt", @@ -48,17 +49,21 @@ ], "dependencies": { "axe-core": "^2.3.1", + "express": "^4.15.5", + "express-easy-zip": "^1.1.4", "extract-zip": "^1.6.5", "filehound": "^1.16.2", "fs-extra": "^3.0.1", "h5o": "^0.11.3", "marko": "^4.4.26", "meow": "^3.7.0", + "multer": "^1.3.0", "nightmare": "^2.10.0", "path": "^0.12.7", "shortid": "^2.2.8", "tmp": "0.0.31", "unzip": "^0.1.11", + "uuidv4": "^0.5.0", "winston": "^2.3.1", "xmldom": "^0.1.27", "xpath": "^0.0.24" diff --git a/src/cli/cli.js b/src/cli/cli.js index d87d5047..95258eb6 100755 --- a/src/cli/cli.js +++ b/src/cli/cli.js @@ -7,6 +7,7 @@ const ace = require('../core/ace.js'); const fs = require('fs'); const meow = require('meow'); const path = require('path'); +const logger = require('./logger.js'); const cli = meow(` Usage: ace [options] @@ -40,9 +41,11 @@ const cli = meow(` string: ['outdir', 'tempdir'], }); +logger.initLogger({verbose: cli.flags.verbose, silent: cli.flags.silent}); + // Check that an EPUB path is specified if (cli.input.length === 0) { - console.log('Input required'); + winston.error('Input required'); cli.showHelp(1); } @@ -57,7 +60,7 @@ if (outdir) { .map(file => path.join(outdir, file)) .filter(fs.existsSync); if (overrides.length > 0) { - console.log(`\ + winston.warn(`\ Output directory is not empty. Running Ace would override the following files or directories: @@ -81,6 +84,6 @@ ace(cli.input[0], { jobId: '', }) .catch((err) => { - if (err) console.log(err.message); + if (err) winston.error(err.message); process.exit(1); }); diff --git a/src/core/ace.js b/src/core/ace.js index 149b7f7f..da45a01b 100644 --- a/src/core/ace.js +++ b/src/core/ace.js @@ -9,14 +9,13 @@ const EPUB = require('../epub/epub.js'); const report = require('../report/report.js'); const winston = require('winston'); -const LOGFILE = __dirname + "/../ace.log"; - tmp.setGracefulCleanup(); module.exports = function ace(epubPath, options) { return new Promise((resolve, reject) => { - initLogger(options); - var jobId = 'jobId' in options ? options.jobId : ''; + // the jobid option just gets returned in the resolve/reject + // so the calling function can track which job finished + var jobId = 'jobid' in options ? options.jobid : ''; winston.verbose("ACE", options); // Check that the EPUB exists @@ -93,25 +92,3 @@ module.exports = function ace(epubPath, options) { // getJSON('story.json').then(function(story) { // addHtmlToPage(story.heading); }; - -function initLogger(options) { - // clear old log file - fs.removeSync(LOGFILE); - - // set up logger - var level = 'info'; - if (options.verbose) { - level = 'verbose'; - } - winston.configure({ - level: level, - transports: [ - new (winston.transports.File)({name: "file", filename: LOGFILE}), - new (winston.transports.Console)({name: "console"}) - ] - }); - if (options.silent) { - winston.remove("console"); - } - winston.cli(); -} diff --git a/src/core/logger.js b/src/core/logger.js new file mode 100644 index 00000000..6a5bd948 --- /dev/null +++ b/src/core/logger.js @@ -0,0 +1,27 @@ +const winston = require('winston'); +const fs = require('fs-extra'); +const LOGFILE = __dirname + "/../ace.log"; + +module.exports = { + initLogger: function(options) { + // clear old log file + fs.removeSync(LOGFILE); + + // set up logger + var level = 'info'; + if (options.verbose) { + level = 'verbose'; + } + winston.configure({ + level: level, + transports: [ + new (winston.transports.File)({name: "file", filename: LOGFILE}), + new (winston.transports.Console)({name: "console"}) + ] + }); + if (options.silent) { + winston.remove("console"); + } + winston.cli(); + } +} diff --git a/src/http/http.js b/src/http/http.js index 20db60c1..3ef0c75f 100644 --- a/src/http/http.js +++ b/src/http/http.js @@ -1,24 +1,161 @@ -/* +const express = require('express'); +const uuidv4 = require('uuid/v4'); +const multer = require('multer'); +const fs = require('fs'); +const zip = require('express-easy-zip'); +const path = require('path'); +const tmp = require('tmp'); +const winston = require('winston'); +const ace = require('../core/ace.js'); +const meow = require('meow'); +const logger = require('../core/logger.js'); +const UPLOADS = tmp.dirSync({ unsafeCleanup: true }).name; +const DEFAULTPORT = 8000; +const DEFAULTHOST = "localhost"; +const JOBSTATUS = {"done": 0, "processing": 1, "error": -1} +var server = express(); +var upload = multer({dest: UPLOADS}); +var joblist = []; +const cli = meow(` + Usage: ace-http [options] -create job ID + Options: -create local outdir + -h, --help output usage information + -v, --version output the version number -run ace + -H, --host set the server's hostname (default: ${DEFAULTHOST}) + -p, --port set the server's port (default: ${DEFAULTPORT}) -return json report and job ID + -V, --verbose display verbose output + -s, --silent do not display any output -*/ + Examples + $ ace-http -p 3000 +`, { + alias: { + h: 'help', + s: 'silent', + v: 'version', + V: 'verbose', + H: 'host', + p: 'port' + }, + boolean: ['verbose', 'silent'], + string: ['host', 'port'], +}); -/* options -port -local tmp dir -*/ -module.exports = function aceHttp(options) { +logger.initLogger({verbose: cli.flags.verbose, silent: cli.flags.silent}); +server = express(); +server.use(zip()); +initRoutes(); +var host = cli.flags.host ? cli.flags.host : DEFAULTHOST; +var port = cli.flags.port ? cli.flags.port : DEFAULTPORT; +var baseurl = "http://" + host + ":" + port; // just for convenience +// todo customize port and hostname +server.listen(port, host, function() { + winston.info("Ace server listening on " + baseurl); +}); +function initRoutes() { + server.get('/jobs/:jobid', getJob); + server.post('/jobs/', upload.single('epub'), postJob); + server.use('/jobs/:jobid/report/', getReport); + server.get('/jobs/', getJobs); +} + +// return the job information +function getJob(req, res, next) { + var jobdata = joblist.find(jobdata => jobdata.internal.id === req.params.jobid); + if (jobdata == undefined || jobdata == null) { + res.sendStatus(404); // not found + } + else { + res.json(jobdata.public); + } + next(); +} + +// return a list of job objects +function getJobs(req, res, next) { + let jobsinfo = joblist.map((jobdata, index, joblist) => { + return jobdata.public; + }); + res.json(jobsinfo); + next(); +} + +// return the job information +function postJob(req, res, next) { + if (req.file == undefined) { + res.sendStatus(400); // bad request + } + else { + var jobid = uuidv4(); + var jobdata = { + public: { + "job": baseurl + "/jobs/" + jobid, + "status": JOBSTATUS.processing, + "report": {"zip": undefined, "json": undefined} + }, + internal: { + "id": jobid, + "outputDir": tmp.dirSync({ unsafeCleanup: true }).name, + "epubPath": req.file.path + } + }; + newJob(jobdata); + + res.status(201); // created + res.json(jobdata.public); + } + next(); +} + +// return the report as either a zipfile or a json object, depending on what was specifically requested +function getReport(req, res) { + var jobdata = joblist.find(jobdata => jobdata.internal.id === req.params.jobid); + if (jobdata == undefined || jobdata == null) { + res.sendStatus(404); // not found + } + else { + if ("type" in req.query && req.query.type === "json") { + var jsonReport = require(path.join(jobdata.internal.outputDir, "ace.json")); + res.json(jsonReport); + } + else { + res.zip({ + files: [ + { path: jobdata.internal.outputDir, name: 'ace-report-' + jobdata.internal.id } + ], + filename: 'ace-report-' + jobdata.internal.id + '.zip' + }); + } + } +} + +// start a new job +function newJob(jobdata) { + winston.info("Job started"); + joblist.push(jobdata); + + // execute the job with Ace + ace(jobdata.internal.epubPath, {'jobid': jobdata.internal.id, 'outdir': jobdata.internal.outputDir}) + .then((jobid) => { + var idx = joblist.findIndex(job => job.internal.id === jobid); + winston.info("Job finished " + joblist[idx].internal.id); + joblist[idx].public.status = JOBSTATUS.done; + joblist[idx].public.report.zip = joblist[idx].public.job + "/report/?type=zip"; + joblist[idx].public.report.json = joblist[idx].public.job + "/report/?type=json"; + }) + .catch((jobid) => { + var idx = joblist.findIndex(job => job.internal.id === jobid); + winston.info("Job error " + joblist[idx].internal.id); + joblist[idx].public.status = JOBSTATUS.error; + }); }