From 4893950fd224ce61176c10b020096937f3d19079 Mon Sep 17 00:00:00 2001 From: Rotimi Best Date: Sat, 16 Mar 2024 06:27:09 +0100 Subject: [PATCH] feat: video upload - disable muse upload + upgrade server (#207) * fix: only upload to cloudflare * feat: ci/cd for apps/backend --- .github/workflows/deploy-backend-on-push.yml | 16 +++++ apps/backend/package.json | 12 ++-- apps/backend/server.js | 6 +- apps/backend/src/routes/uploadVideo.js | 62 ++++++++------------ apps/backend/uploads/.empty | 0 5 files changed, 50 insertions(+), 46 deletions(-) create mode 100644 .github/workflows/deploy-backend-on-push.yml create mode 100644 apps/backend/uploads/.empty diff --git a/.github/workflows/deploy-backend-on-push.yml b/.github/workflows/deploy-backend-on-push.yml new file mode 100644 index 00000000..afd7f3f0 --- /dev/null +++ b/.github/workflows/deploy-backend-on-push.yml @@ -0,0 +1,16 @@ +name: Deloy Backend to Flyio +on: + push: + branches: + - main +jobs: + deploy: + name: Deploy backend + runs-on: ubuntu-latest + concurrency: deploy-group # optional: ensure only one action runs at a time + steps: + - uses: actions/checkout@v4 + - uses: superfly/flyctl-actions/setup-flyctl@master + - run: flyctl deploy --remote-only + env: + FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} diff --git a/apps/backend/package.json b/apps/backend/package.json index 01bce975..c1cfc28b 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -1,7 +1,7 @@ { - "name": "hellonode", - "version": "1.0.0", - "description": "", + "name": "backend", + "version": "0.0.1", + "description": "Express Server for long processing", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", @@ -10,14 +10,14 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/fly-examples/hellonode.git" + "url": "git+https://github.com/rotimi-best/classroomio.git" }, "author": "", "license": "ISC", "bugs": { - "url": "https://github.com/fly-examples/hellonode/issues" + "url": "https://github.com/rotimi-best/classroomio/issues" }, - "homepage": "https://github.com/fly-examples/hellonode#readme", + "homepage": "https://github.com/rotimi-best/classroomio#readme", "dependencies": { "@aws-sdk/client-s3": "^3.388.0", "@supabase/supabase-js": "^2.32.0", diff --git a/apps/backend/server.js b/apps/backend/server.js index 81b9f6c5..09142fe6 100644 --- a/apps/backend/server.js +++ b/apps/backend/server.js @@ -23,7 +23,7 @@ app.use(cors()); // Rate limiting middleware const limiter = rateLimit({ windowMs: 1000, - max: 10, + max: 10 }); app.use(limiter); @@ -34,9 +34,9 @@ app.use('/downloadCourse', downloadCourse); app.use('/uploadVideo', uploadVideo); app.get('/', (req, res) => { - res.send('Hello ClassroomIO'); + res.send('Welcome to ClassroomIO'); }); app.listen(port, () => { - console.log(`HelloNode app listening on port ${port}!`); + console.log(`ClassroomIO Backend listening on port ${port}!`); }); diff --git a/apps/backend/src/routes/uploadVideo.js b/apps/backend/src/routes/uploadVideo.js index 5b9fcf28..71e2569e 100644 --- a/apps/backend/src/routes/uploadVideo.js +++ b/apps/backend/src/routes/uploadVideo.js @@ -1,7 +1,6 @@ const express = require('express'); const FormData = require('form-data'); const axios = require('axios'); -// const Queue = require('bull'); const { promisify } = require('util'); const fs = require('fs'); @@ -9,7 +8,7 @@ const unlinkAsync = promisify(fs.unlink); const { S3Client, - PutObjectCommand, + PutObjectCommand // GetObjectCommand, } = require('@aws-sdk/client-s3'); @@ -22,7 +21,7 @@ const { CLOUDFLARE_SECRET_ACCESS_KEY, CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_PUBLIC_ACCOUNT_ID, - MUSE_API_KEY, + MUSE_API_KEY } = process.env; const router = express.Router(); @@ -32,8 +31,8 @@ const S3 = new S3Client({ endpoint: `https://${CLOUDFLARE_ACCOUNT_ID}.r2.cloudflarestorage.com`, credentials: { accessKeyId: CLOUDFLARE_ACCESS_KEY, - secretAccessKey: CLOUDFLARE_SECRET_ACCESS_KEY, - }, + secretAccessKey: CLOUDFLARE_SECRET_ACCESS_KEY + } }); // const supabase = getSupabase(); @@ -45,7 +44,7 @@ const S3 = new S3Client({ router.post('/', upload.single('videoFile'), async (req, res) => { const { file, - query: { lessonId }, + query: { lessonId } } = req; console.log('lessonId', lessonId); console.log('file', file); @@ -53,67 +52,56 @@ router.post('/', upload.single('videoFile'), async (req, res) => { if (!file?.fieldname || !file?.fieldname) { return res.status(400).json({ success: false, - message: 'You must provide a file to upload', + message: 'You must provide a file to upload' }); } - if (file?.size > 30 * 1024 * 1024) { + if (file?.size > 1000 * 1024 * 1024) { return res.status(400).json({ success: false, type: 'FILE_TOO_LARGE', - message: 'File is too large', + message: 'File is too large' }); } const fileData = fs.readFileSync(file.path); - const fileName = `${genUniqueId()}-${file.originalname}`; + const fileName = `${genUniqueId()}-${file.originalname.split(' ').join('-')}`; const params = { Bucket: 'videos', Key: fileName, - Body: fileData, + Body: fileData }; const fileUrl = `https://pub-${CLOUDFLARE_PUBLIC_ACCOUNT_ID}.r2.dev/${fileName}`; let metadata = {}; try { - const s3Upload = S3.send(new PutObjectCommand(params)); - const museUpload = uploadToMuseNow(fileData, file.originalname); + console.log('Upload starting'); + const s3UploadRes = await S3.send(new PutObjectCommand(params)); + console.log('s3UploadRes', s3UploadRes); - Promise.all([s3Upload, museUpload]).then((values) => { - const [s3UploadRes, museUploadRes] = values; + unlinkAsync(file.path); - // Delete file saved by mutler in file - unlinkAsync(file.path); - - console.log('s3UploadRes', s3UploadRes); - console.log('museUploadRes', museUploadRes); - - if (museUploadRes.metadata) { - metadata = museUploadRes.metadata; - } - - res.json({ - success: true, - url: fileUrl, - metadata, - message: 'Uploaded successfully', - }); + res.json({ + success: true, + url: fileUrl, + metadata, + message: 'Uploaded successfully' }); } catch (error) { // error handling. const { requestId, cfId, extendedRequestId } = error.$$metadata || {}; - console.error('Error uploading file', error); + console.error('Upload failed', error); console.log({ requestId, cfId, extendedRequestId }); res.json({ success: false, - message: 'Uploaded failed: ' + error, + message: 'Uploaded failed: ' + error }); } finally { // finally. - console.log('File upload complete'); + console.log('Upload complete'); // console.log('Add muse queue'); // museUploadQueue.add({ @@ -144,12 +132,12 @@ async function uploadToMuseNow(fileData, fileName) { maxContentLength: Infinity, maxBodyLength: Infinity, headers: { - Key: MUSE_API_KEY, - }, + Key: MUSE_API_KEY + } }); return { - metadata: response.data, + metadata: response.data }; } catch (error) { console.log('Upload to Muse failed', error?.response?.data); diff --git a/apps/backend/uploads/.empty b/apps/backend/uploads/.empty new file mode 100644 index 00000000..e69de29b