├── .gitignore ├── README.md ├── annotations.txt ├── preclass ├── backend │ ├── .gitignore │ ├── README.md │ ├── demo.gif │ ├── package-lock.json │ ├── package.json │ └── src │ │ ├── index.js │ │ ├── routes.js │ │ ├── uploadHandler.js │ │ └── util.js └── frontend │ ├── package-lock.json │ ├── package.json │ └── public │ ├── app.js │ ├── deps │ ├── bootstrap.min.css │ └── socket.io.min.js │ └── index.html └── recorded ├── .vscode └── settings.json ├── parte01 ├── backend │ ├── package-lock.json │ ├── package.json │ └── src │ │ ├── index.js │ │ └── routes.js └── frontend │ ├── package-lock.json │ ├── package.json │ └── public │ ├── app.js │ └── index.html └── parte02 ├── backend ├── package-lock.json ├── package.json └── src │ ├── index.js │ ├── routes.js │ ├── uploadHandler.js │ └── util.js └── frontend ├── package-lock.json ├── package.json └── public ├── app.js └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | *.mp4 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # Snowpack dependency directory (https://snowpack.dev/) 45 | web_modules/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | .parcel-cache 78 | 79 | # Next.js build output 80 | .next 81 | out 82 | 83 | # Nuxt.js build / generate output 84 | .nuxt 85 | dist 86 | 87 | # Gatsby files 88 | .cache/ 89 | # Comment in the public line in if your project uses Gatsby and not Next.js 90 | # https://nextjs.org/blog/next-9-1#public-directory-support 91 | # public 92 | 93 | # vuepress build output 94 | .vuepress/dist 95 | 96 | # Serverless directories 97 | .serverless/ 98 | 99 | # FuseBox cache 100 | .fusebox/ 101 | 102 | # DynamoDB Local files 103 | .dynamodb/ 104 | 105 | # TernJS port file 106 | .tern-port 107 | 108 | # Stores VSCode versions used for testing VSCode extensions 109 | .vscode-test 110 | 111 | # yarn v2 112 | .yarn/cache 113 | .yarn/unplugged 114 | .yarn/build-state.yml 115 | .yarn/install-state.gz 116 | .pnp.* 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # How to upload Gigabytes of files concurrently in using Node.js, Busboy and WebSocket 2 | 3 | This is the source code of my [Youtube video](https://youtu.be/QRhoGbnEs78) in Portuguese, look in to [./recorded](./recorded) to see all examples for both two classes 4 | 5 | ## Author 6 | - [Erick Wendel](https://twitter.com/erickwendel_) 7 | -------------------------------------------------------------------------------- /annotations.txt: -------------------------------------------------------------------------------- 1 | https://bytearcher.com/articles/formidable-vs-busboy-vs-multer-vs-multiparty/#:~:text=Busboy%20is%20an%20event%2Dbased,that's%20not%20tied%20to%20Express.&text=Multer%20is%20an%20Express.,hard%20disk%20and%20populates%20req. 2 | 3 | 4 | 5 | aula01 6 | Sobre o projeto 7 | mkdir frontend 8 | npm init -y 9 | npm i http-server 10 | package.json 11 | start 12 | mkdir public 13 | touch index.html 14 | show get bootstrap 15 | add html without socket.io 16 | 17 | touch app.js 18 | showSize 19 | updateStatus 20 | formatBytes 21 | mkdir backend 22 | npm init -y 23 | npm i -D nodemon 24 | package.json 25 | start 26 | mkdir src 27 | touch index.js 28 | all server 29 | setTimeout -> 30 | io.emit(FILE_EVENT_NAME, size) 31 | 32 | socket.io cdn 33 | https://cdnjs.com/libraries/socket.io/3.0.4 34 | 35 | frontend 36 | app.js 37 | ioClient 38 | 39 | backend 40 | routes.js 41 | post 42 | onFinish and origin 43 | res.end() 44 | frontend 45 | configureForm 46 | click in upload 47 | backend 48 | routes.js 49 | options 50 | click in upload 51 | frontend 52 | showMessage 53 | 54 | aula02 55 | cp aula01 56 | npm start 57 | npm i pino@6 pino@4 58 | backend 59 | util.js 60 | logger 61 | change logs from index.js 62 | 63 | npm i busboy 64 | 65 | UploadHandler 66 | registerEvents 67 | #onFile 68 | till logger.info 69 | backend 70 | routes 71 | const uploadHandler = new UploadHandler(this.#io, socketId) 72 | all 73 | uploadFIle 74 | backend 75 | util 76 | promisify 77 | routes 78 | add promisify 79 | uploadHandler 80 | #handleFileBytes 81 | change #onFile 82 | uploadFIle 83 | open two different tabs 84 | uploadFIle 85 | 86 | -------------------------------------------------------------------------------- /preclass/backend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # Snowpack dependency directory (https://snowpack.dev/) 45 | web_modules/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | .parcel-cache 78 | 79 | # Next.js build output 80 | .next 81 | out 82 | 83 | # Nuxt.js build / generate output 84 | .nuxt 85 | dist 86 | 87 | # Gatsby files 88 | .cache/ 89 | # Comment in the public line in if your project uses Gatsby and not Next.js 90 | # https://nextjs.org/blog/next-9-1#public-directory-support 91 | # public 92 | 93 | # vuepress build output 94 | .vuepress/dist 95 | 96 | # Serverless directories 97 | .serverless/ 98 | 99 | # FuseBox cache 100 | .fusebox/ 101 | 102 | # DynamoDB Local files 103 | .dynamodb/ 104 | 105 | # TernJS port file 106 | .tern-port 107 | 108 | # Stores VSCode versions used for testing VSCode extensions 109 | .vscode-test 110 | 111 | # yarn v2 112 | .yarn/cache 113 | .yarn/unplugged 114 | .yarn/build-state.yml 115 | .yarn/install-state.gz 116 | .pnp.* 117 | -------------------------------------------------------------------------------- /preclass/backend/README.md: -------------------------------------------------------------------------------- 1 | # Busboy + Socket Upload Status 2 | 3 | This project was built to show how to upload files using Busboy and then emit status events throught channels on Socket.io 4 | 5 | ## Demo 6 | 7 | ![](./demo.gif) 8 | 9 | ## Running 10 | 11 | - `npm install` 12 | - `npm start` 13 | 14 | Go to [http://localhost:3000](http://localhost:3000) 15 | -------------------------------------------------------------------------------- /preclass/backend/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErickWendel/upload-multiple-files-yt/34cf07720c91f440c9047244a428d432f36a57e6/preclass/backend/demo.gif -------------------------------------------------------------------------------- /preclass/backend/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "busboy-upload", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@hapi/bourne": { 8 | "version": "2.0.0", 9 | "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.0.0.tgz", 10 | "integrity": "sha512-WEezM1FWztfbzqIUbsDzFRVMxSoLy3HugVcux6KDDtTqzPsLE8NDRHfXvev66aH1i2oOKKar3/XDjbvh/OUBdg==" 11 | }, 12 | "@types/component-emitter": { 13 | "version": "1.2.10", 14 | "resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz", 15 | "integrity": "sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg==" 16 | }, 17 | "@types/cookie": { 18 | "version": "0.4.0", 19 | "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.0.tgz", 20 | "integrity": "sha512-y7mImlc/rNkvCRmg8gC3/lj87S7pTUIJ6QGjwHR9WQJcFs+ZMTOaoPrkdFA/YdbuqVEmEbb5RdhVxMkAcgOnpg==" 21 | }, 22 | "@types/cors": { 23 | "version": "2.8.9", 24 | "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.9.tgz", 25 | "integrity": "sha512-zurD1ibz21BRlAOIKP8yhrxlqKx6L9VCwkB5kMiP6nZAhoF5MvC7qS1qPA7nRcr1GJolfkQC7/EAL4hdYejLtg==" 26 | }, 27 | "@types/node": { 28 | "version": "14.14.14", 29 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.14.tgz", 30 | "integrity": "sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==" 31 | }, 32 | "accepts": { 33 | "version": "1.3.7", 34 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 35 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 36 | "requires": { 37 | "mime-types": "~2.1.24", 38 | "negotiator": "0.6.2" 39 | } 40 | }, 41 | "ansi-styles": { 42 | "version": "3.2.1", 43 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 44 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 45 | "requires": { 46 | "color-convert": "^1.9.0" 47 | } 48 | }, 49 | "args": { 50 | "version": "5.0.1", 51 | "resolved": "https://registry.npmjs.org/args/-/args-5.0.1.tgz", 52 | "integrity": "sha512-1kqmFCFsPffavQFGt8OxJdIcETti99kySRUPMpOhaGjL6mRJn8HFU1OxKY5bMqfZKUwTQc1mZkAjmGYaVOHFtQ==", 53 | "requires": { 54 | "camelcase": "5.0.0", 55 | "chalk": "2.4.2", 56 | "leven": "2.1.0", 57 | "mri": "1.1.4" 58 | }, 59 | "dependencies": { 60 | "chalk": { 61 | "version": "2.4.2", 62 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 63 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 64 | "requires": { 65 | "ansi-styles": "^3.2.1", 66 | "escape-string-regexp": "^1.0.5", 67 | "supports-color": "^5.3.0" 68 | } 69 | } 70 | } 71 | }, 72 | "atomic-sleep": { 73 | "version": "1.0.0", 74 | "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", 75 | "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==" 76 | }, 77 | "base64-arraybuffer": { 78 | "version": "0.1.4", 79 | "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", 80 | "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=" 81 | }, 82 | "base64id": { 83 | "version": "2.0.0", 84 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", 85 | "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" 86 | }, 87 | "busboy": { 88 | "version": "0.3.1", 89 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.3.1.tgz", 90 | "integrity": "sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==", 91 | "requires": { 92 | "dicer": "0.3.0" 93 | } 94 | }, 95 | "camelcase": { 96 | "version": "5.0.0", 97 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", 98 | "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==" 99 | }, 100 | "chalk": { 101 | "version": "4.1.0", 102 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", 103 | "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", 104 | "requires": { 105 | "ansi-styles": "^4.1.0", 106 | "supports-color": "^7.1.0" 107 | }, 108 | "dependencies": { 109 | "ansi-styles": { 110 | "version": "4.3.0", 111 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 112 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 113 | "requires": { 114 | "color-convert": "^2.0.1" 115 | } 116 | }, 117 | "color-convert": { 118 | "version": "2.0.1", 119 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 120 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 121 | "requires": { 122 | "color-name": "~1.1.4" 123 | } 124 | }, 125 | "color-name": { 126 | "version": "1.1.4", 127 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 128 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 129 | }, 130 | "has-flag": { 131 | "version": "4.0.0", 132 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 133 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" 134 | }, 135 | "supports-color": { 136 | "version": "7.2.0", 137 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 138 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 139 | "requires": { 140 | "has-flag": "^4.0.0" 141 | } 142 | } 143 | } 144 | }, 145 | "color-convert": { 146 | "version": "1.9.3", 147 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 148 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 149 | "requires": { 150 | "color-name": "1.1.3" 151 | } 152 | }, 153 | "color-name": { 154 | "version": "1.1.3", 155 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 156 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 157 | }, 158 | "component-emitter": { 159 | "version": "1.3.0", 160 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", 161 | "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" 162 | }, 163 | "cookie": { 164 | "version": "0.4.1", 165 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", 166 | "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" 167 | }, 168 | "cors": { 169 | "version": "2.8.5", 170 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", 171 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", 172 | "requires": { 173 | "object-assign": "^4", 174 | "vary": "^1" 175 | } 176 | }, 177 | "dateformat": { 178 | "version": "3.0.3", 179 | "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", 180 | "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==" 181 | }, 182 | "debug": { 183 | "version": "4.1.1", 184 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 185 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 186 | "requires": { 187 | "ms": "^2.1.1" 188 | } 189 | }, 190 | "dicer": { 191 | "version": "0.3.0", 192 | "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz", 193 | "integrity": "sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==", 194 | "requires": { 195 | "streamsearch": "0.1.2" 196 | } 197 | }, 198 | "end-of-stream": { 199 | "version": "1.4.4", 200 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 201 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 202 | "requires": { 203 | "once": "^1.4.0" 204 | } 205 | }, 206 | "engine.io": { 207 | "version": "4.0.5", 208 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-4.0.5.tgz", 209 | "integrity": "sha512-Ri+whTNr2PKklxQkfbGjwEo+kCBUM4Qxk4wtLqLrhH+b1up2NFL9g9pjYWiCV/oazwB0rArnvF/ZmZN2ab5Hpg==", 210 | "requires": { 211 | "accepts": "~1.3.4", 212 | "base64id": "2.0.0", 213 | "cookie": "~0.4.1", 214 | "cors": "~2.8.5", 215 | "debug": "~4.1.0", 216 | "engine.io-parser": "~4.0.0", 217 | "ws": "^7.1.2" 218 | } 219 | }, 220 | "engine.io-parser": { 221 | "version": "4.0.2", 222 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-4.0.2.tgz", 223 | "integrity": "sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/MqJdZbUjW97JU72iYg==", 224 | "requires": { 225 | "base64-arraybuffer": "0.1.4" 226 | } 227 | }, 228 | "escape-string-regexp": { 229 | "version": "1.0.5", 230 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 231 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 232 | }, 233 | "fast-redact": { 234 | "version": "3.0.0", 235 | "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.0.0.tgz", 236 | "integrity": "sha512-a/S/Hp6aoIjx7EmugtzLqXmcNsyFszqbt6qQ99BdG61QjBZF6shNis0BYR6TsZOQ1twYc0FN2Xdhwwbv6+KD0w==" 237 | }, 238 | "fast-safe-stringify": { 239 | "version": "2.0.7", 240 | "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", 241 | "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" 242 | }, 243 | "flatstr": { 244 | "version": "1.0.12", 245 | "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz", 246 | "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==" 247 | }, 248 | "has-flag": { 249 | "version": "3.0.0", 250 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 251 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" 252 | }, 253 | "inherits": { 254 | "version": "2.0.4", 255 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 256 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 257 | }, 258 | "jmespath": { 259 | "version": "0.15.0", 260 | "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", 261 | "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" 262 | }, 263 | "joycon": { 264 | "version": "2.2.5", 265 | "resolved": "https://registry.npmjs.org/joycon/-/joycon-2.2.5.tgz", 266 | "integrity": "sha512-YqvUxoOcVPnCp0VU1/56f+iKSdvIRJYPznH22BdXV3xMk75SFXhWeJkZ8C9XxUWt1b5x2X1SxuFygW1U0FmkEQ==" 267 | }, 268 | "leven": { 269 | "version": "2.1.0", 270 | "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", 271 | "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=" 272 | }, 273 | "mime-db": { 274 | "version": "1.44.0", 275 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", 276 | "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" 277 | }, 278 | "mime-types": { 279 | "version": "2.1.27", 280 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", 281 | "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", 282 | "requires": { 283 | "mime-db": "1.44.0" 284 | } 285 | }, 286 | "mri": { 287 | "version": "1.1.4", 288 | "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz", 289 | "integrity": "sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w==" 290 | }, 291 | "ms": { 292 | "version": "2.1.3", 293 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 294 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 295 | }, 296 | "negotiator": { 297 | "version": "0.6.2", 298 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 299 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 300 | }, 301 | "object-assign": { 302 | "version": "4.1.1", 303 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 304 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 305 | }, 306 | "once": { 307 | "version": "1.4.0", 308 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 309 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 310 | "requires": { 311 | "wrappy": "1" 312 | } 313 | }, 314 | "pino": { 315 | "version": "6.8.0", 316 | "resolved": "https://registry.npmjs.org/pino/-/pino-6.8.0.tgz", 317 | "integrity": "sha512-nxq+6Jr7m0cMjYFBoTRw3bco14omZ/SQCheAHz9GVwdkbUrzKhgT+gSI/ql2Mnsca0QQKgpB/ACWhjxE4JsX3Q==", 318 | "requires": { 319 | "fast-redact": "^3.0.0", 320 | "fast-safe-stringify": "^2.0.7", 321 | "flatstr": "^1.0.12", 322 | "pino-std-serializers": "^2.4.2", 323 | "quick-format-unescaped": "^4.0.1", 324 | "sonic-boom": "^1.0.2" 325 | } 326 | }, 327 | "pino-pretty": { 328 | "version": "4.3.0", 329 | "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-4.3.0.tgz", 330 | "integrity": "sha512-uEc9SUCCGVEs0goZvyznKXBHtI1PNjGgqHviJHxOCEFEWZN6Z/IQKv5pO9gSdm/b+WfX+/dfheWhtZUyScqjlQ==", 331 | "requires": { 332 | "@hapi/bourne": "^2.0.0", 333 | "args": "^5.0.1", 334 | "chalk": "^4.0.0", 335 | "dateformat": "^3.0.3", 336 | "fast-safe-stringify": "^2.0.7", 337 | "jmespath": "^0.15.0", 338 | "joycon": "^2.2.5", 339 | "pump": "^3.0.0", 340 | "readable-stream": "^3.6.0", 341 | "split2": "^3.1.1", 342 | "strip-json-comments": "^3.1.1" 343 | } 344 | }, 345 | "pino-std-serializers": { 346 | "version": "2.5.0", 347 | "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-2.5.0.tgz", 348 | "integrity": "sha512-wXqbqSrIhE58TdrxxlfLwU9eDhrzppQDvGhBEr1gYbzzM4KKo3Y63gSjiDXRKLVS2UOXdPNR2v+KnQgNrs+xUg==" 349 | }, 350 | "pump": { 351 | "version": "3.0.0", 352 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 353 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 354 | "requires": { 355 | "end-of-stream": "^1.1.0", 356 | "once": "^1.3.1" 357 | } 358 | }, 359 | "quick-format-unescaped": { 360 | "version": "4.0.1", 361 | "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.1.tgz", 362 | "integrity": "sha512-RyYpQ6Q5/drsJyOhrWHYMWTedvjTIat+FTwv0K4yoUxzvekw2aRHMQJLlnvt8UantkZg2++bEzD9EdxXqkWf4A==" 363 | }, 364 | "readable-stream": { 365 | "version": "3.6.0", 366 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 367 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 368 | "requires": { 369 | "inherits": "^2.0.3", 370 | "string_decoder": "^1.1.1", 371 | "util-deprecate": "^1.0.1" 372 | } 373 | }, 374 | "safe-buffer": { 375 | "version": "5.2.1", 376 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 377 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 378 | }, 379 | "socket.io": { 380 | "version": "3.0.4", 381 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-3.0.4.tgz", 382 | "integrity": "sha512-Vj1jUoO75WGc9txWd311ZJJqS9Dr8QtNJJ7gk2r7dcM/yGe9sit7qOijQl3GAwhpBOz/W8CwkD7R6yob07nLbA==", 383 | "requires": { 384 | "@types/cookie": "^0.4.0", 385 | "@types/cors": "^2.8.8", 386 | "@types/node": "^14.14.7", 387 | "accepts": "~1.3.4", 388 | "base64id": "~2.0.0", 389 | "debug": "~4.1.0", 390 | "engine.io": "~4.0.0", 391 | "socket.io-adapter": "~2.0.3", 392 | "socket.io-parser": "~4.0.1" 393 | } 394 | }, 395 | "socket.io-adapter": { 396 | "version": "2.0.3", 397 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.0.3.tgz", 398 | "integrity": "sha512-2wo4EXgxOGSFueqvHAdnmi5JLZzWqMArjuP4nqC26AtLh5PoCPsaRbRdah2xhcwTAMooZfjYiNVNkkmmSMaxOQ==" 399 | }, 400 | "socket.io-parser": { 401 | "version": "4.0.2", 402 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.2.tgz", 403 | "integrity": "sha512-Bs3IYHDivwf+bAAuW/8xwJgIiBNtlvnjYRc4PbXgniLmcP1BrakBoq/QhO24rgtgW7VZ7uAaswRGxutUnlAK7g==", 404 | "requires": { 405 | "@types/component-emitter": "^1.2.10", 406 | "component-emitter": "~1.3.0", 407 | "debug": "~4.1.0" 408 | } 409 | }, 410 | "sonic-boom": { 411 | "version": "1.3.0", 412 | "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.3.0.tgz", 413 | "integrity": "sha512-4nX6OYvOYr6R76xfQKi6cZpTO3YSWe/vd+QdIfoH0lBy0MnPkeAbb2rRWgmgADkXUeCKPwO1FZAKlAVWAadELw==", 414 | "requires": { 415 | "atomic-sleep": "^1.0.0", 416 | "flatstr": "^1.0.12" 417 | } 418 | }, 419 | "split2": { 420 | "version": "3.2.2", 421 | "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", 422 | "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", 423 | "requires": { 424 | "readable-stream": "^3.0.0" 425 | } 426 | }, 427 | "streamsearch": { 428 | "version": "0.1.2", 429 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", 430 | "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" 431 | }, 432 | "string_decoder": { 433 | "version": "1.3.0", 434 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 435 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 436 | "requires": { 437 | "safe-buffer": "~5.2.0" 438 | } 439 | }, 440 | "strip-json-comments": { 441 | "version": "3.1.1", 442 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 443 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" 444 | }, 445 | "supports-color": { 446 | "version": "5.5.0", 447 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 448 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 449 | "requires": { 450 | "has-flag": "^3.0.0" 451 | } 452 | }, 453 | "util-deprecate": { 454 | "version": "1.0.2", 455 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 456 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 457 | }, 458 | "vary": { 459 | "version": "1.1.2", 460 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 461 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 462 | }, 463 | "wrappy": { 464 | "version": "1.0.2", 465 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 466 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 467 | }, 468 | "ws": { 469 | "version": "7.4.1", 470 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", 471 | "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==" 472 | } 473 | } 474 | } 475 | -------------------------------------------------------------------------------- /preclass/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "busboy-upload", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "npx nodemon src/index.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "busboy": "^0.3.1", 15 | "pino": "^6.8.0", 16 | "pino-pretty": "^4.3.0", 17 | "socket.io": "^3.0.4" 18 | }, 19 | "devDependencies": { 20 | "nodemon": "^2.0.4" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /preclass/backend/src/index.js: -------------------------------------------------------------------------------- 1 | const http = require('http') 2 | 3 | const socketIo = require('socket.io'); 4 | 5 | const { logger } = require('./util'); 6 | const Routes = require('./routes'); 7 | const PORT = 3000 8 | 9 | const handler = function (request, response) { 10 | const defaultRoute = async(request, response) => response.end('hello!'); 11 | 12 | const routes = new Routes(io) 13 | const chosen = routes[request.method.toLowerCase()] || defaultRoute 14 | 15 | return chosen.apply(routes, [request, response]) 16 | } 17 | 18 | 19 | const socketServer = http.createServer(handler); 20 | const io = socketIo(socketServer, { 21 | cors: { 22 | origin: "*", 23 | credentials: false, 24 | } 25 | }); 26 | 27 | io.on('connection', (socket) => logger.info('someone connected!', socket.id)); 28 | 29 | const startServer = () => { 30 | 31 | const { address: host, port } = socketServer.address() 32 | logger.info(`app running at http://${host}:${port}`) 33 | } 34 | 35 | socketServer.listen(PORT, startServer); -------------------------------------------------------------------------------- /preclass/backend/src/routes.js: -------------------------------------------------------------------------------- 1 | const url = require('url'); 2 | const { logger, pipelineAsync } = require('./util'); 3 | const UploadHandler = require('./uploadHandler'); 4 | 5 | 6 | class Routes { 7 | #io 8 | constructor(io) { 9 | this.#io = io 10 | } 11 | async options(request, response) { 12 | response.writeHead(204, { 13 | 'Access-Control-Allow-Origin': '*', 14 | 'Access-Control-Allow-Methods': 'OPTIONS, POST, GET' 15 | }); 16 | 17 | return response.end(); 18 | } 19 | 20 | async post(request, response) { 21 | const { headers } = request 22 | const { query: { socketId } } = url.parse(request.url, true) 23 | const redirectTo = headers.origin 24 | const uploadHandler = new UploadHandler(this.#io, socketId) 25 | 26 | const onFinish = (response, redirectTo) => () => { 27 | response.writeHead(303, { 28 | Connection: 'close', 29 | Location: `${redirectTo}?msg=Files uploaded with success!`, 30 | }); 31 | 32 | response.end(); 33 | } 34 | 35 | const busboyInstance = uploadHandler 36 | .registerEvents( 37 | headers, 38 | onFinish(response, redirectTo), 39 | ) 40 | 41 | 42 | await pipelineAsync( 43 | request, 44 | busboyInstance 45 | ) 46 | logger.info('Request finished with success!!'); 47 | 48 | } 49 | 50 | } 51 | 52 | module.exports = Routes -------------------------------------------------------------------------------- /preclass/backend/src/uploadHandler.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | 4 | const Busboy = require('busboy'); 5 | const { logger, pipelineAsync } = require('./util'); 6 | 7 | 8 | const FILE_EVENT_NAME = 'file-uploaded' 9 | 10 | class UploadHandler { 11 | #io 12 | #socketId 13 | 14 | constructor(io, socketId) { 15 | this.#io = io 16 | this.#socketId = socketId 17 | } 18 | 19 | registerEvents(headers, onFinish) { 20 | const busboy = new Busboy({ headers }); 21 | 22 | busboy.on('file', this.#onFile.bind(this)); 23 | busboy.on('finish', onFinish); 24 | 25 | return busboy 26 | } 27 | 28 | #handleFileBytes(filename) { 29 | async function* handleData(data) { 30 | for await (const item of data) { 31 | const size = item.length 32 | // logger.info(`File [${filename}] got ${size} bytes to ${this.#socketId}`) 33 | this.#io.to(this.#socketId).emit(FILE_EVENT_NAME, size) 34 | 35 | yield item 36 | } 37 | } 38 | 39 | return handleData.bind(this) 40 | } 41 | 42 | async #onFile(fieldname, file, filename) { 43 | const saveTo = path.join(__dirname, '../', 'downloads', filename); 44 | logger.info('Uploading: ' + saveTo); 45 | await pipelineAsync( 46 | file, 47 | this.#handleFileBytes.apply(this, [filename]), 48 | fs.createWriteStream(saveTo), 49 | ) 50 | 51 | logger.info(`File [${filename}] Finished`) 52 | } 53 | } 54 | 55 | 56 | module.exports = UploadHandler -------------------------------------------------------------------------------- /preclass/backend/src/util.js: -------------------------------------------------------------------------------- 1 | const logger = require('pino')({ 2 | prettyPrint: { 3 | ignore: 'pid,hostname' 4 | 5 | }, 6 | }); 7 | 8 | const { promisify } = require('util') 9 | const { pipeline } = require('stream'); 10 | const pipelineAsync = promisify(pipeline) 11 | 12 | 13 | module.exports = { 14 | pipelineAsync, 15 | promisify, 16 | logger: logger, 17 | } -------------------------------------------------------------------------------- /preclass/frontend/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "async": { 8 | "version": "2.6.3", 9 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", 10 | "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", 11 | "dev": true, 12 | "requires": { 13 | "lodash": "^4.17.14" 14 | } 15 | }, 16 | "basic-auth": { 17 | "version": "1.1.0", 18 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", 19 | "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", 20 | "dev": true 21 | }, 22 | "colors": { 23 | "version": "1.4.0", 24 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", 25 | "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", 26 | "dev": true 27 | }, 28 | "corser": { 29 | "version": "2.0.1", 30 | "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", 31 | "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", 32 | "dev": true 33 | }, 34 | "debug": { 35 | "version": "3.2.7", 36 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", 37 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", 38 | "dev": true, 39 | "requires": { 40 | "ms": "^2.1.1" 41 | } 42 | }, 43 | "ecstatic": { 44 | "version": "3.3.2", 45 | "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", 46 | "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", 47 | "dev": true, 48 | "requires": { 49 | "he": "^1.1.1", 50 | "mime": "^1.6.0", 51 | "minimist": "^1.1.0", 52 | "url-join": "^2.0.5" 53 | } 54 | }, 55 | "eventemitter3": { 56 | "version": "4.0.7", 57 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", 58 | "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", 59 | "dev": true 60 | }, 61 | "follow-redirects": { 62 | "version": "1.13.1", 63 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", 64 | "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==", 65 | "dev": true 66 | }, 67 | "he": { 68 | "version": "1.2.0", 69 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 70 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 71 | "dev": true 72 | }, 73 | "http-proxy": { 74 | "version": "1.18.1", 75 | "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", 76 | "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", 77 | "dev": true, 78 | "requires": { 79 | "eventemitter3": "^4.0.0", 80 | "follow-redirects": "^1.0.0", 81 | "requires-port": "^1.0.0" 82 | } 83 | }, 84 | "http-server": { 85 | "version": "0.12.3", 86 | "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", 87 | "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", 88 | "dev": true, 89 | "requires": { 90 | "basic-auth": "^1.0.3", 91 | "colors": "^1.4.0", 92 | "corser": "^2.0.1", 93 | "ecstatic": "^3.3.2", 94 | "http-proxy": "^1.18.0", 95 | "minimist": "^1.2.5", 96 | "opener": "^1.5.1", 97 | "portfinder": "^1.0.25", 98 | "secure-compare": "3.0.1", 99 | "union": "~0.5.0" 100 | } 101 | }, 102 | "lodash": { 103 | "version": "4.17.20", 104 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 105 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", 106 | "dev": true 107 | }, 108 | "mime": { 109 | "version": "1.6.0", 110 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 111 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 112 | "dev": true 113 | }, 114 | "minimist": { 115 | "version": "1.2.5", 116 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 117 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 118 | "dev": true 119 | }, 120 | "mkdirp": { 121 | "version": "0.5.5", 122 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 123 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 124 | "dev": true, 125 | "requires": { 126 | "minimist": "^1.2.5" 127 | } 128 | }, 129 | "ms": { 130 | "version": "2.1.3", 131 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 132 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 133 | "dev": true 134 | }, 135 | "opener": { 136 | "version": "1.5.2", 137 | "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", 138 | "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", 139 | "dev": true 140 | }, 141 | "portfinder": { 142 | "version": "1.0.28", 143 | "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", 144 | "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", 145 | "dev": true, 146 | "requires": { 147 | "async": "^2.6.2", 148 | "debug": "^3.1.1", 149 | "mkdirp": "^0.5.5" 150 | } 151 | }, 152 | "qs": { 153 | "version": "6.9.4", 154 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", 155 | "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", 156 | "dev": true 157 | }, 158 | "requires-port": { 159 | "version": "1.0.0", 160 | "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", 161 | "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", 162 | "dev": true 163 | }, 164 | "secure-compare": { 165 | "version": "3.0.1", 166 | "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", 167 | "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", 168 | "dev": true 169 | }, 170 | "union": { 171 | "version": "0.5.0", 172 | "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", 173 | "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", 174 | "dev": true, 175 | "requires": { 176 | "qs": "^6.4.0" 177 | } 178 | }, 179 | "url-join": { 180 | "version": "2.0.5", 181 | "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", 182 | "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", 183 | "dev": true 184 | } 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /preclass/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "npx http-server --cors public" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "http-server": "^0.12.3" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /preclass/frontend/public/app.js: -------------------------------------------------------------------------------- 1 | let bytesAmount = 0; 2 | const API_URL = "http://localhost:3000" 3 | const ON_UPLOAD_EVENT = "file-uploaded" 4 | 5 | 6 | 7 | function formatBytes(bytes, decimals = 2) { 8 | if (bytes === 0) return "0 Bytes"; 9 | 10 | const k = 1024; 11 | const dm = decimals < 0 ? 0 : decimals; 12 | const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; 13 | 14 | const i = Math.floor(Math.log(bytes) / Math.log(k)); 15 | 16 | return ( 17 | parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i] 18 | ); 19 | } 20 | 21 | function updateStatus(size) { 22 | const text = `Pending Bytes to upload: ${formatBytes(size)}`; 23 | document.getElementById("size").innerHTML = text; 24 | } 25 | 26 | function showSize() { 27 | const { files: fileElements } = document.getElementById("file"); 28 | if (!fileElements.length) return; 29 | 30 | const files = Array.from(fileElements) 31 | 32 | const { size } = files 33 | .reduce((prev, next) => ({ size: prev.size + next.size }), { size: 0 }); 34 | 35 | 36 | bytesAmount = size 37 | updateStatus(size); 38 | 39 | // const interval = setInterval(() => { 40 | // console.count() 41 | // const result = bytesAmount - 5e6; 42 | // bytesAmount = result < 0 ? 0 : result 43 | // updateStatus(bytesAmount); 44 | // if(bytesAmount === 0) clearInterval(interval) 45 | // }, 50); 46 | }; 47 | 48 | 49 | const configureForm = (targetUrl) => { 50 | const form = document.getElementById('form') 51 | form.action = targetUrl 52 | form.addEventListener('reset', () => updateStatus(0)) 53 | } 54 | 55 | const updateMessage = (message) => { 56 | const msg = document.getElementById('msg') 57 | msg.innerText = message 58 | 59 | msg.classList.add('alert', 'alert-primary') 60 | 61 | setTimeout(() => { 62 | msg.hidden = true 63 | }, 3000); 64 | } 65 | 66 | const showMessages = () => { 67 | const urlParams = new URLSearchParams(window.location.search); 68 | const serverMessage = urlParams.get('msg') 69 | if (!serverMessage) return; 70 | 71 | updateMessage(serverMessage) 72 | 73 | } 74 | 75 | const onload = () => { 76 | showMessages() 77 | 78 | const ioClient = io.connect(API_URL, { withCredentials: false }); 79 | ioClient.on("connect", (msg) => { 80 | console.log("connected!", ioClient.id) 81 | const targetUrl = API_URL + `?socketId=${ioClient.id}` 82 | configureForm(targetUrl) 83 | }); 84 | 85 | ioClient.on(ON_UPLOAD_EVENT, (bytesReceived) => { 86 | // console.log("uploaded!", msg); 87 | bytesAmount = bytesAmount - bytesReceived; 88 | updateStatus(bytesAmount); 89 | }); 90 | 91 | updateStatus(0) 92 | } 93 | 94 | 95 | window.showSize = showSize; 96 | window.onload = onload; 97 | 98 | -------------------------------------------------------------------------------- /preclass/frontend/public/deps/socket.io.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Socket.IO v3.0.4 3 | * (c) 2014-2020 Guillermo Rauch 4 | * Released under the MIT License. 5 | */ 6 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.io=e():t.io=e()}("undefined"!=typeof self?self:"undefined"!=typeof window?window:"undefined"!=typeof global?global:Function("return this")(),(function(){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=18)}([function(t,e,n){function r(t){if(t)return function(t){for(var e in r.prototype)t[e]=r.prototype[e];return t}(t)}t.exports=r,r.prototype.on=r.prototype.addEventListener=function(t,e){return this._callbacks=this._callbacks||{},(this._callbacks["$"+t]=this._callbacks["$"+t]||[]).push(e),this},r.prototype.once=function(t,e){function n(){this.off(t,n),e.apply(this,arguments)}return n.fn=e,this.on(t,n),this},r.prototype.off=r.prototype.removeListener=r.prototype.removeAllListeners=r.prototype.removeEventListener=function(t,e){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n,r=this._callbacks["$"+t];if(!r)return this;if(1==arguments.length)return delete this._callbacks["$"+t],this;for(var o=0;o=this._reconnectionAttempts)this.backoff.reset(),i(u(b.prototype),"emit",this).call(this,"reconnect_failed"),this._reconnecting=!1;else{var n=this.backoff.duration();this._reconnecting=!0;var r=setTimeout((function(){e.skipReconnect||(i(u(b.prototype),"emit",t).call(t,"reconnect_attempt",e.backoff.attempts),e.skipReconnect||e.open((function(n){n?(e._reconnecting=!1,e.reconnect(),i(u(b.prototype),"emit",t).call(t,"reconnect_error",n)):e.onreconnect()})))}),n);this.subs.push({destroy:function(){clearTimeout(r)}})}}},{key:"onreconnect",value:function(){var t=this.backoff.attempts;this._reconnecting=!1,this.backoff.reset(),i(u(b.prototype),"emit",this).call(this,"reconnect",t)}}])&&o(e.prototype,n),a&&o(e,a),b}(l);e.Manager=b},function(t,e,n){var r=n(9),o=n(23),i=n(27),s=n(28);e.polling=function(t){var e=!1,n=!1,s=!1!==t.jsonp;if("undefined"!=typeof location){var c="https:"===location.protocol,a=location.port;a||(a=c?443:80),e=t.hostname!==location.hostname||a!==t.port,n=t.secure!==c}if(t.xdomain=e,t.xscheme=n,"open"in new r(t)&&!t.forceJSONP)return new o(t);if(!s)throw new Error("JSONP disabled");return new i(t)},e.websocket=s},function(t,e,n){var r=n(22),o=n(2);t.exports=function(t){var e=t.xdomain,n=t.xscheme,i=t.enablesXDR;try{if("undefined"!=typeof XMLHttpRequest&&(!e||r))return new XMLHttpRequest}catch(t){}try{if("undefined"!=typeof XDomainRequest&&!n&&i)return new XDomainRequest}catch(t){}if(!e)try{return new(o[["Active"].concat("Object").join("X")])("Microsoft.XMLHTTP")}catch(t){}}},function(t,e,n){function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n0);return e}function u(){var t=a(+new Date);return t!==r?(s=0,r=t):t+"."+a(s++)}for(;c<64;c++)i[o[c]]=c;u.encode=a,u.decode=function(t){var e=0;for(c=0;c1?e-1:0),r=1;r=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,c=!0,a=!1;return{s:function(){n=t[Symbol.iterator]()},n:function(){var t=n.next();return c=t.done,t},e:function(t){a=!0,s=t},f:function(){try{c||null==n.return||n.return()}finally{if(a)throw s}}}}function i(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=new Array(e);n1?e-1:0),r=1;r1&&void 0!==arguments[1]?arguments[1]:{};return i(this,l),e=f.call(this),t&&"object"===o(t)&&(n=t,t=null),t?(t=y(t),n.hostname=t.host,n.secure="https"===t.protocol||"wss"===t.protocol,n.port=t.port,t.query&&(n.query=t.query)):n.host&&(n.hostname=y(n.host).host),e.secure=null!=n.secure?n.secure:"undefined"!=typeof location&&"https:"===location.protocol,n.hostname&&!n.port&&(n.port=e.secure?"443":"80"),e.hostname=n.hostname||("undefined"!=typeof location?location.hostname:"localhost"),e.port=n.port||("undefined"!=typeof location&&location.port?location.port:e.secure?443:80),e.transports=n.transports||["polling","websocket"],e.readyState="",e.writeBuffer=[],e.prevBufferLen=0,e.opts=r({path:"/engine.io",agent:!1,withCredentials:!1,upgrade:!0,jsonp:!0,timestampParam:"t",rememberUpgrade:!1,rejectUnauthorized:!0,perMessageDeflate:{threshold:1024},transportOptions:{}},n),e.opts.path=e.opts.path.replace(/\/$/,"")+"/","string"==typeof e.opts.query&&(e.opts.query=d.decode(e.opts.query)),e.id=null,e.upgrades=null,e.pingInterval=null,e.pingTimeout=null,e.pingTimeoutTimer=null,e.open(),e}return e=l,(n=[{key:"createTransport",value:function(t){var e=function(t){var e={};for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}(this.opts.query);e.EIO=h.protocol,e.transport=t,this.id&&(e.sid=this.id);var n=r({},this.opts.transportOptions[t],this.opts,{query:e,socket:this,hostname:this.hostname,secure:this.secure,port:this.port});return new p[t](n)}},{key:"open",value:function(){var t;if(this.opts.rememberUpgrade&&l.priorWebsocketSuccess&&-1!==this.transports.indexOf("websocket"))t="websocket";else{if(0===this.transports.length){var e=this;return void setTimeout((function(){e.emit("error","No transports available")}),0)}t=this.transports[0]}this.readyState="opening";try{t=this.createTransport(t)}catch(t){return this.transports.shift(),void this.open()}t.open(),this.setTransport(t)}},{key:"setTransport",value:function(t){var e=this;this.transport&&this.transport.removeAllListeners(),this.transport=t,t.on("drain",(function(){e.onDrain()})).on("packet",(function(t){e.onPacket(t)})).on("error",(function(t){e.onError(t)})).on("close",(function(){e.onClose("transport close")}))}},{key:"probe",value:function(t){var e=this.createTransport(t,{probe:1}),n=!1,r=this;function o(){if(r.onlyBinaryUpgrades){var t=!this.supportsBinary&&r.transport.supportsBinary;n=n||t}n||(e.send([{type:"ping",data:"probe"}]),e.once("packet",(function(t){if(!n)if("pong"===t.type&&"probe"===t.data){if(r.upgrading=!0,r.emit("upgrading",e),!e)return;l.priorWebsocketSuccess="websocket"===e.name,r.transport.pause((function(){n||"closed"!==r.readyState&&(f(),r.setTransport(e),e.send([{type:"upgrade"}]),r.emit("upgrade",e),e=null,r.upgrading=!1,r.flush())}))}else{var o=new Error("probe error");o.transport=e.name,r.emit("upgradeError",o)}})))}function i(){n||(n=!0,f(),e.close(),e=null)}function s(t){var n=new Error("probe error: "+t);n.transport=e.name,i(),r.emit("upgradeError",n)}function c(){s("transport closed")}function a(){s("socket closed")}function u(t){e&&t.name!==e.name&&i()}function f(){e.removeListener("open",o),e.removeListener("error",s),e.removeListener("close",c),r.removeListener("close",a),r.removeListener("upgrading",u)}l.priorWebsocketSuccess=!1,e.once("open",o),e.once("error",s),e.once("close",c),this.once("close",a),this.once("upgrading",u),e.open()}},{key:"onOpen",value:function(){if(this.readyState="open",l.priorWebsocketSuccess="websocket"===this.transport.name,this.emit("open"),this.flush(),"open"===this.readyState&&this.opts.upgrade&&this.transport.pause)for(var t=0,e=this.upgrades.length;t0&&void 0!==arguments[0]?arguments[0]:{};return o(t,{xd:this.xd,xs:this.xs},this.opts),new w(this.uri(),t)}},{key:"doWrite",value:function(t,e){var n=this.request({method:"POST",data:t}),r=this;n.on("success",e),n.on("error",(function(t){r.onError("xhr post error",t)}))}},{key:"doPoll",value:function(){var t=this.request(),e=this;t.on("data",(function(t){e.onData(t)})),t.on("error",(function(t){e.onError("xhr poll error",t)})),this.pollXhr=t}}]),n}(y),w=function(t){a(n,t);var e=f(n);function n(t,r){var o;return i(this,n),(o=e.call(this)).opts=r,o.method=r.method||"GET",o.uri=t,o.async=!1!==r.async,o.data=void 0!==r.data?r.data:null,o.create(),o}return c(n,[{key:"create",value:function(){var t=v(this.opts,"agent","enablesXDR","pfx","key","passphrase","cert","ca","ciphers","rejectUnauthorized");t.xdomain=!!this.opts.xd,t.xscheme=!!this.opts.xs;var e=this.xhr=new h(t),r=this;try{e.open(this.method,this.uri,this.async);try{if(this.opts.extraHeaders)for(var o in e.setDisableHeaderCheck&&e.setDisableHeaderCheck(!0),this.opts.extraHeaders)this.opts.extraHeaders.hasOwnProperty(o)&&e.setRequestHeader(o,this.opts.extraHeaders[o])}catch(t){}if("POST"===this.method)try{e.setRequestHeader("Content-type","text/plain;charset=UTF-8")}catch(t){}try{e.setRequestHeader("Accept","*/*")}catch(t){}"withCredentials"in e&&(e.withCredentials=this.opts.withCredentials),this.opts.requestTimeout&&(e.timeout=this.opts.requestTimeout),this.hasXDR()?(e.onload=function(){r.onLoad()},e.onerror=function(){r.onError(e.responseText)}):e.onreadystatechange=function(){4===e.readyState&&(200===e.status||1223===e.status?r.onLoad():setTimeout((function(){r.onError("number"==typeof e.status?e.status:0)}),0))},e.send(this.data)}catch(t){return void setTimeout((function(){r.onError(t)}),0)}"undefined"!=typeof document&&(this.index=n.requestsCount++,n.requests[this.index]=this)}},{key:"onSuccess",value:function(){this.emit("success"),this.cleanup()}},{key:"onData",value:function(t){this.emit("data",t),this.onSuccess()}},{key:"onError",value:function(t){this.emit("error",t),this.cleanup(!0)}},{key:"cleanup",value:function(t){if(void 0!==this.xhr&&null!==this.xhr){if(this.hasXDR()?this.xhr.onload=this.xhr.onerror=m:this.xhr.onreadystatechange=m,t)try{this.xhr.abort()}catch(t){}"undefined"!=typeof document&&delete n.requests[this.index],this.xhr=null}}},{key:"onLoad",value:function(){var t=this.xhr.responseText;null!==t&&this.onData(t)}},{key:"hasXDR",value:function(){return"undefined"!=typeof XDomainRequest&&!this.xs&&this.enablesXDR}},{key:"abort",value:function(){this.cleanup()}}]),n}(d);if(w.requestsCount=0,w.requests={},"undefined"!=typeof document)if("function"==typeof attachEvent)attachEvent("onunload",_);else if("function"==typeof addEventListener){addEventListener("onpagehide"in b?"pagehide":"unload",_,!1)}function _(){for(var t in w.requests)w.requests.hasOwnProperty(t)&&w.requests[t].abort()}t.exports=k,t.exports.Request=w},function(t,e,n){var r=n(11).PACKET_TYPES,o="function"==typeof Blob||"undefined"!=typeof Blob&&"[object BlobConstructor]"===Object.prototype.toString.call(Blob),i="function"==typeof ArrayBuffer,s=function(t,e){var n=new FileReader;return n.onload=function(){var t=n.result.split(",")[1];e("b"+t)},n.readAsDataURL(t)};t.exports=function(t,e,n){var c,a=t.type,u=t.data;return o&&u instanceof Blob?e?n(u):s(u,n):i&&(u instanceof ArrayBuffer||(c=u,"function"==typeof ArrayBuffer.isView?ArrayBuffer.isView(c):c&&c.buffer instanceof ArrayBuffer))?e?n(u instanceof ArrayBuffer?u:u.buffer):s(new Blob([u]),n):n(r[a]+(u||""))}},function(t,e,n){var r,o=n(11),i=o.PACKET_TYPES_REVERSE,s=o.ERROR_PACKET;"function"==typeof ArrayBuffer&&(r=n(26));var c=function(t,e){if(r){var n=r.decode(t);return a(n,e)}return{base64:!0,data:t}},a=function(t,e){switch(e){case"blob":return t instanceof ArrayBuffer?new Blob([t]):t;case"arraybuffer":default:return t}};t.exports=function(t,e){if("string"!=typeof t)return{type:"message",data:a(t,e)};var n=t.charAt(0);return"b"===n?{type:"message",data:c(t.substring(1),e)}:i[n]?t.length>1?{type:i[n],data:t.substring(1)}:{type:i[n]}:s}},function(t,e){!function(){"use strict";for(var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",n=new Uint8Array(256),r=0;r>2],i+=t[(3&r[n])<<4|r[n+1]>>4],i+=t[(15&r[n+1])<<2|r[n+2]>>6],i+=t[63&r[n+2]];return o%3==2?i=i.substring(0,i.length-1)+"=":o%3==1&&(i=i.substring(0,i.length-2)+"=="),i},e.decode=function(t){var e,r,o,i,s,c=.75*t.length,a=t.length,u=0;"="===t[t.length-1]&&(c--,"="===t[t.length-2]&&c--);var f=new ArrayBuffer(c),p=new Uint8Array(f);for(e=0;e>4,p[u++]=(15&o)<<4|i>>2,p[u++]=(3&i)<<6|63&s;return f}}()},function(t,e,n){function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e){for(var n=0;n';n=document.createElement(t)}catch(t){(n=document.createElement("iframe")).name=r.iframeId,n.src="javascript:0"}n.id=r.iframeId,r.form.appendChild(n),r.iframe=n}this.form.action=this.uri(),a(),t=t.replace(d,"\\\n"),this.area.value=t.replace(y,"\\n");try{this.form.submit()}catch(t){}this.iframe.attachEvent?this.iframe.onreadystatechange=function(){"complete"===r.iframe.readyState&&c()}:this.iframe.onload=c}},{key:"supportsBinary",get:function(){return!1}}])&&o(e.prototype,n),r&&o(e,r),l}(l);t.exports=b},function(t,e,n){function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e){for(var n=0;n0&&t.jitter<=1?t.jitter:0,this.attempts=0}t.exports=n,n.prototype.duration=function(){var t=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var e=Math.random(),n=Math.floor(e*this.jitter*t);t=0==(1&Math.floor(10*e))?t-n:t+n}return 0|Math.min(t,this.max)},n.prototype.reset=function(){this.attempts=0},n.prototype.setMin=function(t){this.ms=t},n.prototype.setMax=function(t){this.max=t},n.prototype.setJitter=function(t){this.jitter=t}}])})); 7 | //# sourceMappingURL=socket.io.min.js.map -------------------------------------------------------------------------------- /preclass/frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Upload files using Busboy 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |

