-
-
Save 1amageek/a5142e9c229bafab78b75b9415efa2f6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as functions from "firebase-functions" | |
import express from "express" | |
import * as admin from "firebase-admin" | |
import sharp from "sharp" | |
const MAX_WIDTH = 1080 | |
const MAX_HEIGHT = 1080 | |
interface Size { | |
width: number | |
height: number | |
} | |
const app = express() | |
const router = express.Router() | |
const cacheControl = "public, max-age=3600, s-maxage=36000" | |
const parseSize = (size: string): Size => { | |
let width, height; | |
if (size.indexOf(",") !== -1) { | |
[width, height] = size.split(","); | |
} else if (size.indexOf("x") !== -1) { | |
[width, height] = size.split("x"); | |
} else { | |
throw new Error(`height and width are not delimited by a "," or a "x"`); | |
} | |
width = parseInt(width, 10) || MAX_WIDTH | |
height = parseInt(height, 10) || MAX_HEIGHT | |
width = Math.min(width, MAX_WIDTH) | |
height = Math.min(height, MAX_HEIGHT) | |
return { width, height } | |
} | |
router.get("/w/:width/*", async (req, res, next) => { | |
res.set("Cache-Control", cacheControl) | |
const { width } = req.params | |
let sizeWidth = parseInt(width, 10) || MAX_WIDTH | |
let sizeHeight = parseInt(width, 10) || MAX_WIDTH | |
sizeWidth = Math.min(sizeWidth, MAX_WIDTH) | |
sizeHeight = Math.min(sizeHeight, MAX_WIDTH) | |
const targetSize = { | |
width: sizeWidth, | |
height: sizeHeight | |
} | |
const path = req.params[0] | |
if (path.includes(".jpg") || path.includes(".jpeg") || path.includes(".png")) { | |
const bucket = admin.storage().bucket() | |
try { | |
const response = await bucket.file(path).download() | |
const originalImage = response[0] | |
if (path.includes(".jpg") || path.includes(".jpeg")) res.type("jpg") | |
if (path.includes(".png")) res.type("png") | |
const resizedImage = await sharp(originalImage) | |
.resize(targetSize.width, targetSize.height) | |
.toBuffer() | |
res.status(200).send(resizedImage) | |
} catch (error) { | |
next(error) | |
} | |
} | |
}) | |
router.get("/s/:size/*", async (req, res, next) => { | |
res.set("Cache-Control", cacheControl) | |
const { size } = req.params | |
const targetSize = parseSize(size) | |
const path = req.params[0] | |
if (path.includes(".jpg") || path.includes(".jpeg") || path.includes(".png")) { | |
const bucket = admin.storage().bucket() | |
try { | |
const response = await bucket.file(path).download() | |
const originalImage = response[0] | |
if (path.includes(".jpg") || path.includes(".jpeg")) res.type("jpg") | |
if (path.includes(".png")) res.type("png") | |
const resizedImage = await sharp(originalImage) | |
.resize(targetSize.width, targetSize.height) | |
.toBuffer() | |
res.status(200).send(resizedImage) | |
} catch (error) { | |
next(error) | |
} | |
} | |
}) | |
router.get("*", async (req, res, next) => { | |
res.set("Cache-Control", cacheControl) | |
const path = req.path.slice(1) | |
if (path.includes(".jpg") || path.includes(".jpeg") || path.includes(".png")) { | |
const bucket = admin.storage().bucket() | |
try { | |
const response = await bucket.file(path).download() | |
if (path.includes(".jpg") || path.includes(".jpeg")) res.type("jpg") | |
if (path.includes(".png")) res.type("png") | |
res.status(200).send(response[0]) | |
} catch (error) { | |
next(error) | |
} | |
} | |
}) | |
router.use((req, res, next) => { | |
const err = new Error("Not Found") | |
next(err) | |
}) | |
// error handler | |
router.use((req, res, next) => { | |
res.status(400).send("Bad Request") | |
}) | |
app.use("/cdn", router) | |
export const cdn = functions | |
.runWith({ | |
memory: "2GB" | |
}) | |
.https.onRequest(app) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment