diff --git a/.gitignore b/.gitignore index fc4d205..95339c2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,9 @@ node_modules -credentials.json -download_tests build -FileShare +logs upload/ lathes/ mills/ diff --git a/docker-compose.yml b/docker-compose.yml index ef34b79..b4dabdf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,6 +34,7 @@ services: env_file: ./.env volumes: - ./src/build:/ffs/ + - ./logs:/ffs/logs - /ffs/node_modules - ./file_share:/ffs/file_share/ - ${LOCAL_DIR_GANTRY}:/ffs/file_share/Gantry/ diff --git a/package-lock.json b/package-lock.json index eec1d83..b6c4ab4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,8 @@ "express": "^4.17.1", "forge-apis": "^0.8.6", "generic-pool": "^3.8.2", - "ts-postgres": "^1.2.1" + "ts-postgres": "^1.2.1", + "winston": "^3.5.1" }, "devDependencies": { "@types/dotenv": "^8.2.0", @@ -137,6 +138,16 @@ "node": ">=4" } }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -492,6 +503,11 @@ "node": ">=8" } }, + "node_modules/async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -710,6 +726,15 @@ "fsevents": "~2.3.2" } }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -725,8 +750,46 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "node_modules/combined-stream": { "version": "1.0.8", @@ -922,6 +985,11 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -1546,6 +1614,11 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "node_modules/fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1617,6 +1690,11 @@ "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", "dev": true }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/follow-redirects": { "version": "1.14.7", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", @@ -2004,6 +2082,11 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -2170,6 +2253,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -2310,6 +2404,11 @@ "node": ">= 0.6" } }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2348,6 +2447,28 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "node_modules/logform": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.2.tgz", + "integrity": "sha512-V6JiPThZzTsbVRspNO6TmHkR99oqYTs8fivMBYQkjZj6rxW92KxtDCPE6IkAk1DNBnYKNkjm4jYBm6JDUcyhOA==", + "dependencies": { + "colors": "1.4.0", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^1.1.0", + "triple-beam": "^1.3.0" + } + }, + "node_modules/logform/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/logform/node_modules/safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==" + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2545,6 +2666,14 @@ "wrappy": "1" } }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, "node_modules/opener": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", @@ -2792,6 +2921,19 @@ "node": ">=0.6" } }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -2894,6 +3036,14 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/safe-stable-stringify": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz", + "integrity": "sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -3004,6 +3154,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -3051,6 +3209,14 @@ "node": ">=0.10.0" } }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "engines": { + "node": "*" + } + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -3059,6 +3225,33 @@ "node": ">= 0.6" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -3182,6 +3375,11 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -3219,6 +3417,11 @@ "node": ">=0.8" } }, + "node_modules/triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, "node_modules/ts-postgres": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ts-postgres/-/ts-postgres-1.2.1.tgz", @@ -3351,6 +3554,11 @@ "punycode": "^2.1.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -3426,6 +3634,39 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/winston": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.5.1.tgz", + "integrity": "sha512-tbRtVy+vsSSCLcZq/8nXZaOie/S2tPXPFt4be/Q3vI/WtYwm7rrwidxVw2GRa38FIXcJ1kUM6MOZ9Jmnk3F3UA==", + "dependencies": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.3.2", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.2" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -3533,6 +3774,16 @@ } } }, + "@dabh/diagnostics": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", + "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -3821,6 +4072,11 @@ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, + "async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -3988,6 +4244,30 @@ "readdirp": "~3.6.0" } }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + }, + "dependencies": { + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + } + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4000,8 +4280,30 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-string": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" + }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } }, "combined-stream": { "version": "1.0.8", @@ -4160,6 +4462,11 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -4639,6 +4946,11 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fecha": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4695,6 +5007,11 @@ "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", "dev": true }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "follow-redirects": { "version": "1.14.7", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", @@ -4962,6 +5279,11 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -5068,6 +5390,11 @@ "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", "dev": true }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, "is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -5181,6 +5508,11 @@ "tsscmp": "1.0.6" } }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5213,6 +5545,30 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "logform": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.2.tgz", + "integrity": "sha512-V6JiPThZzTsbVRspNO6TmHkR99oqYTs8fivMBYQkjZj6rxW92KxtDCPE6IkAk1DNBnYKNkjm4jYBm6JDUcyhOA==", + "requires": { + "colors": "1.4.0", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^1.1.0", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==" + } + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -5353,6 +5709,14 @@ "wrappy": "1" } }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, "opener": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", @@ -5536,6 +5900,16 @@ } } }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -5612,6 +5986,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "safe-stable-stringify": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz", + "integrity": "sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -5700,6 +6079,14 @@ "object-inspect": "^1.9.0" } }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + } + }, "slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -5733,11 +6120,31 @@ "tweetnacl": "~0.14.0" } }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -5832,6 +6239,11 @@ } } }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -5860,6 +6272,11 @@ "punycode": "^2.1.1" } }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, "ts-postgres": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ts-postgres/-/ts-postgres-1.2.1.tgz", @@ -5958,6 +6375,11 @@ "punycode": "^2.1.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -6011,6 +6433,33 @@ "is-symbol": "^1.0.3" } }, + "winston": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.5.1.tgz", + "integrity": "sha512-tbRtVy+vsSSCLcZq/8nXZaOie/S2tPXPFt4be/Q3vI/WtYwm7rrwidxVw2GRa38FIXcJ1kUM6MOZ9Jmnk3F3UA==", + "requires": { + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.3.2", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.4.2" + } + }, + "winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "requires": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", diff --git a/package.json b/package.json index 66b41bf..43e4497 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "express": "^4.17.1", "forge-apis": "^0.8.6", "generic-pool": "^3.8.2", - "ts-postgres": "^1.2.1" + "ts-postgres": "^1.2.1", + "winston": "^3.5.1" }, "devDependencies": { "@types/dotenv": "^8.2.0", diff --git a/src/db.ts b/src/db.ts index de2386e..9693a63 100644 --- a/src/db.ts +++ b/src/db.ts @@ -42,9 +42,7 @@ const pool = createPool( const executeQuery = (query: Query) => { console.log("executing query"); - const res = pool.acquire(); - - return res + return pool.acquire() .then(async (client: Client) => { console.log("aquired client from pool"); const result = await client.execute(query); diff --git a/src/forge-download.ts b/src/forge-download.ts index 204a55a..7d9cf22 100644 --- a/src/forge-download.ts +++ b/src/forge-download.ts @@ -1,7 +1,7 @@ import * as ForgeSDK from "forge-apis"; - -const fs = require("fs").promises; +import * as fs from "fs"; import * as config from "./config"; +import { logger } from './logger'; const ObjectsApi = new ForgeSDK.ObjectsApi(); const ItemsApi = new ForgeSDK.ItemsApi(); @@ -16,24 +16,38 @@ const ItemsApi = new ForgeSDK.ItemsApi(); * @param {string} destination * @param {ForgeSDK.AuthClient} credentials */ -exports.download = async (projectID: string, itemID: string, fileName: string, destination: string, credentials: ForgeSDK.AuthToken) => { - const storageLocation = await getStorageLocation(projectID, itemID, credentials); +exports.download = async ( + projectID: string, + itemID: string, + fileName: string, + destination: string, + credentials: ForgeSDK.AuthToken +): Promise => { + const storageLocation: string = await getStorageLocation(projectID, itemID, credentials); - console.log("Downloading file " + fileName); + logger.info(`download: Downloading file "${fileName}" to ${destination}`); return ObjectsApi.getObject("wip.dm.prod", storageLocation, {}, config.authClient, credentials) .then((res: ForgeSDK.ApiResponse) => { - console.log("Downloaded file " + fileName + " to " + destination); - fs.writeFile(`${destination}/${fileName}`, res.body); + try { + fs.writeFileSync(`${destination}/${fileName}`, res.body); + logger.info(`download: Downloaded file ${fileName} to ${destination}`); + } catch (err) { + logger.error(`download: Error writing file "${fileName}"`, err); + } return itemID; }) .catch((err: ForgeSDK.ApiError) => { - console.log("error while processing " + storageLocation); - console.log(err); + logger.error(`download: Error downloading "${fileName}": ${err.statusCode}`, err); + throw new Error(err.statusMessage); }); }; -const getStorageLocation = (projectID: string, itemID: string, credentials: ForgeSDK.AuthToken) => { +const getStorageLocation = ( + projectID: string, + itemID: string, + credentials: ForgeSDK.AuthToken +): Promise => { return ItemsApi.getItem(projectID, itemID, config.authClient, credentials) .then((res: ForgeSDK.ApiResponse) => { let data = res.body.included[0]; @@ -41,6 +55,7 @@ const getStorageLocation = (projectID: string, itemID: string, credentials: Forg storageID = storageID.substring(storageID.indexOf("/") + 1); return storageID; }).catch((err: ForgeSDK.ApiError) => { - console.log("unable to get storage location for " + itemID + ": " + err.statusCode); + logger.error(`download: Unable to get storage location for ${itemID}: ${err.statusCode}`, err); + throw new Error(err.statusMessage); }); }; diff --git a/src/forge-upload.ts b/src/forge-upload.ts index 77f9771..eb972a1 100644 --- a/src/forge-upload.ts +++ b/src/forge-upload.ts @@ -1,5 +1,6 @@ import * as ForgeSDK from 'forge-apis'; import * as config from './config'; +import { logger } from './logger'; import * as fs from 'fs'; const jsonVersion: ForgeSDK.JsonApiVersionJsonapi = {version: "1.0"} @@ -138,8 +139,8 @@ function createItem(fileName: string, folderID: string, objectID: string, creden return true; }, (err: ForgeSDK.ApiError) => { - console.log("API ERROR CODE: ", err.statusCode, "\nMESSAGE: ", err.statusMessage, "\nBODY: ", err.statusBody); - return false; + logger.error(`upload: Error creating a new item: ${err.statusCode}`, err); + return false; } ); } @@ -171,12 +172,7 @@ function uploadFileObject(fileName: string, folderName: string, objectID: string {contentDisposition: fileName}, config.authClient, credentials).then( - (resp: ForgeSDK.ApiResponse) => { - if (resp.statusCode != 200) { - console.log("Upload File Error: ", resp.statusCode); - return false; - } - + (res: ForgeSDK.ApiResponse) => { return createItem(fileName, config.folderMap[folderName].fusionID, objectID, credentials); }, (err: ForgeSDK.ApiError) => { diff --git a/src/forge-webhooks.ts b/src/forge-webhooks.ts index c281e99..ec6006c 100644 --- a/src/forge-webhooks.ts +++ b/src/forge-webhooks.ts @@ -1,6 +1,7 @@ import * as axios from "axios"; import * as ForgeSDK from "forge-apis"; import * as config from "./config"; +import { logger } from "./logger"; /** * Kevin Pan | pan261@purdue.edu | Last Modified: 2/7/2022 @@ -22,7 +23,8 @@ const fileShareID = "urn:adsk.wipprod:fs.folder:co.T0n0mYQeS16K0lq1VuuYVQ"; * Function to manage hook lifecycle */ exports.setupHooks = (callbackUrl: string, credentials: ForgeSDK.AuthToken) => { - console.log("Checking hooks"); + logger.info('webhooks: Checking webhooks'); + axios.default({ method: "GET", url: "https://developer.api.autodesk.com/webhooks/v1/hooks", @@ -42,7 +44,7 @@ exports.setupHooks = (callbackUrl: string, credentials: ForgeSDK.AuthToken) => { } else { hookEvents.push(hook.event); if (hook.status === "inactive") { - console.log("reactivating " + hook.event + " hook"); + logger.info(`webhooks: Reactivating hook for ${hook.event}`); reactivateHook(hook.event, hook.hookId, credentials); } } @@ -62,7 +64,7 @@ exports.setupHooks = (callbackUrl: string, credentials: ForgeSDK.AuthToken) => { } }) .catch((err: axios.AxiosError) => { - console.log(err); + logger.error(`webhooks: Error getting webhooks: ${err.code}`, err.response); }); }; @@ -83,10 +85,10 @@ const createHook = (event: string, callbackUrl: string, credentials: ForgeSDK.Au }, }) .then((res: axios.AxiosResponse) => { - console.log("Sucessfully created hook for " + event); + logger.info(`webhooks: Successfully created hook for ${event}`, res.data); }) .catch((err: axios.AxiosError) => { - err.response && console.log("error creating hook for " + event + ": " + err.response.status); + err.response && logger.error(`webhooks: Error creating hook for ${event}: ${err.code}`, err.response); }); }; @@ -104,10 +106,10 @@ const reactivateHook = (event: string, hookID: string, credentials: ForgeSDK.Aut }, }) .then((res: axios.AxiosResponse) => { - console.log("successfully reactivated " + event + " hook"); + logger.info(`webhooks: Successfully reactivated ${event} hook`, res.data); }) .catch((err: axios.AxiosError) => { - err.response && console.log("error reactivating hook for " + event + ": " + err.response.status); + logger.error(`webhooks: Error reactivating hook for ${event}: ${err.code}`, err.response); }); }; @@ -120,17 +122,15 @@ const deleteHook = (event: string, hookID: string, credentials: ForgeSDK.AuthTok }, }) .then((res: axios.AxiosResponse) => { - console.log("deleted " + event + " hook with bad callback url"); + logger.info(`webhooks: Deleted ${event} hook with bad callback URL`, res.data); }) .catch((err: axios.AxiosError) => { - if (err.response) { - console.log("error deleting hook for " + event + ": " + err.response.status); - } + err.response && logger.error(`webhooks: Error deleteing hook for ${event}: ${err.code}`, err.response); }); }; exports.setupToken = (credentials: ForgeSDK.AuthToken) => { - console.log("Checking webhook token"); + logger.info('webhooks: Checking webhook token'); axios.default({ method: "POST", @@ -144,15 +144,15 @@ exports.setupToken = (credentials: ForgeSDK.AuthToken) => { }, }) .then((res: axios.AxiosResponse) => { - console.log(res.data.detail); + logger.info('webhooks: Added new webhook token', res.data) }) .catch((err: axios.AxiosError) => { if (err.response) { if (err.response.status == 400) { - console.log("Webhook token already exists, updating"); + logger.info('webhooks: Webhook token already exists, updating'); updateToken(credentials); } else { - console.log("Error creating a new webhook token"); + logger.error(`webhooks: Error creating webhook token: ${err.code}`, err.response); } } }); @@ -172,9 +172,9 @@ const updateToken = (credentials: ForgeSDK.AuthToken) => { }, }) .then((res: axios.AxiosResponse) => { - console.log("Successfully updated webhook token"); + logger.info('webhooks: Successfully updated webhook token', res.data); }) .catch((err: axios.AxiosError) => { - console.log("Error updating webhook token"); + logger.error(`webhooks: Error updating webhook token: ${err.code}`, err); }); }; diff --git a/src/localhook.ts b/src/localhook.ts index e9b7855..f9cd011 100644 --- a/src/localhook.ts +++ b/src/localhook.ts @@ -1,6 +1,7 @@ import * as chokidar from 'chokidar'; import { AuthToken } from 'forge-apis'; import * as uploader from './forge-upload'; +import { logger } from './logger'; const polltime: number = 100; @@ -54,8 +55,9 @@ function extractFolder(path: string): string[] { * Signal indexing complete, display tracked folders */ watcher.on('ready', () => { - console.log('\nIndexing complete\nPolling every ' + polltime + ' milliseconds\nWatching directories:'); - watcher.getWatched()['.'].forEach((element) => console.log(element + '/')); + let watched: string = ""; + watcher.getWatched()['.'].forEach((element) => watched += ` ${element}/\n`); + logger.info(`localhook: Indexing complete\n Polling every ${polltime} milliseconds\n Watching directories:\n${watched}`); }); /* Gavin Williams | will1742 | 01/19/22 @@ -65,16 +67,11 @@ watcher.on('ready', () => { watcher.on('add', (path: string) => { try { [folder, file] = extractFolder(path); - } catch (e) { - console.log("Invalid Path"); + } catch (err) { + logger.error(`localhook: Invalid path`, err); return; } - console.log(file + ' locally added to ' + folder); - console.log( - '\x1b[93mlocalhook.js::add:', - '\x1b[0mAttempting upload...' - ); - + logger.info(`localhook: ${file} locally added to ${folder}`); uploader.uploadFile(file, folder.toLowerCase(), credentials); }); @@ -85,11 +82,11 @@ watcher.on('add', (path: string) => { watcher.on('unlink', (path: string) => { try { [folder, file] = extractFolder(path); - } catch (e) { - console.log("Invalid Path"); + } catch (err) { + logger.error(`localhook: Invalid path`, err); return; } - console.log(file + ' has been removed from ' + folder); + logger.info(`localhook: ${file} has been removed from ${folder}`); }); /* Kevin Pan | pan261 | 01/30/22 @@ -99,15 +96,15 @@ watcher.on('unlink', (path: string) => { watcher.on('change', (path: string) => { try { [folder, file] = extractFolder(path); - } catch (e) { - console.log("Invalid Path"); + } catch (err) { + logger.error(`localhook: Invalid path`, err); return; } - console.log(file + ' has been modified in ' + folder) + logger.info(`localhook: ${file} has been modified in ${folder}`); }); // Error handling so errors don't crash the server watcher.on('error', (err: any) => { - console.log("Chokidar error:", err) + logger.error(`localhook: Chokidar error`, err); }) diff --git a/src/logger.ts b/src/logger.ts new file mode 100644 index 0000000..89d74ef --- /dev/null +++ b/src/logger.ts @@ -0,0 +1,49 @@ +import * as winston from 'winston'; + +const timezone = () => { + return new Date().toLocaleString('en-US', { + timeZone: 'America/New_York' + }); +} + +const consoleFormat = (info: winston.Logform.TransformableInfo) => { + return `${[info.timestamp]}: ${info.level}: ${info.message}`; +} + +const fileFormat = (info: winston.Logform.TransformableInfo) => { + let meta = info.metadata; + let timestamp = meta.timestamp + + if (Object.keys(meta).length === 1) { + return `${meta.timestamp}: ${info.level}: ${info.message}`; + } + + delete info.timestamp; + + return `${timestamp}: ${info.level}: ${info.message}\nData:` + JSON.stringify(info.metadata, null, '\t') + '\n'; +} + +export const logger = winston.createLogger({ + level: 'info', + transports: [ + new winston.transports.Console({ + level: 'info', + format: winston.format.combine( + winston.format.colorize({ all: true }), + winston.format.timestamp({format: timezone}), + winston.format.prettyPrint(), + winston.format.printf(info => consoleFormat(info)), + ) + }), + new winston.transports.File({ + level: 'info', + filename: `${__dirname}/logs/ffs.log`, + format: winston.format.combine( + winston.format.timestamp({format: timezone}), + winston.format.metadata(), + winston.format.prettyPrint(), + winston.format.printf(info => fileFormat(info)), + ) + }) + ] +}); \ No newline at end of file diff --git a/src/server.ts b/src/server.ts index 0788e38..ef109de 100644 --- a/src/server.ts +++ b/src/server.ts @@ -4,10 +4,10 @@ import * as axios from 'axios'; import * as crypto from "crypto"; import * as config from "./config"; import * as db from "./db"; +import { logger } from "./logger"; import * as ForgeSDK from "forge-apis"; import { Request, Response, ErrorRequestHandler } from "express"; -import { resolve } from "path/posix"; const webhooks = require("./forge-webhooks"); const downloader = require("./forge-download"); @@ -40,7 +40,7 @@ const verifySignature = ( buf: Buffer, encoding: crypto.Encoding ) => { - console.log("Verifying webhook callback signature"); + logger.info("server: Verifying webhook callback signature"); const signature = req.header("x-adsk-signature"); if (!signature) { return; @@ -72,15 +72,15 @@ const getWebhookCallbackURL = () => { let url: string = ""; data.forEach((entry: any) => { if (entry.name === "command_line (http)") { - url = entry.public_url + "/hook" - console.log("Webhook callback url is:", url); + url = entry.public_url + "/hook"; + logger.info(`server: Webhook callback URL is: ${url}`); } }); return url; }) .catch((err: axios.AxiosError) => { - console.log("ngrok server error:", err.code, err.message); + logger.error('server: ngrok server error:', err.response); }); } @@ -99,16 +99,13 @@ const createServer = () => { const PORT = config.port || 3000; if (config.forgeClientId == null || config.forgeClientSecret == null) { - console.error("Missing FORGE_CLIENT_ID or FORGE_CLIENT_SECRET env. variables."); + logger.error("Missing FORGE_CLIENT_ID or FORGE_CLIENT_SECRET env. variables"); return; } // Endpoint to begin authentication process app.get("/auth", function (req: Request, res: Response) { - console.log( - "\x1b[96mserver.js::createServer:", - "\x1b[0m/auth endpoint called" - ); + logger.info('server: /auth endpoint called'); res.redirect(config.authClient.generateAuthUrl("")); }); @@ -120,10 +117,7 @@ const createServer = () => { credentials = creds; refreshTime = creds.expires_in - 300; res.send("Generated token: " + credentials.access_token); - console.log( - "\x1b[92mserver.js::createServer:", - "\x1b[0m/callback reached, token generated" - ); + logger.info('server: /callback endpoint reached', creds); }) .then(async () => { // get webhook callback url from ngrok @@ -145,38 +139,20 @@ const createServer = () => { setTimeout(() => { credentials.access_token = ""; clearInterval(intervalID); - console.log( - "\x1b[93mserver.js::createServer:", - "\x1b[0mRefresh token expiring, need to authenticate again" - ); + logger.info('server: Refresh token expiring, need to authenticate again'); }, 13 * 24 * 3600 * 1000); // 13 days to ms }) .catch((err: ForgeSDK.ApiError) => { - console.error(err); + logger.error('server: Error getting token in /callback:', err); res.send(err); }); }); - // Endpoint for internal use, to get credentials from our auth server - app.get("/credentials", function (req: Request, res: Response) { - if (credentials.access_token !== "") { - console.log( - "\x1b[96mserver.js::createServer:", - "\x1b[0m/credentials endpoint called, credentials returned" - ); - res.send(credentials); - } else { - console.log( - "\x1b[93mserver.js::createServer:", - "\x1b[0m/credentials endpoint called, no credentials found" - ); - res.send("Need to authenticate at localhost:3000/auth"); - } - }); - app.post("/hook", async function (req: any, res: Response) { + logger.info('server: Webhook callback received'); + if (!req.signature_match) { - console.log("Request received from outside webhooks service"); + logger.warn('server: Request received from outside webhooks service', req); return res.status(403).send("Not called from webhooks service"); } @@ -184,13 +160,26 @@ const createServer = () => { let body: Request["body"] = req.body; + if (credentials && body.hook.event === "dm.version.added") { + logger.info(`server: "${body.payload.name}" has been added in ${config.folderIDtoLocal[body.payload.parentFolderUrn]}`, body); + } + + if (credentials && body.hook.event === "dm.version.modified") { + logger.info(`server: "${body.payload.name}" has been modified in ${config.folderIDtoLocal[body.payload.parentFolderUrn]}`, body); + } + + if (credentials && body.hook.event === "dm.version.deleted") { + logger.info(`server: "${body.payload.name}" has been deleted in ${config.folderIDtoLocal[body.payload.parentFolderUrn]}`, body); + } + if (credentials && body.hook.event === "dm.version.added") { const itemID = body.payload.lineageUrn; //TODO: check if extension is in the name const fileName = body.payload.name; const destination = __dirname + "/file_share" + config.folderIDtoLocal[body.payload.parentFolderUrn]; - await downloader.download(config.projectID, itemID, fileName, destination, credentials); - // await deleter.delete(config.projectID, itemID, fileName, credentials); + await downloader.download(config.projectID, itemID, fileName, destination, credentials).catch((err: Error) => { + console.log(err); + }); } }); @@ -213,7 +202,7 @@ const createServer = () => { app.use(errorHandler); const server = app.listen(PORT, () => { - console.log(`Server listening on port ${PORT}`); + logger.info(`Server listening on port ${PORT}`); }); return server; @@ -227,11 +216,7 @@ const refresh = () => { .refreshToken(credentials, config.scopes) .then(async (creds: ForgeSDK.AuthToken) => { credentials = creds; - console.log( - "\x1b[92mserver.js::refresh:", - "\x1b[0mnew token generated from refresh token:" - ); - console.log(credentials); + logger.info('server: Token refresed', creds); // check callback URL let webhookUrl = await getWebhookCallbackURL(); @@ -243,7 +228,7 @@ const refresh = () => { localhook.setCredentials(credentials); }) .catch((err: ForgeSDK.ApiError) => { - console.log(err); + logger.error('server: Error refreshing token:', err); }); };