Uploading files using BusBoy

16 |
17 |
18 | 19 | 27 | 28 |
29 | 30 |
31 |
32 | 33 | 34 |
35 |
36 |
37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /recorded/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "window.zoomLevel": 3 3 | } -------------------------------------------------------------------------------- /recorded/parte01/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "npx nodemon src/index.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "nodemon": "^2.0.6" 14 | }, 15 | "dependencies": { 16 | "socket.io": "3.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /recorded/parte01/backend/src/index.js: -------------------------------------------------------------------------------- 1 | const http = require('http') 2 | const socketIo = require('socket.io') 3 | const Routes = require('./routes') 4 | const PORT = 3000 5 | 6 | const handler = function (request, response) { 7 | const defaultRoute = async (request, response) => response.end('Hello!') 8 | 9 | const routes = new Routes(io) 10 | const chosen = routes[request.method.toLowerCase()] || defaultRoute 11 | 12 | return chosen.apply(routes, [request, response]) 13 | } 14 | 15 | const server = http.createServer(handler) 16 | const io = socketIo(server, { 17 | cors: { 18 | origin: "*", 19 | credentials: false 20 | } 21 | }) 22 | 23 | io.on("connection", (socket) => console.log('someone connected', socket.id)) 24 | 25 | // setInterval(() => { 26 | // io.emit('file-uploaded', 5e6) 27 | // }, 250) 28 | 29 | const startServer = () => { 30 | const { address, port } = server.address() 31 | console.log(`app running at http://${address}:${port}`) 32 | } 33 | 34 | server.listen(PORT, startServer) -------------------------------------------------------------------------------- /recorded/parte01/backend/src/routes.js: -------------------------------------------------------------------------------- 1 | const url = require('url') 2 | class Routes { 3 | #io 4 | constructor(io) { 5 | this.#io = io 6 | } 7 | 8 | async post(request, response) { 9 | const { headers } = request 10 | const { query: { socketId } } = url.parse(request.url, true) 11 | const redirectTo = headers.origin 12 | 13 | this.#io.to(socketId).emit('file-uploaded', 5e9) 14 | this.#io.to(socketId).emit('file-uploaded', 5e9) 15 | this.#io.to(socketId).emit('file-uploaded', 5e9) 16 | this.#io.to(socketId).emit('file-uploaded', 5e9) 17 | 18 | const onFinish = (response, redirectTo) => { 19 | response.writeHead(303, { 20 | Connection: 'close', 21 | Location: `${redirectTo}?msg=Files uploaded with success!` 22 | }) 23 | 24 | response.end() 25 | } 26 | setTimeout(() => { 27 | return onFinish(response, headers.origin) 28 | 29 | }, 2000); 30 | } 31 | } 32 | 33 | module.exports = Routes -------------------------------------------------------------------------------- /recorded/parte01/frontend/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "version": "1.0.0", 9 | "license": "ISC", 10 | "dependencies": { 11 | "http-server": "^0.12.3" 12 | } 13 | }, 14 | "node_modules/async": { 15 | "version": "2.6.3", 16 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", 17 | "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", 18 | "dependencies": { 19 | "lodash": "^4.17.14" 20 | } 21 | }, 22 | "node_modules/basic-auth": { 23 | "version": "1.1.0", 24 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", 25 | "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", 26 | "engines": { 27 | "node": ">= 0.6" 28 | } 29 | }, 30 | "node_modules/colors": { 31 | "version": "1.4.0", 32 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", 33 | "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", 34 | "engines": { 35 | "node": ">=0.1.90" 36 | } 37 | }, 38 | "node_modules/corser": { 39 | "version": "2.0.1", 40 | "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", 41 | "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", 42 | "engines": { 43 | "node": ">= 0.4.0" 44 | } 45 | }, 46 | "node_modules/debug": { 47 | "version": "3.2.7", 48 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", 49 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", 50 | "dependencies": { 51 | "ms": "^2.1.1" 52 | } 53 | }, 54 | "node_modules/ecstatic": { 55 | "version": "3.3.2", 56 | "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", 57 | "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", 58 | "dependencies": { 59 | "he": "^1.1.1", 60 | "mime": "^1.6.0", 61 | "minimist": "^1.1.0", 62 | "url-join": "^2.0.5" 63 | }, 64 | "bin": { 65 | "ecstatic": "lib/ecstatic.js" 66 | } 67 | }, 68 | "node_modules/eventemitter3": { 69 | "version": "4.0.7", 70 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", 71 | "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" 72 | }, 73 | "node_modules/follow-redirects": { 74 | "version": "1.13.1", 75 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", 76 | "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==", 77 | "funding": [ 78 | { 79 | "type": "individual", 80 | "url": "https://github.com/sponsors/RubenVerborgh" 81 | } 82 | ], 83 | "engines": { 84 | "node": ">=4.0" 85 | }, 86 | "peerDependenciesMeta": { 87 | "debug": { 88 | "optional": true 89 | } 90 | } 91 | }, 92 | "node_modules/he": { 93 | "version": "1.2.0", 94 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 95 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 96 | "bin": { 97 | "he": "bin/he" 98 | } 99 | }, 100 | "node_modules/http-proxy": { 101 | "version": "1.18.1", 102 | "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", 103 | "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", 104 | "dependencies": { 105 | "eventemitter3": "^4.0.0", 106 | "follow-redirects": "^1.0.0", 107 | "requires-port": "^1.0.0" 108 | }, 109 | "engines": { 110 | "node": ">=8.0.0" 111 | } 112 | }, 113 | "node_modules/http-server": { 114 | "version": "0.12.3", 115 | "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", 116 | "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", 117 | "dependencies": { 118 | "basic-auth": "^1.0.3", 119 | "colors": "^1.4.0", 120 | "corser": "^2.0.1", 121 | "ecstatic": "^3.3.2", 122 | "http-proxy": "^1.18.0", 123 | "minimist": "^1.2.5", 124 | "opener": "^1.5.1", 125 | "portfinder": "^1.0.25", 126 | "secure-compare": "3.0.1", 127 | "union": "~0.5.0" 128 | }, 129 | "bin": { 130 | "hs": "bin/http-server", 131 | "http-server": "bin/http-server" 132 | }, 133 | "engines": { 134 | "node": ">=6" 135 | } 136 | }, 137 | "node_modules/lodash": { 138 | "version": "4.17.20", 139 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 140 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" 141 | }, 142 | "node_modules/mime": { 143 | "version": "1.6.0", 144 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 145 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 146 | "bin": { 147 | "mime": "cli.js" 148 | }, 149 | "engines": { 150 | "node": ">=4" 151 | } 152 | }, 153 | "node_modules/minimist": { 154 | "version": "1.2.5", 155 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 156 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" 157 | }, 158 | "node_modules/mkdirp": { 159 | "version": "0.5.5", 160 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 161 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 162 | "dependencies": { 163 | "minimist": "^1.2.5" 164 | }, 165 | "bin": { 166 | "mkdirp": "bin/cmd.js" 167 | } 168 | }, 169 | "node_modules/ms": { 170 | "version": "2.1.3", 171 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 172 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 173 | }, 174 | "node_modules/opener": { 175 | "version": "1.5.2", 176 | "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", 177 | "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", 178 | "bin": { 179 | "opener": "bin/opener-bin.js" 180 | } 181 | }, 182 | "node_modules/portfinder": { 183 | "version": "1.0.28", 184 | "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", 185 | "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", 186 | "dependencies": { 187 | "async": "^2.6.2", 188 | "debug": "^3.1.1", 189 | "mkdirp": "^0.5.5" 190 | }, 191 | "engines": { 192 | "node": ">= 0.12.0" 193 | } 194 | }, 195 | "node_modules/qs": { 196 | "version": "6.9.4", 197 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", 198 | "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", 199 | "engines": { 200 | "node": ">=0.6" 201 | }, 202 | "funding": { 203 | "url": "https://github.com/sponsors/ljharb" 204 | } 205 | }, 206 | "node_modules/requires-port": { 207 | "version": "1.0.0", 208 | "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", 209 | "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" 210 | }, 211 | "node_modules/secure-compare": { 212 | "version": "3.0.1", 213 | "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", 214 | "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=" 215 | }, 216 | "node_modules/union": { 217 | "version": "0.5.0", 218 | "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", 219 | "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", 220 | "dependencies": { 221 | "qs": "^6.4.0" 222 | }, 223 | "engines": { 224 | "node": ">= 0.8.0" 225 | } 226 | }, 227 | "node_modules/url-join": { 228 | "version": "2.0.5", 229 | "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", 230 | "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=" 231 | } 232 | }, 233 | "dependencies": { 234 | "async": { 235 | "version": "2.6.3", 236 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", 237 | "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", 238 | "requires": { 239 | "lodash": "^4.17.14" 240 | } 241 | }, 242 | "basic-auth": { 243 | "version": "1.1.0", 244 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", 245 | "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=" 246 | }, 247 | "colors": { 248 | "version": "1.4.0", 249 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", 250 | "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" 251 | }, 252 | "corser": { 253 | "version": "2.0.1", 254 | "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", 255 | "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=" 256 | }, 257 | "debug": { 258 | "version": "3.2.7", 259 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", 260 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", 261 | "requires": { 262 | "ms": "^2.1.1" 263 | } 264 | }, 265 | "ecstatic": { 266 | "version": "3.3.2", 267 | "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", 268 | "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", 269 | "requires": { 270 | "he": "^1.1.1", 271 | "mime": "^1.6.0", 272 | "minimist": "^1.1.0", 273 | "url-join": "^2.0.5" 274 | } 275 | }, 276 | "eventemitter3": { 277 | "version": "4.0.7", 278 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", 279 | "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" 280 | }, 281 | "follow-redirects": { 282 | "version": "1.13.1", 283 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", 284 | "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==" 285 | }, 286 | "he": { 287 | "version": "1.2.0", 288 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 289 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" 290 | }, 291 | "http-proxy": { 292 | "version": "1.18.1", 293 | "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", 294 | "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", 295 | "requires": { 296 | "eventemitter3": "^4.0.0", 297 | "follow-redirects": "^1.0.0", 298 | "requires-port": "^1.0.0" 299 | } 300 | }, 301 | "http-server": { 302 | "version": "0.12.3", 303 | "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", 304 | "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", 305 | "requires": { 306 | "basic-auth": "^1.0.3", 307 | "colors": "^1.4.0", 308 | "corser": "^2.0.1", 309 | "ecstatic": "^3.3.2", 310 | "http-proxy": "^1.18.0", 311 | "minimist": "^1.2.5", 312 | "opener": "^1.5.1", 313 | "portfinder": "^1.0.25", 314 | "secure-compare": "3.0.1", 315 | "union": "~0.5.0" 316 | } 317 | }, 318 | "lodash": { 319 | "version": "4.17.20", 320 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 321 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" 322 | }, 323 | "mime": { 324 | "version": "1.6.0", 325 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 326 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 327 | }, 328 | "minimist": { 329 | "version": "1.2.5", 330 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 331 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" 332 | }, 333 | "mkdirp": { 334 | "version": "0.5.5", 335 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 336 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 337 | "requires": { 338 | "minimist": "^1.2.5" 339 | } 340 | }, 341 | "ms": { 342 | "version": "2.1.3", 343 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 344 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 345 | }, 346 | "opener": { 347 | "version": "1.5.2", 348 | "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", 349 | "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" 350 | }, 351 | "portfinder": { 352 | "version": "1.0.28", 353 | "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", 354 | "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", 355 | "requires": { 356 | "async": "^2.6.2", 357 | "debug": "^3.1.1", 358 | "mkdirp": "^0.5.5" 359 | } 360 | }, 361 | "qs": { 362 | "version": "6.9.4", 363 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", 364 | "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" 365 | }, 366 | "requires-port": { 367 | "version": "1.0.0", 368 | "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", 369 | "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" 370 | }, 371 | "secure-compare": { 372 | "version": "3.0.1", 373 | "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", 374 | "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=" 375 | }, 376 | "union": { 377 | "version": "0.5.0", 378 | "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", 379 | "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", 380 | "requires": { 381 | "qs": "^6.4.0" 382 | } 383 | }, 384 | "url-join": { 385 | "version": "2.0.5", 386 | "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", 387 | "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=" 388 | } 389 | } 390 | } 391 | -------------------------------------------------------------------------------- /recorded/parte01/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "npx http-server --cors public" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "http-server": "^0.12.3" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /recorded/parte01/frontend/public/app.js: -------------------------------------------------------------------------------- 1 | let bytesAmount = 0 2 | const API_URL = "http://localhost:3000" 3 | const ON_UPLOAD_EVENT = "file-uploaded" 4 | 5 | const formatBytes = (bytes, decimals = 2) => { 6 | if (bytes === 0) return '0 Bytes'; 7 | 8 | const k = 1024 9 | const dm = decimals < 0 ? 0 : decimals 10 | const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB"] 11 | const i = Math.floor(Math.log(bytes) / Math.log(k)) 12 | 13 | return ( 14 | parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i] 15 | ) 16 | } 17 | 18 | const updateStatus = (size) => { 19 | const text = `Pending Bytes to Upload: ${formatBytes(size)}` 20 | document.getElementById("size").innerHTML = text 21 | } 22 | 23 | const showSize = () => { 24 | const { files: fileElements } = document.getElementById('file') 25 | if (!fileElements.length) return; 26 | 27 | const files = Array.from(fileElements) 28 | const { size } = files 29 | .reduce((prev, next) => ({ size: prev.size + next.size }), { size: 0 }) 30 | 31 | bytesAmount = size 32 | updateStatus(size) 33 | 34 | // const interval = setInterval(() => { 35 | // console.count() 36 | // const result = bytesAmount - 5e6 37 | // bytesAmount = result < 0 ? 0 : result 38 | // updateStatus(bytesAmount) 39 | // if(bytesAmount === 0 ) clearInterval(interval) 40 | // }, 50) 41 | } 42 | 43 | const updateMessage = (message) => { 44 | const msg = document.getElementById('msg') 45 | msg.innerText = message 46 | 47 | msg.classList.add('alert', 'alert-success') 48 | setTimeout(() => (msg.hidden = true), 3000); 49 | 50 | } 51 | 52 | const showMessage = () => { 53 | const urlParams = new URLSearchParams(window.location.search) 54 | const serverMessage = urlParams.get('msg') 55 | if (!serverMessage) return; 56 | 57 | updateMessage(serverMessage) 58 | } 59 | 60 | const configureForm = (targetUrl) => { 61 | const form = document.getElementById("form") 62 | form.action = targetUrl 63 | } 64 | 65 | const onload = () => { 66 | showMessage() 67 | 68 | const ioClient = io.connect(API_URL, { withCredentials: false }) 69 | ioClient.on("connect", (msg) => { 70 | console.log('connected!', ioClient.id) 71 | const targetUrl = API_URL + `?socketId=${ioClient.id}` 72 | configureForm(targetUrl) 73 | }) 74 | 75 | ioClient.on(ON_UPLOAD_EVENT, (bytesReceived) => { 76 | console.log('received', bytesReceived) 77 | bytesAmount = bytesAmount - bytesReceived 78 | updateStatus(bytesAmount) 79 | }) 80 | 81 | updateStatus(0) 82 | 83 | } 84 | 85 | window.onload = onload 86 | window.showSize = showSize -------------------------------------------------------------------------------- /recorded/parte01/frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |

