diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6b09517 --- /dev/null +++ b/.gitignore @@ -0,0 +1,52 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +_.env +.env*.local +.env.dev +.env +.env.production +.env.staging +.env.development +.env.master +key.json +key.txt +sec-push.sh + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# other branches +/dev-branch + +# other +output.txt +test.js \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..6aa16d1 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "trailingComma": "es5", + "tabWidth": 4, + "semi": true, + "singleQuote": false, + "endOfLine": "lf" +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e6240fb --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# symposia-video + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run index.js +``` + +This project was created using `bun init` in bun v1.0.30. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..a73a26b Binary files /dev/null and b/bun.lockb differ diff --git a/cspell.json b/cspell.json new file mode 100644 index 0000000..e7eb5e1 --- /dev/null +++ b/cspell.json @@ -0,0 +1,12 @@ +{ + "version": "0.2", + "ignorePaths": [], + "dictionaryDefinitions": [], + "dictionaries": [], + "words": [ + "Filip", + "Niklas" + ], + "ignoreWords": [], + "import": [] +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..e5776cf --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "caravan", + "version": "0.0.1", + "description": "storage server for symposia", + "scripts": { + "start": "bun run src/index.ts", + "dev": "bun --watch src/index.ts" + }, + "author": "Filip Niklas", + "license": "MIT", + "dependencies": { + "@google-cloud/storage": "^7.11.0", + "@types/express": "^4.17.21", + "@types/node": "^20.12.12", + "dotenv": "^16.4.5", + "express": "^4.19.2", + "typescript": "^5.4.5" + }, + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + } +} \ No newline at end of file diff --git a/src/bucket.ts b/src/bucket.ts new file mode 100644 index 0000000..dcbe8f8 --- /dev/null +++ b/src/bucket.ts @@ -0,0 +1,38 @@ +import { Storage, type GetSignedUrlConfig } from "@google-cloud/storage"; + +const storage = new Storage(); + +const PRIMARY_BUCKET_NAME = process.env.GCP_PRIMARY_BUCKET_NAME ?? "invalid"; +const SECONDARY_BUCKET_NAME = + process.env.GCP_SECONDARY_BUCKET_NAME ?? "invalid"; + +/** + * Storage bucket reference instance. Call methods on this object to interact with the bucket. + * @see https://cloud.google.com/nodejs/docs/reference/storage/latest + */ +export const primaryBucket = storage.bucket(PRIMARY_BUCKET_NAME); +export const secondaryBucket = storage.bucket(SECONDARY_BUCKET_NAME); + +// export async function TestBucket() { +// const sa = await storage.getProjectId(); +// console.log(sa); +// const a = await storage.getServiceAccount(); +// console.log(a); +// } + +export async function gcGenerateReadSignedUrl({ + fileName, + id, +}: { + fileName: string; + id: string; +}) { + const filePath = `video/${id}/${fileName}`; + const options: GetSignedUrlConfig = { + version: "v4", + action: "read", + expires: Date.now() + 15 * 60 * 1000, // 15 minutes + }; + const [url] = await primaryBucket.file(filePath).getSignedUrl(options); + return url; +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..b53376d --- /dev/null +++ b/src/index.ts @@ -0,0 +1,28 @@ +import express, { type Express, type Request, type Response } from "express"; +import dotenv from "dotenv"; +import { gcGenerateReadSignedUrl } from "./bucket"; + +dotenv.config(); + +const app: Express = express(); +const port = process.env.PORT || 3000; + +app.get("/", async (req: Request, res: Response) => { + const fileName = "VID_20200103_135115.mp4"; + const id = "cluvqhyly0007uwfdmg2hn33a"; + const url = await gcGenerateReadSignedUrl({ fileName, id }); + res.send(url); +}); + +app.get("/:id/:filename", async (req: Request, res: Response) => { + const fileName = req.params.filename; + const id = req.params.id; + const url = await gcGenerateReadSignedUrl({ fileName, id }); + res.send(url); +}); + +app.listen(port, () => { + console.log(`Server listening on port ${port}`); +}); + +// http://localhost:3000/cluvqhyly0007uwfdmg2hn33a/VID_20200103_135115.mp4 diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..0fef23a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +}