feat: video upload - disable muse upload + upgrade server (#207)

* fix: only upload to cloudflare

* feat: ci/cd for apps/backend
This commit is contained in:
Rotimi Best
2024-03-16 06:27:09 +01:00
committed by GitHub
parent 18f37b1b66
commit 4893950fd2
5 changed files with 50 additions and 46 deletions
@@ -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 }}
+6 -6
View File
@@ -1,7 +1,7 @@
{ {
"name": "hellonode", "name": "backend",
"version": "1.0.0", "version": "0.0.1",
"description": "", "description": "Express Server for long processing",
"main": "server.js", "main": "server.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
@@ -10,14 +10,14 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/fly-examples/hellonode.git" "url": "git+https://github.com/rotimi-best/classroomio.git"
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"bugs": { "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": { "dependencies": {
"@aws-sdk/client-s3": "^3.388.0", "@aws-sdk/client-s3": "^3.388.0",
"@supabase/supabase-js": "^2.32.0", "@supabase/supabase-js": "^2.32.0",
+3 -3
View File
@@ -23,7 +23,7 @@ app.use(cors());
// Rate limiting middleware // Rate limiting middleware
const limiter = rateLimit({ const limiter = rateLimit({
windowMs: 1000, windowMs: 1000,
max: 10, max: 10
}); });
app.use(limiter); app.use(limiter);
@@ -34,9 +34,9 @@ app.use('/downloadCourse', downloadCourse);
app.use('/uploadVideo', uploadVideo); app.use('/uploadVideo', uploadVideo);
app.get('/', (req, res) => { app.get('/', (req, res) => {
res.send('Hello ClassroomIO'); res.send('Welcome to ClassroomIO');
}); });
app.listen(port, () => { app.listen(port, () => {
console.log(`HelloNode app listening on port ${port}!`); console.log(`ClassroomIO Backend listening on port ${port}!`);
}); });
+20 -32
View File
@@ -1,7 +1,6 @@
const express = require('express'); const express = require('express');
const FormData = require('form-data'); const FormData = require('form-data');
const axios = require('axios'); const axios = require('axios');
// const Queue = require('bull');
const { promisify } = require('util'); const { promisify } = require('util');
const fs = require('fs'); const fs = require('fs');
@@ -9,7 +8,7 @@ const unlinkAsync = promisify(fs.unlink);
const { const {
S3Client, S3Client,
PutObjectCommand, PutObjectCommand
// GetObjectCommand, // GetObjectCommand,
} = require('@aws-sdk/client-s3'); } = require('@aws-sdk/client-s3');
@@ -22,7 +21,7 @@ const {
CLOUDFLARE_SECRET_ACCESS_KEY, CLOUDFLARE_SECRET_ACCESS_KEY,
CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_ACCOUNT_ID,
CLOUDFLARE_PUBLIC_ACCOUNT_ID, CLOUDFLARE_PUBLIC_ACCOUNT_ID,
MUSE_API_KEY, MUSE_API_KEY
} = process.env; } = process.env;
const router = express.Router(); const router = express.Router();
@@ -32,8 +31,8 @@ const S3 = new S3Client({
endpoint: `https://${CLOUDFLARE_ACCOUNT_ID}.r2.cloudflarestorage.com`, endpoint: `https://${CLOUDFLARE_ACCOUNT_ID}.r2.cloudflarestorage.com`,
credentials: { credentials: {
accessKeyId: CLOUDFLARE_ACCESS_KEY, accessKeyId: CLOUDFLARE_ACCESS_KEY,
secretAccessKey: CLOUDFLARE_SECRET_ACCESS_KEY, secretAccessKey: CLOUDFLARE_SECRET_ACCESS_KEY
}, }
}); });
// const supabase = getSupabase(); // const supabase = getSupabase();
@@ -45,7 +44,7 @@ const S3 = new S3Client({
router.post('/', upload.single('videoFile'), async (req, res) => { router.post('/', upload.single('videoFile'), async (req, res) => {
const { const {
file, file,
query: { lessonId }, query: { lessonId }
} = req; } = req;
console.log('lessonId', lessonId); console.log('lessonId', lessonId);
console.log('file', file); console.log('file', file);
@@ -53,67 +52,56 @@ router.post('/', upload.single('videoFile'), async (req, res) => {
if (!file?.fieldname || !file?.fieldname) { if (!file?.fieldname || !file?.fieldname) {
return res.status(400).json({ return res.status(400).json({
success: false, 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({ return res.status(400).json({
success: false, success: false,
type: 'FILE_TOO_LARGE', type: 'FILE_TOO_LARGE',
message: 'File is too large', message: 'File is too large'
}); });
} }
const fileData = fs.readFileSync(file.path); const fileData = fs.readFileSync(file.path);
const fileName = `${genUniqueId()}-${file.originalname}`; const fileName = `${genUniqueId()}-${file.originalname.split(' ').join('-')}`;
const params = { const params = {
Bucket: 'videos', Bucket: 'videos',
Key: fileName, Key: fileName,
Body: fileData, Body: fileData
}; };
const fileUrl = `https://pub-${CLOUDFLARE_PUBLIC_ACCOUNT_ID}.r2.dev/${fileName}`; const fileUrl = `https://pub-${CLOUDFLARE_PUBLIC_ACCOUNT_ID}.r2.dev/${fileName}`;
let metadata = {}; let metadata = {};
try { try {
const s3Upload = S3.send(new PutObjectCommand(params)); console.log('Upload starting');
const museUpload = uploadToMuseNow(fileData, file.originalname); const s3UploadRes = await S3.send(new PutObjectCommand(params));
Promise.all([s3Upload, museUpload]).then((values) => {
const [s3UploadRes, museUploadRes] = values;
// Delete file saved by mutler in file
unlinkAsync(file.path);
console.log('s3UploadRes', s3UploadRes); console.log('s3UploadRes', s3UploadRes);
console.log('museUploadRes', museUploadRes);
if (museUploadRes.metadata) { unlinkAsync(file.path);
metadata = museUploadRes.metadata;
}
res.json({ res.json({
success: true, success: true,
url: fileUrl, url: fileUrl,
metadata, metadata,
message: 'Uploaded successfully', message: 'Uploaded successfully'
});
}); });
} catch (error) { } catch (error) {
// error handling. // error handling.
const { requestId, cfId, extendedRequestId } = error.$$metadata || {}; const { requestId, cfId, extendedRequestId } = error.$$metadata || {};
console.error('Error uploading file', error); console.error('Upload failed', error);
console.log({ requestId, cfId, extendedRequestId }); console.log({ requestId, cfId, extendedRequestId });
res.json({ res.json({
success: false, success: false,
message: 'Uploaded failed: ' + error, message: 'Uploaded failed: ' + error
}); });
} finally { } finally {
// finally. // finally.
console.log('File upload complete'); console.log('Upload complete');
// console.log('Add muse queue'); // console.log('Add muse queue');
// museUploadQueue.add({ // museUploadQueue.add({
@@ -144,12 +132,12 @@ async function uploadToMuseNow(fileData, fileName) {
maxContentLength: Infinity, maxContentLength: Infinity,
maxBodyLength: Infinity, maxBodyLength: Infinity,
headers: { headers: {
Key: MUSE_API_KEY, Key: MUSE_API_KEY
}, }
}); });
return { return {
metadata: response.data, metadata: response.data
}; };
} catch (error) { } catch (error) {
console.log('Upload to Muse failed', error?.response?.data); console.log('Upload to Muse failed', error?.response?.data);
View File