Uploading files using BusBoy

16 |
17 |
18 | 19 | 27 | 28 |
29 | 30 | 31 |
32 |
33 | 34 | 35 |
36 |
37 |
38 |
39 | 40 | -------------------------------------------------------------------------------- /recorded/parte02/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "npx nodemon src/index.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "nodemon": "^2.0.6" 14 | }, 15 | "dependencies": { 16 | "busboy": "^0.3.1", 17 | "pino": "^6.8.0", 18 | "pino-pretty": "^4.3.0", 19 | "socket.io": "3.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /recorded/parte02/backend/src/index.js: -------------------------------------------------------------------------------- 1 | const http = require('http') 2 | const socketIo = require('socket.io') 3 | const { logger } = require('./util') 4 | const Routes = require('./routes') 5 | const PORT = 3000 6 | 7 | const handler = function (request, response) { 8 | const defaultRoute = async (request, response) => response.end('Hello!') 9 | 10 | const routes = new Routes(io) 11 | const chosen = routes[request.method.toLowerCase()] || defaultRoute 12 | 13 | return chosen.apply(routes, [request, response]) 14 | } 15 | 16 | const server = http.createServer(handler) 17 | const io = socketIo(server, { 18 | cors: { 19 | origin: "*", 20 | credentials: false 21 | } 22 | }) 23 | 24 | io.on("connection", (socket) => logger.info('someone connected ' + socket.id)) 25 | 26 | // setInterval(() => { 27 | // io.emit('file-uploaded', 5e6) 28 | // }, 250) 29 | 30 | const startServer = () => { 31 | const { address, port } = server.address() 32 | logger.info(`app running at http://${address}:${port}`) 33 | } 34 | 35 | server.listen(PORT, startServer) -------------------------------------------------------------------------------- /recorded/parte02/backend/src/routes.js: -------------------------------------------------------------------------------- 1 | const url = require('url') 2 | const UploadHandler = require('./uploadHandler') 3 | const { pipelineAsync, logger } = require('./util') 4 | class Routes { 5 | #io 6 | constructor(io) { 7 | this.#io = io 8 | } 9 | async options(request, response) { 10 | response.writeHead(204, { 11 | 'Access-Control-Allow-Origin': '*', 12 | 'Access-Control-Allow-Methods': 'OPTIONS, POST' 13 | }) 14 | response.end() 15 | } 16 | 17 | 18 | async post(request, response) { 19 | const { headers } = request 20 | const { query: { socketId } } = url.parse(request.url, true) 21 | const redirectTo = headers.origin 22 | 23 | const uploadHandler = new UploadHandler(this.#io, socketId) 24 | 25 | const onFinish = (response, redirectTo) => () => { 26 | response.writeHead(303, { 27 | Connection: 'close', 28 | Location: `${redirectTo}?msg=Files uploaded with success!` 29 | }) 30 | 31 | response.end() 32 | } 33 | 34 | const busboyInstance = uploadHandler 35 | .registerEvents( 36 | headers, 37 | onFinish(response, redirectTo) 38 | ) 39 | 40 | await pipelineAsync( 41 | request, 42 | busboyInstance 43 | ) 44 | 45 | logger.info('Request finished with success!') 46 | 47 | 48 | } 49 | } 50 | 51 | module.exports = Routes -------------------------------------------------------------------------------- /recorded/parte02/backend/src/uploadHandler.js: -------------------------------------------------------------------------------- 1 | const Busboy = require('busboy') 2 | const { logger, pipelineAsync } = require('./util') 3 | const { join } = require('path') 4 | const { createWriteStream } = require('fs') 5 | const ON_UPLOAD_EVENT = "file-uploaded" 6 | 7 | class UploadHandler { 8 | #io 9 | #socketId 10 | constructor(io, socketId) { 11 | this.#io = io 12 | this.#socketId = socketId 13 | } 14 | 15 | registerEvents(headers, onFinish) { 16 | const busboy = new Busboy({ headers }) 17 | 18 | busboy.on("file", this.#onFile.bind(this)) 19 | 20 | busboy.on("finish", onFinish) 21 | 22 | return busboy 23 | } 24 | 25 | #handleFileBytes(filename) { 26 | async function * handleData(data) { 27 | for await (const item of data) { 28 | const size = item.length 29 | // logger.info(`File [${filename}] got ${size} bytes to ${this.#socketId}`) 30 | this.#io.to(this.#socketId).emit(ON_UPLOAD_EVENT, size) 31 | 32 | yield item 33 | } 34 | } 35 | 36 | return handleData.bind(this) 37 | } 38 | 39 | async #onFile(fieldname, file, filename) { 40 | const saveFileTo = join(__dirname, '../', 'downloads', filename) 41 | logger.info('Uploading: ' + saveFileTo) 42 | 43 | await pipelineAsync( 44 | file, 45 | this.#handleFileBytes.apply(this, [ filename ]), 46 | createWriteStream(saveFileTo) 47 | ) 48 | 49 | logger.info(`File [${filename}] finished!`) 50 | } 51 | 52 | } 53 | 54 | module.exports = UploadHandler -------------------------------------------------------------------------------- /recorded/parte02/backend/src/util.js: -------------------------------------------------------------------------------- 1 | const logger = require('pino')({ 2 | prettyPrint: { 3 | ignore: 'pid,hostname' 4 | } 5 | }) 6 | 7 | const { promisify } = require('util') 8 | const { pipeline } = require('stream') 9 | const pipelineAsync = promisify(pipeline) 10 | 11 | module.exports = { 12 | logger, 13 | pipelineAsync, 14 | promisify 15 | } -------------------------------------------------------------------------------- /recorded/parte02/frontend/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "version": "1.0.0", 9 | "license": "ISC", 10 | "dependencies": { 11 | "http-server": "^0.12.3" 12 | } 13 | }, 14 | "node_modules/async": { 15 | "version": "2.6.3", 16 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", 17 | "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", 18 | "dependencies": { 19 | "lodash": "^4.17.14" 20 | } 21 | }, 22 | "node_modules/basic-auth": { 23 | "version": "1.1.0", 24 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", 25 | "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", 26 | "engines": { 27 | "node": ">= 0.6" 28 | } 29 | }, 30 | "node_modules/colors": { 31 | "version": "1.4.0", 32 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", 33 | "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", 34 | "engines": { 35 | "node": ">=0.1.90" 36 | } 37 | }, 38 | "node_modules/corser": { 39 | "version": "2.0.1", 40 | "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", 41 | "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", 42 | "engines": { 43 | "node": ">= 0.4.0" 44 | } 45 | }, 46 | "node_modules/debug": { 47 | "version": "3.2.7", 48 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", 49 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", 50 | "dependencies": { 51 | "ms": "^2.1.1" 52 | } 53 | }, 54 | "node_modules/ecstatic": { 55 | "version": "3.3.2", 56 | "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", 57 | "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", 58 | "dependencies": { 59 | "he": "^1.1.1", 60 | "mime": "^1.6.0", 61 | "minimist": "^1.1.0", 62 | "url-join": "^2.0.5" 63 | }, 64 | "bin": { 65 | "ecstatic": "lib/ecstatic.js" 66 | } 67 | }, 68 | "node_modules/eventemitter3": { 69 | "version": "4.0.7", 70 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", 71 | "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" 72 | }, 73 | "node_modules/follow-redirects": { 74 | "version": "1.13.1", 75 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", 76 | "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==", 77 | "funding": [ 78 | { 79 | "type": "individual", 80 | "url": "https://github.com/sponsors/RubenVerborgh" 81 | } 82 | ], 83 | "engines": { 84 | "node": ">=4.0" 85 | }, 86 | "peerDependenciesMeta": { 87 | "debug": { 88 | "optional": true 89 | } 90 | } 91 | }, 92 | "node_modules/he": { 93 | "version": "1.2.0", 94 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 95 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 96 | "bin": { 97 | "he": "bin/he" 98 | } 99 | }, 100 | "node_modules/http-proxy": { 101 | "version": "1.18.1", 102 | "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", 103 | "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", 104 | "dependencies": { 105 | "eventemitter3": "^4.0.0", 106 | "follow-redirects": "^1.0.0", 107 | "requires-port": "^1.0.0" 108 | }, 109 | "engines": { 110 | "node": ">=8.0.0" 111 | } 112 | }, 113 | "node_modules/http-server": { 114 | "version": "0.12.3", 115 | "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", 116 | "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", 117 | "dependencies": { 118 | "basic-auth": "^1.0.3", 119 | "colors": "^1.4.0", 120 | "corser": "^2.0.1", 121 | "ecstatic": "^3.3.2", 122 | "http-proxy": "^1.18.0", 123 | "minimist": "^1.2.5", 124 | "opener": "^1.5.1", 125 | "portfinder": "^1.0.25", 126 | "secure-compare": "3.0.1", 127 | "union": "~0.5.0" 128 | }, 129 | "bin": { 130 | "hs": "bin/http-server", 131 | "http-server": "bin/http-server" 132 | }, 133 | "engines": { 134 | "node": ">=6" 135 | } 136 | }, 137 | "node_modules/lodash": { 138 | "version": "4.17.20", 139 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 140 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" 141 | }, 142 | "node_modules/mime": { 143 | "version": "1.6.0", 144 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 145 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 146 | "bin": { 147 | "mime": "cli.js" 148 | }, 149 | "engines": { 150 | "node": ">=4" 151 | } 152 | }, 153 | "node_modules/minimist": { 154 | "version": "1.2.5", 155 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 156 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" 157 | }, 158 | "node_modules/mkdirp": { 159 | "version": "0.5.5", 160 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 161 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 162 | "dependencies": { 163 | "minimist": "^1.2.5" 164 | }, 165 | "bin": { 166 | "mkdirp": "bin/cmd.js" 167 | } 168 | }, 169 | "node_modules/ms": { 170 | "version": "2.1.3", 171 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 172 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 173 | }, 174 | "node_modules/opener": { 175 | "version": "1.5.2", 176 | "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", 177 | "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", 178 | "bin": { 179 | "opener": "bin/opener-bin.js" 180 | } 181 | }, 182 | "node_modules/portfinder": { 183 | "version": "1.0.28", 184 | "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", 185 | "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", 186 | "dependencies": { 187 | "async": "^2.6.2", 188 | "debug": "^3.1.1", 189 | "mkdirp": "^0.5.5" 190 | }, 191 | "engines": { 192 | "node": ">= 0.12.0" 193 | } 194 | }, 195 | "node_modules/qs": { 196 | "version": "6.9.4", 197 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", 198 | "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", 199 | "engines": { 200 | "node": ">=0.6" 201 | }, 202 | "funding": { 203 | "url": "https://github.com/sponsors/ljharb" 204 | } 205 | }, 206 | "node_modules/requires-port": { 207 | "version": "1.0.0", 208 | "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", 209 | "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" 210 | }, 211 | "node_modules/secure-compare": { 212 | "version": "3.0.1", 213 | "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", 214 | "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=" 215 | }, 216 | "node_modules/union": { 217 | "version": "0.5.0", 218 | "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", 219 | "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", 220 | "dependencies": { 221 | "qs": "^6.4.0" 222 | }, 223 | "engines": { 224 | "node": ">= 0.8.0" 225 | } 226 | }, 227 | "node_modules/url-join": { 228 | "version": "2.0.5", 229 | "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", 230 | "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=" 231 | } 232 | }, 233 | "dependencies": { 234 | "async": { 235 | "version": "2.6.3", 236 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", 237 | "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", 238 | "requires": { 239 | "lodash": "^4.17.14" 240 | } 241 | }, 242 | "basic-auth": { 243 | "version": "1.1.0", 244 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", 245 | "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=" 246 | }, 247 | "colors": { 248 | "version": "1.4.0", 249 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", 250 | "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" 251 | }, 252 | "corser": { 253 | "version": "2.0.1", 254 | "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", 255 | "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=" 256 | }, 257 | "debug": { 258 | "version": "3.2.7", 259 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", 260 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", 261 | "requires": { 262 | "ms": "^2.1.1" 263 | } 264 | }, 265 | "ecstatic": { 266 | "version": "3.3.2", 267 | "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", 268 | "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", 269 | "requires": { 270 | "he": "^1.1.1", 271 | "mime": "^1.6.0", 272 | "minimist": "^1.1.0", 273 | "url-join": "^2.0.5" 274 | } 275 | }, 276 | "eventemitter3": { 277 | "version": "4.0.7", 278 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", 279 | "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" 280 | }, 281 | "follow-redirects": { 282 | "version": "1.13.1", 283 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", 284 | "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==" 285 | }, 286 | "he": { 287 | "version": "1.2.0", 288 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 289 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" 290 | }, 291 | "http-proxy": { 292 | "version": "1.18.1", 293 | "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", 294 | "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", 295 | "requires": { 296 | "eventemitter3": "^4.0.0", 297 | "follow-redirects": "^1.0.0", 298 | "requires-port": "^1.0.0" 299 | } 300 | }, 301 | "http-server": { 302 | "version": "0.12.3", 303 | "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", 304 | "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", 305 | "requires": { 306 | "basic-auth": "^1.0.3", 307 | "colors": "^1.4.0", 308 | "corser": "^2.0.1", 309 | "ecstatic": "^3.3.2", 310 | "http-proxy": "^1.18.0", 311 | "minimist": "^1.2.5", 312 | "opener": "^1.5.1", 313 | "portfinder": "^1.0.25", 314 | "secure-compare": "3.0.1", 315 | "union": "~0.5.0" 316 | } 317 | }, 318 | "lodash": { 319 | "version": "4.17.20", 320 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", 321 | "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" 322 | }, 323 | "mime": { 324 | "version": "1.6.0", 325 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 326 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 327 | }, 328 | "minimist": { 329 | "version": "1.2.5", 330 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 331 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" 332 | }, 333 | "mkdirp": { 334 | "version": "0.5.5", 335 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 336 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 337 | "requires": { 338 | "minimist": "^1.2.5" 339 | } 340 | }, 341 | "ms": { 342 | "version": "2.1.3", 343 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 344 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 345 | }, 346 | "opener": { 347 | "version": "1.5.2", 348 | "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", 349 | "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" 350 | }, 351 | "portfinder": { 352 | "version": "1.0.28", 353 | "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", 354 | "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", 355 | "requires": { 356 | "async": "^2.6.2", 357 | "debug": "^3.1.1", 358 | "mkdirp": "^0.5.5" 359 | } 360 | }, 361 | "qs": { 362 | "version": "6.9.4", 363 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", 364 | "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" 365 | }, 366 | "requires-port": { 367 | "version": "1.0.0", 368 | "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", 369 | "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" 370 | }, 371 | "secure-compare": { 372 | "version": "3.0.1", 373 | "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", 374 | "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=" 375 | }, 376 | "union": { 377 | "version": "0.5.0", 378 | "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", 379 | "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", 380 | "requires": { 381 | "qs": "^6.4.0" 382 | } 383 | }, 384 | "url-join": { 385 | "version": "2.0.5", 386 | "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", 387 | "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=" 388 | } 389 | } 390 | } 391 | -------------------------------------------------------------------------------- /recorded/parte02/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "npx http-server --cors public" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "http-server": "^0.12.3" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /recorded/parte02/frontend/public/app.js: -------------------------------------------------------------------------------- 1 | let bytesAmount = 0 2 | const API_URL = "http://localhost:3000" 3 | const ON_UPLOAD_EVENT = "file-uploaded" 4 | 5 | const formatBytes = (bytes, decimals = 2) => { 6 | if (bytes === 0) return '0 Bytes'; 7 | 8 | const k = 1024 9 | const dm = decimals < 0 ? 0 : decimals 10 | const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB"] 11 | const i = Math.floor(Math.log(bytes) / Math.log(k)) 12 | 13 | return ( 14 | parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i] 15 | ) 16 | } 17 | 18 | const updateStatus = (size) => { 19 | const text = `Pending Bytes to Upload: ${formatBytes(size)}` 20 | document.getElementById("size").innerHTML = text 21 | } 22 | 23 | const showSize = () => { 24 | const { files: fileElements } = document.getElementById('file') 25 | if (!fileElements.length) return; 26 | 27 | const files = Array.from(fileElements) 28 | const { size } = files 29 | .reduce((prev, next) => ({ size: prev.size + next.size }), { size: 0 }) 30 | 31 | bytesAmount = size 32 | updateStatus(size) 33 | 34 | // const interval = setInterval(() => { 35 | // console.count() 36 | // const result = bytesAmount - 5e6 37 | // bytesAmount = result < 0 ? 0 : result 38 | // updateStatus(bytesAmount) 39 | // if(bytesAmount === 0 ) clearInterval(interval) 40 | // }, 50) 41 | } 42 | 43 | const updateMessage = (message) => { 44 | const msg = document.getElementById('msg') 45 | msg.innerText = message 46 | 47 | msg.classList.add('alert', 'alert-success') 48 | setTimeout(() => (msg.hidden = true), 3000); 49 | 50 | } 51 | 52 | const showMessage = () => { 53 | const urlParams = new URLSearchParams(window.location.search) 54 | const serverMessage = urlParams.get('msg') 55 | if (!serverMessage) return; 56 | 57 | updateMessage(serverMessage) 58 | } 59 | 60 | const configureForm = (targetUrl) => { 61 | const form = document.getElementById("form") 62 | form.action = targetUrl 63 | } 64 | 65 | const onload = () => { 66 | showMessage() 67 | 68 | const ioClient = io.connect(API_URL, { withCredentials: false }) 69 | ioClient.on("connect", (msg) => { 70 | console.log('connected!', ioClient.id) 71 | const targetUrl = API_URL + `?socketId=${ioClient.id}` 72 | configureForm(targetUrl) 73 | }) 74 | 75 | ioClient.on(ON_UPLOAD_EVENT, (bytesReceived) => { 76 | console.log('received', bytesReceived) 77 | bytesAmount = bytesAmount - bytesReceived 78 | updateStatus(bytesAmount) 79 | }) 80 | 81 | updateStatus(0) 82 | 83 | } 84 | 85 | window.onload = onload 86 | window.showSize = showSize -------------------------------------------------------------------------------- /recorded/parte02/frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |

Uploading files using BusBoy

16 |
17 |
18 | 19 | 27 | 28 |
29 | 30 | 31 |
32 |
33 | 34 | 35 |
36 |
37 |
38 |
39 | 40 | --------------------------------------------------------------------------------