diff --git a/default.env b/default.env index 2f2ccd1..cb7cf9f 100644 --- a/default.env +++ b/default.env @@ -1 +1,8 @@ -DATABASE_FILE=data/icebox.sqlite +DATABASE_FILE="data/icebox.sqlite" +OBJECT_SERVICE="" +OBJECT_EXPIRATION=3600 +OBJECT_BUCKET="" +OBJECT_ENDPOINT="" +OBJECT_REGION="" +OBJECT_ACCESS_KEY="" +OBJECT_ACCESS_SECRET="" \ No newline at end of file diff --git a/dist/file/index.d.ts b/dist/file/index.d.ts index 7f16c33..1fdd676 100644 --- a/dist/file/index.d.ts +++ b/dist/file/index.d.ts @@ -1,5 +1,7 @@ interface FileInfo { success: boolean; + filename?: string; + original?: string; hash?: string; size?: number; created?: number; @@ -8,4 +10,4 @@ interface FileInfo { export declare class File { static info(filePath: string): Promise; } -export {}; +export type { FileInfo }; diff --git a/dist/file/index.js b/dist/file/index.js index bbcd449..f1319a0 100644 --- a/dist/file/index.js +++ b/dist/file/index.js @@ -2,10 +2,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.File = void 0; const promises_1 = require("fs/promises"); +const path_1 = require("path"); const size_1 = require("../size"); const hash_1 = require("../hash"); class File { static async info(filePath) { + const original = (0, path_1.resolve)(filePath); + const filename = (0, path_1.basename)(filePath); let success = false; let hash; let fileSize; @@ -46,6 +49,8 @@ class File { success = true; return { success, + filename, + original, hash, size: fileSize, created @@ -53,4 +58,5 @@ class File { } } exports.File = File; +module.exports = { File }; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/file/index.js.map b/dist/file/index.js.map index 3d6e9fa..fbfd8c5 100644 --- a/dist/file/index.js.map +++ b/dist/file/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/file/index.ts"],"names":[],"mappings":";;;AAAA,0CAAmC;AAGnC,kCAA+B;AAC/B,kCAAiC;AAUjC,MAAa,IAAI;IACT,MAAM,CAAC,KAAK,CAAC,IAAI,CAAE,QAAiB;QAC1C,IAAI,OAAO,GAAa,KAAK,CAAC;QAC9B,IAAI,IAAa,CAAC;QAClB,IAAI,QAAiB,CAAC;QACtB,IAAI,OAAgB,CAAC;QACrB,IAAI,KAAa,CAAC;QAClB,IAAI,KAAa,CAAC;QAElB,IAAI,CAAC;YACJ,IAAI,GAAG,MAAM,aAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,KAAK,GAAG,GAAY,CAAC;YACrB,OAAO;gBACN,OAAO;gBACP,KAAK;aACL,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACJ,QAAQ,GAAG,MAAM,IAAA,WAAI,EAAC,QAAQ,CAAC,CAAA;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,KAAK,GAAG,GAAY,CAAC;YACrB,OAAO;gBACN,OAAO;gBACP,KAAK;aACL,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACJ,KAAK,GAAG,MAAM,IAAA,eAAI,EAAC,QAAQ,CAAC,CAAC;YAC7B,OAAO,GAAG,KAAK,CAAC,WAAW,CAAC;QAC7B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,KAAK,GAAG,GAAY,CAAC;YACrB,OAAO;gBACN,OAAO;gBACP,KAAK;aACL,CAAC;QACH,CAAC;QAED,OAAO,GAAG,IAAI,CAAC;QACf,OAAO;YACN,OAAO;YACP,IAAI;YACJ,IAAI,EAAG,QAAQ;YACf,OAAO;SACP,CAAC;IACH,CAAC;CACD;AAhDD,oBAgDC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/file/index.ts"],"names":[],"mappings":";;;AAAA,0CAAmC;AAEnC,+BAAyC;AAEzC,kCAA+B;AAC/B,kCAAiC;AAYjC,MAAa,IAAI;IACT,MAAM,CAAC,KAAK,CAAC,IAAI,CAAE,QAAiB;QAC1C,MAAM,QAAQ,GAAY,IAAA,cAAO,EAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAY,IAAA,eAAQ,EAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,OAAO,GAAa,KAAK,CAAC;QAC9B,IAAI,IAAa,CAAC;QAClB,IAAI,QAAiB,CAAC;QACtB,IAAI,OAAgB,CAAC;QACrB,IAAI,KAAa,CAAC;QAClB,IAAI,KAAa,CAAC;QAElB,IAAI,CAAC;YACJ,IAAI,GAAG,MAAM,aAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,KAAK,GAAG,GAAY,CAAC;YACrB,OAAO;gBACN,OAAO;gBACP,KAAK;aACL,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACJ,QAAQ,GAAG,MAAM,IAAA,WAAI,EAAC,QAAQ,CAAC,CAAA;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,KAAK,GAAG,GAAY,CAAC;YACrB,OAAO;gBACN,OAAO;gBACP,KAAK;aACL,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACJ,KAAK,GAAG,MAAM,IAAA,eAAI,EAAC,QAAQ,CAAC,CAAC;YAC7B,OAAO,GAAG,KAAK,CAAC,WAAW,CAAC;QAC7B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,KAAK,GAAG,GAAY,CAAC;YACrB,OAAO;gBACN,OAAO;gBACP,KAAK;aACL,CAAC;QACH,CAAC;QAED,OAAO,GAAG,IAAI,CAAC;QACf,OAAO;YACN,OAAO;YACP,QAAQ;YACR,QAAQ;YACR,IAAI;YACJ,IAAI,EAAG,QAAQ;YACf,OAAO;SACP,CAAC;IACH,CAAC;CACD;AApDD,oBAoDC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,CAAC"} \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts index cb0ff5c..0b172b7 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1 +1 @@ -export {}; +import 'dotenv/config'; diff --git a/dist/index.js b/dist/index.js index 0e5fe6f..3629b43 100644 --- a/dist/index.js +++ b/dist/index.js @@ -36,6 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +require("dotenv/config"); const express_1 = __importDefault(require("express")); const handlebars = __importStar(require("express-handlebars")); const body_parser_1 = __importDefault(require("body-parser")); @@ -61,7 +62,7 @@ app.get('/', (req, res, next) => { const data = {}; return res.render('home', data); }); -app.post('/lookup', (req, res, next) => { +app.post('/lookup', async (req, res, next) => { const data = { alert: { class: 'primary', @@ -69,10 +70,43 @@ app.post('/lookup', (req, res, next) => { } }; if (typeof req.body !== 'undefined') { - console.dir(req.body); + if (typeof req.body['first-name'] !== 'undefined' && req.body['first-name'] !== '') { + //bot trap + log.warn(`Potential bot trapped: ${JSON.stringify(req.body)}`); + } + else if (typeof req.body.email !== 'undefined' && req.body.email.trim() !== '') { + } } return res.render('home', data); }); +app.get('/file/:id', async (req, res, next) => { + const data = {}; + data.file = { + filename: 'Test.mov' + }; + if (false) { + data.alert = { + class: 'warning', + message: `This download link expired on` + }; + } + if (false) { + data.alert = { + class: 'danger', + message: `No download link was found with this ID` + }; + return res.render('home', data); + } + return res.render('file', data); +}); +app.get('/example.txt', (req, res, next) => { + return res.send('Test'); +}); +app.post('/file/:id/download', async (req, res, next) => { + const data = {}; + const url = `http://localhost:${PORT}/example.txt`; + return res.redirect(307, url); +}); /* import http from 'http'; import path from 'path'; diff --git a/dist/index.js.map b/dist/index.js.map index ec5ce10..a26542a 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,sDAA8B;AAC9B,+DAAiD;AAEjD,8DAAqC;AACrC,+BAA4B;AAG5B,+BAA+B;AAC/B,+BAAkC;AAElC,MAAM,IAAI,GAAY,IAAA,YAAM,EAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAC3C,MAAM,SAAS,GAAY,IAAA,WAAI,EAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AACvD,MAAM,UAAU,GAAY,IAAA,WAAI,EAAC,SAAS,EAAE,WAAW,CAAC,CAAC;AAEzD,MAAM,GAAG,GAAa,IAAA,iBAAO,GAAE,CAAC;AAChC,MAAM,GAAG,GAAY,IAAA,eAAS,EAAC,QAAQ,CAAC,CAAC;AACzC,MAAM,GAAG,GAAmC,UAAU,CAAC,MAAM,CAAC;IAC1D,aAAa,EAAE,MAAM;IACrB,UAAU,EAAE,IAAA,WAAI,EAAC,SAAS,EAAE,WAAW,CAAC;IACxC,WAAW,EAAE,IAAA,WAAI,EAAC,SAAS,EAAE,WAAW,CAAC;CAC5C,CAAC,CAAC;AAEH,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AACpC,GAAG,CAAC,GAAG,CAAC,qBAAU,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACnD,GAAG,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;AACrC,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;AACrC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AAE5B,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAa,EAAE,GAAc,EAAE,IAAmB,EAAE,EAAE;IAChE,MAAM,IAAI,GAAS,EAAE,CAAC;IACtB,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACpC,CAAC,CAAC,CAAC;AAEH,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,GAAa,EAAE,GAAc,EAAE,IAAmB,EAAE,EAAE;IACvE,MAAM,IAAI,GAAS;QACf,KAAK,EAAG;YACJ,KAAK,EAAE,SAAS;YAChB,OAAO,EAAG,+FAA+F;SAC5G;KACJ,CAAC;IACF,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACpC,CAAC,CAAC,CAAA;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgQE;AAEF,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IAClB,GAAG,CAAC,IAAI,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/monitor/index.js b/dist/monitor/index.js index d248326..b8253cf 100644 --- a/dist/monitor/index.js +++ b/dist/monitor/index.js @@ -1,34 +1,107 @@ "use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); Object.defineProperty(exports, "__esModule", { value: true }); require("dotenv/config"); const upload_1 = require("../upload"); const log_1 = require("../log"); -const chokidar_1 = __importDefault(require("chokidar")); -const EXPIRATION = 3600; //1 hour +const file_1 = require("../file"); +const env_1 = require("../env"); +const cli_progress_1 = require("cli-progress"); +const colors = __importStar(require("ansi-colors")); const log = (0, log_1.createLog)('files'); -async function processUpload(filePath) { +function createConfig() { + const ENDPOINT = (0, env_1.envString)('OBJECT_ENDPOINT', ''); + const ACCESS_KEY = (0, env_1.envString)('OBJECT_ACCESS_KEY', ''); + const ACCESS_SECRET = (0, env_1.envString)('OBJECT_ACCESS_SECRET', ''); const config = { - region: 'us-east-1', - bucketName: 'your-bucket-name', - expirationSeconds: EXPIRATION + region: (0, env_1.envString)('OBJECT_REGION', 'us-east-1'), + bucketName: (0, env_1.envString)('OBJECT_BUCKET', 'icebox'), + expirationSeconds: (0, env_1.envInt)('OBJECT_EXPIRATION', 3600) //1 hour }; + if (ENDPOINT !== '') { + config.endpoint = ENDPOINT; + config.forcePathStyle = true; + } + if (ACCESS_KEY !== '' && ACCESS_SECRET !== '') { + config.credentials = { + accessKeyId: ACCESS_KEY, + secretAccessKey: ACCESS_SECRET + }; + } + return config; +} +async function process(filePath) { + const fileInfo = await file_1.File.info(filePath); + const config = createConfig(); + const progress = new cli_progress_1.SingleBar({ + format: `Printing [${fileInfo.filename}] | ${colors.cyan('{bar}')} | {percentage}% || ETA: {time}`, + barCompleteChar: '\u2588', + barIncompleteChar: '\u2591', + hideCursor: true + }); + if (!fileInfo.success) { + log.error(`Error processing file info`, fileInfo.error); + return; + } + console.dir(fileInfo); log.info(`Started upload: ${filePath}`); - const result = await (0, upload_1.upload)('test', filePath, config); + progress.start(100, 0, { + time: 'N/A' + }); + const result = await (0, upload_1.upload)('test', filePath, config, (progressInfo) => { + progress.update(Math.floor((progressInfo.loaded / progressInfo.total) * 100.0), { time: 'N/A' }); + }); if (result.success) { - log.info('File ${filePath} uploaded successfully!'); - log.info('Private URL:', result.url); + progress.update(100, { + time: 'Done' + }); + } + progress.stop(); + if (result.success) { + log.info(`File ${filePath} uploaded successfully`); + log.info(`Private URL: ${result.url}`); } else { log.error('Upload failed:', result.error); } } async function main() { - chokidar_1.default.watch('./watch', { ignored: /(^|[/\\])\../ }).on('all', (event, path) => { + /*chokidar.watch('./watch', { ignored: /(^|[/\\])\../ }).on('all', (event : any, path : string) => { log.info(`File ${path} changed with event type ${event}`); - }); + });*/ + process('/Users/matthewmcwilliams9/Desktop/m1554 hd optical printer test.mov'); } main().catch(log.error); /* diff --git a/dist/monitor/index.js.map b/dist/monitor/index.js.map index 59695fd..633acec 100644 --- a/dist/monitor/index.js.map +++ b/dist/monitor/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/monitor/index.ts"],"names":[],"mappings":";;;;;AAAA,yBAAuB;AAEvB,sCAAmC;AACnC,gCAAmC;AAEnC,wDAAgC;AAIhC,MAAM,UAAU,GAAY,IAAI,CAAC,CAAC,QAAQ;AAE1C,MAAM,GAAG,GAAY,IAAA,eAAS,EAAC,OAAO,CAAC,CAAC;AAExC,KAAK,UAAU,aAAa,CAAE,QAAiB;IAC9C,MAAM,MAAM,GAAc;QACzB,MAAM,EAAE,WAAW;QACnB,UAAU,EAAE,kBAAkB;QAC9B,iBAAiB,EAAE,UAAU;KAC7B,CAAC;IAEF,GAAG,CAAC,IAAI,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;IACxC,MAAM,MAAM,GAAkB,MAAM,IAAA,eAAM,EAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAErE,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,GAAG,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;QACpD,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QACP,GAAG,CAAC,KAAK,CAAC,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;AACF,CAAC;AAED,KAAK,UAAU,IAAI;IAClB,kBAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAW,EAAE,IAAa,EAAE,EAAE;QAC/F,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,4BAA4B,KAAK,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsCE"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/monitor/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/upload/index.d.ts b/dist/upload/index.d.ts index cbdd648..eb18ecc 100644 --- a/dist/upload/index.d.ts +++ b/dist/upload/index.d.ts @@ -21,5 +21,5 @@ interface UploadResult { * @param config - S3 configuration parameters * @returns Promise containing the result with URL if successful */ -export declare function upload(id: string, filePath: string, config: S3Config): Promise; +export declare function upload(id: string, filePath: string, config: S3Config, progressCb?: Function | null): Promise; export type { UploadResult, S3Config }; diff --git a/dist/upload/index.js b/dist/upload/index.js index 82a8ca7..0e9c3dc 100644 --- a/dist/upload/index.js +++ b/dist/upload/index.js @@ -5,17 +5,18 @@ const client_s3_1 = require("@aws-sdk/client-s3"); const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner"); const fs_1 = require("fs"); const path_1 = require("path"); +const lib_storage_1 = require("@aws-sdk/lib-storage"); /** * Uploads a file to S3 and returns a private, time-limited URL to access it * @param filePath - Absolute or relative path to the file to upload * @param config - S3 configuration parameters * @returns Promise containing the result with URL if successful */ -async function upload(id, filePath, config) { +async function upload(id, filePath, config, progressCb = null) { const fullPath = (0, path_1.resolve)(filePath); const fileName = (0, path_1.basename)(filePath); const extName = (0, path_1.extname)(filePath); - const key = `${id}${extName}`; + const key = `${id}/${fileName}`; if (!key) { return { success: false, @@ -28,13 +29,15 @@ async function upload(id, filePath, config) { } catch (err) { const error = err; + console.error(error); return { success: false, error: `Error reading file: ${error.message}` }; } const s3ClientOptions = { - region: config.region + region: config.region //, + //requestHandler: new XhrHttpHandler({}) }; if (config.endpoint) { s3ClientOptions.endpoint = config.endpoint; @@ -47,12 +50,23 @@ async function upload(id, filePath, config) { } const s3Client = new client_s3_1.S3Client(s3ClientOptions); try { - const uploadCommand = new client_s3_1.PutObjectCommand({ - Bucket: config.bucketName, - Key: key, - Body: fileStream + const upload = new lib_storage_1.Upload({ + client: s3Client, + params: { + Bucket: config.bucketName, + Key: key, + Body: fileStream + } }); - await s3Client.send(uploadCommand); + upload.on('httpUploadProgress', (progress) => { + if (progressCb !== null) { + progressCb(progress); + } + else { + console.log(`${progress.loaded}/${progress.total} [${Math.round((progress.loaded / progress.total) * 100.0)}%]`); + } + }); + await upload.done(); const getCommand = new client_s3_1.GetObjectCommand({ Bucket: config.bucketName, Key: key @@ -68,6 +82,7 @@ async function upload(id, filePath, config) { } catch (err) { const error = err; + console.error(error); return { success: false, error: `Error uploading to S3: ${error.message}` diff --git a/dist/upload/index.js.map b/dist/upload/index.js.map index 5f0aee7..1237613 100644 --- a/dist/upload/index.js.map +++ b/dist/upload/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/upload/index.ts"],"names":[],"mappings":";;AA+BA,wBAyEC;AAxGD,kDAAkF;AAClF,wEAA6D;AAC7D,2BAAkD;AAClD,+BAAkD;AAsBlD;;;;;GAKG;AACI,KAAK,UAAU,MAAM,CAAE,EAAU,EAAE,QAAgB,EAAE,MAAgB;IACxE,MAAM,QAAQ,GAAY,IAAA,cAAO,EAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAY,IAAA,eAAQ,EAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAa,IAAA,cAAO,EAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAW,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IAEtC,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,OAAO;YACH,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,sBAAsB;SAChC,CAAC;IACN,CAAC;IAED,IAAI,UAAuB,CAAC;IAE5B,IAAI,CAAC;QACD,UAAU,GAAG,IAAA,qBAAgB,EAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,MAAM,KAAK,GAAU,GAAY,CAAC;QAClC,OAAO;YACH,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,uBAAuB,KAAK,CAAC,OAAO,EAAE;SAChD,CAAC;IACN,CAAC;IAED,MAAM,eAAe,GAAwB;QACzC,MAAM,EAAE,MAAM,CAAC,MAAM;KACxB,CAAC;IAEF,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QAClB,eAAe,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IAC/C,CAAC;IAED,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACrB,eAAe,CAAC,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;IACrD,CAAC;IAED,IAAI,MAAM,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;QACtC,eAAe,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;IAC3D,CAAC;IAED,MAAM,QAAQ,GAAa,IAAI,oBAAQ,CAAC,eAAe,CAAC,CAAC;IAEzD,IAAI,CAAC;QACD,MAAM,aAAa,GAAqB,IAAI,4BAAgB,CAAC;YACzD,MAAM,EAAE,MAAM,CAAC,UAAU;YACzB,GAAG,EAAE,GAAG;YACR,IAAI,EAAE,UAAU;SACnB,CAAC,CAAC;QAEH,MAAM,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAEnC,MAAM,UAAU,GAAqB,IAAI,4BAAgB,CAAC;YACtD,MAAM,EAAE,MAAM,CAAC,UAAU;YACzB,GAAG,EAAE,GAAG;SACX,CAAC,CAAC;QAEH,MAAM,GAAG,GAAY,MAAM,IAAA,mCAAY,EAAC,QAAQ,EAAE,UAAU,EAAE;YAC1D,SAAS,EAAE,MAAM,CAAC,iBAAiB;SACtC,CAAC,CAAC;QAEH,OAAO;YACH,OAAO,EAAE,IAAI;YACb,GAAG;YACH,GAAG;SACN,CAAC;IACN,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,MAAM,KAAK,GAAW,GAAY,CAAC;QACnC,OAAO;YACH,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,0BAA0B,KAAK,CAAC,OAAO,EAAE;SACnD,CAAC;IACN,CAAC;AACL,CAAC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,MAAM,EAAE,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/upload/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 30bfdc5..97b613e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,10 +10,14 @@ "license": "MIT", "dependencies": { "@aws-sdk/client-s3": "^3.777.0", + "@aws-sdk/lib-storage": "^3.779.0", "@aws-sdk/s3-request-presigner": "^3.777.0", + "@aws-sdk/xhr-http-handler": "^3.775.0", + "ansi-colors": "^4.1.3", "bcrypt": "^5.1.1", "body-parser": "^2.2.0", "chokidar": "^4.0.3", + "cli-progress": "^3.12.0", "dotenv": "^16.4.7", "express": "^4.18.2", "express-handlebars": "^8.0.1", @@ -28,6 +32,7 @@ "winston": "^3.17.0" }, "devDependencies": { + "@types/cli-progress": "^3.11.6", "@types/express": "^4.17.17", "@types/node": "^20.5.1", "typescript": "^5.1.6" @@ -236,9 +241,9 @@ } }, "node_modules/@aws-sdk/client-s3": { - "version": "3.777.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.777.0.tgz", - "integrity": "sha512-KVX2QD6lLczZxtzIRCpmztgNnGq+spiMIDYqkum/rCBjCX1YJoDHwMYXaMf2EtAH8tFkJmBiA/CiT/J36iN7Xg==", + "version": "3.779.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.779.0.tgz", + "integrity": "sha512-Lagz+ersQaLNYkpOU9V12PYspT//lGvhPXlKU3OXDj3whDchdqUdtRKY8rmV+jli4KXe+udx/hj2yqrFRfKGvQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", @@ -510,6 +515,37 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/lib-storage": { + "version": "3.779.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.779.0.tgz", + "integrity": "sha512-AZfykrCgfnhlb5d5uyThHsqIwt41PYgnUTMyDuk4hbuKbiY8pfOiPdg8BYsC59iD2T4Iw9NujYhWUD+l8zNKcw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.0.2", + "@smithy/middleware-endpoint": "^4.1.0", + "@smithy/smithy-client": "^4.2.0", + "buffer": "5.6.0", + "events": "3.3.0", + "stream-browserify": "3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "^3.779.0" + } + }, + "node_modules/@aws-sdk/lib-storage/node_modules/buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, "node_modules/@aws-sdk/middleware-bucket-endpoint": { "version": "3.775.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.775.0.tgz", @@ -904,6 +940,20 @@ } } }, + "node_modules/@aws-sdk/xhr-http-handler": { + "version": "3.775.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xhr-http-handler/-/xhr-http-handler-3.775.0.tgz", + "integrity": "sha512-oTu16c9G2IRXnY97DubmTLNPlFxATtADa4siRW+AmGbnl1WQ/qquQBNEWgqvZN2WECR/8sT/w2HWDZ/s+4Io6w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.775.0", + "@smithy/protocol-http": "^5.1.0", + "@smithy/querystring-builder": "^4.0.2", + "@smithy/types": "^4.2.0", + "events": "3.3.0", + "tslib": "^2.6.2" + } + }, "node_modules/@aws-sdk/xml-builder": { "version": "3.775.0", "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.775.0.tgz", @@ -1814,6 +1864,16 @@ "@types/node": "*" } }, + "node_modules/@types/cli-progress": { + "version": "3.11.6", + "resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.6.tgz", + "integrity": "sha512-cE3+jb9WRlu+uOSAugewNpITJDt1VF8dHOopPO4IABFc3SXYL5WE/+PTz/FCdZRRfIujiWW3n3aMbv1eIGVRWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", @@ -2006,6 +2066,15 @@ "node": ">=8" } }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2385,6 +2454,18 @@ "node": ">=6" } }, + "node_modules/cli-progress": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", + "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", + "license": "MIT", + "dependencies": { + "string-width": "^4.2.3" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", @@ -2818,6 +2899,15 @@ "node": ">= 0.6" } }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -5042,6 +5132,16 @@ "node": ">= 0.8" } }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", diff --git a/package.json b/package.json index ee6fef1..076b355 100644 --- a/package.json +++ b/package.json @@ -19,10 +19,14 @@ "license": "MIT", "dependencies": { "@aws-sdk/client-s3": "^3.777.0", + "@aws-sdk/lib-storage": "^3.779.0", "@aws-sdk/s3-request-presigner": "^3.777.0", + "@aws-sdk/xhr-http-handler": "^3.775.0", + "ansi-colors": "^4.1.3", "bcrypt": "^5.1.1", "body-parser": "^2.2.0", "chokidar": "^4.0.3", + "cli-progress": "^3.12.0", "dotenv": "^16.4.7", "express": "^4.18.2", "express-handlebars": "^8.0.1", @@ -37,6 +41,7 @@ "winston": "^3.17.0" }, "devDependencies": { + "@types/cli-progress": "^3.11.6", "@types/express": "^4.17.17", "@types/node": "^20.5.1", "typescript": "^5.1.6" diff --git a/scripts/db.sh b/scripts/db.sh index e1e5eb7..9241d8b 100644 --- a/scripts/db.sh +++ b/scripts/db.sh @@ -2,9 +2,10 @@ source .env -if [[ ! -f ${DATABASE_FILE} ]]; then +if [[ -z "${DATABASE_FILE}" ]]; then echo "Please define DATABASE_FILE in the .env file" exit 1 fi -cat sql/setup.sql | sqlite3 ${DATABASE_FILE} \ No newline at end of file +mkdir -p $(dirname "${DATABASE_FILE}") +cat sql/setup.sql | sqlite3 "${DATABASE_FILE}" \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index e2a118a..ddc72de 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ +import 'dotenv/config'; import express from 'express'; import * as handlebars from 'express-handlebars'; @@ -60,7 +61,7 @@ app.get('/file/:id', async (req : Request, res : Response, next : NextFunction) if ( false ) { data.alert = { class : 'warning', - message : `This download link expired ` + message : `This download link expired on` } } diff --git a/src/monitor/index.ts b/src/monitor/index.ts index e27b814..04360f3 100644 --- a/src/monitor/index.ts +++ b/src/monitor/index.ts @@ -3,45 +3,87 @@ import 'dotenv/config'; import { upload } from '../upload'; import { createLog } from '../log'; import { File } from '../file'; +import { envString, envInt } from '../env'; import chokidar from 'chokidar'; import type { Logger } from 'winston'; import type { UploadResult, S3Config } from '../upload'; import type { FileInfo } from '../file'; +import { SingleBar } from 'cli-progress'; +import * as colors from 'ansi-colors'; -const EXPIRATION : number = 3600; //1 hour const log : Logger = createLog('files'); +function createConfig () : S3Config { + const ENDPOINT : string = envString('OBJECT_ENDPOINT', ''); + const ACCESS_KEY : string = envString('OBJECT_ACCESS_KEY', ''); + const ACCESS_SECRET : string = envString('OBJECT_ACCESS_SECRET', ''); + const config : S3Config = { + region: envString('OBJECT_REGION', 'us-east-1'), + bucketName: envString('OBJECT_BUCKET', 'icebox'), + expirationSeconds: envInt('OBJECT_EXPIRATION', 3600) //1 hour + }; + + if (ENDPOINT !== '') { + config.endpoint = ENDPOINT; + config.forcePathStyle = true; + } + + if (ACCESS_KEY !== '' && ACCESS_SECRET !== '') { + config.credentials = { + accessKeyId : ACCESS_KEY, + secretAccessKey : ACCESS_SECRET + }; + } + return config; +} + async function process (filePath : string) { - const config : S3Config = { - region: 'us-east-1', - bucketName: 'your-bucket-name', - expirationSeconds: EXPIRATION - }; - const fileInfo : FileInfo = await File.info(filePath); - + const config : S3Config = createConfig(); + const progress : SingleBar = new SingleBar({ + format: `Printing [${fileInfo.filename}] | ${colors.cyan('{bar}')} | {percentage}% || ETA: {time}`, + barCompleteChar: '\u2588', + barIncompleteChar: '\u2591', + hideCursor: true + }); if (!fileInfo.success) { log.error(`Error processing file info`, fileInfo.error); return; } + console.dir(fileInfo); + log.info(`Started upload: ${filePath}`); - const result : UploadResult = await upload('test', filePath, config); + progress.start(100, 0, { + time : 'N/A' + }); + const result : UploadResult = await upload('test', filePath, config, (progressInfo : any) => { + progress.update(Math.floor((progressInfo.loaded / progressInfo.total) * 100.0), { time : 'N/A'}); + }); + + if (result.success) { + progress.update(100, { + time : 'Done' + }); + } + + progress.stop(); if (result.success) { - log.info('File ${filePath} uploaded successfully!'); - log.info('Private URL:', result.url); + log.info(`File ${filePath} uploaded successfully`); + log.info(`Private URL: ${result.url}`); } else { log.error('Upload failed:', result.error); } } async function main() { - chokidar.watch('./watch', { ignored: /(^|[/\\])\../ }).on('all', (event : any, path : string) => { + /*chokidar.watch('./watch', { ignored: /(^|[/\\])\../ }).on('all', (event : any, path : string) => { log.info(`File ${path} changed with event type ${event}`); - }); + });*/ + process('/Users/matthewmcwilliams9/Desktop/m1554 hd optical printer test.mov'); } main().catch(log.error); diff --git a/src/upload/index.ts b/src/upload/index.ts index cc1f394..6d75709 100644 --- a/src/upload/index.ts +++ b/src/upload/index.ts @@ -2,6 +2,8 @@ import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3 import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; import { ReadStream, createReadStream } from 'fs'; import { resolve, basename, extname } from 'path'; +import { XhrHttpHandler } from '@aws-sdk/xhr-http-handler'; +import { Upload } from '@aws-sdk/lib-storage'; // S3 configuration interface interface S3Config { @@ -29,11 +31,11 @@ interface UploadResult { * @param config - S3 configuration parameters * @returns Promise containing the result with URL if successful */ -export async function upload (id: string, filePath: string, config: S3Config): Promise { +export async function upload (id: string, filePath: string, config: S3Config, progressCb : Function | null = null): Promise { const fullPath : string = resolve(filePath); const fileName : string = basename(filePath); const extName : string = extname(filePath); - const key: string = `${id}${extName}`; + const key: string = `${id}/${fileName}`; if (!key) { return { @@ -48,6 +50,7 @@ export async function upload (id: string, filePath: string, config: S3Config): P fileStream = createReadStream(fullPath); } catch (err) { const error: Error = err as Error; + console.error(error); return { success: false, error: `Error reading file: ${error.message}` @@ -55,7 +58,8 @@ export async function upload (id: string, filePath: string, config: S3Config): P } const s3ClientOptions: Record = { - region: config.region + region: config.region//, + //requestHandler: new XhrHttpHandler({}) }; if (config.endpoint) { @@ -73,13 +77,24 @@ export async function upload (id: string, filePath: string, config: S3Config): P const s3Client: S3Client = new S3Client(s3ClientOptions); try { - const uploadCommand: PutObjectCommand = new PutObjectCommand({ - Bucket: config.bucketName, - Key: key, - Body: fileStream + const upload : Upload = new Upload({ + client : s3Client, + params: { + Bucket : config.bucketName, + Key : key, + Body: fileStream + } }); - - await s3Client.send(uploadCommand); + + upload.on('httpUploadProgress', (progress : any) => { + if (progressCb !== null) { + progressCb(progress); + } else { + console.log(`${progress.loaded}/${progress.total} [${Math.round((progress.loaded / progress.total) * 100.0)}%]`); + } + }); + + await upload.done(); const getCommand: GetObjectCommand = new GetObjectCommand({ Bucket: config.bucketName, @@ -97,6 +112,7 @@ export async function upload (id: string, filePath: string, config: S3Config): P }; } catch (err) { const error : Error = err as Error; + console.error(error); return { success: false, error: `Error uploading to S3: ${error.message}`