Skip to content

Commit

Permalink
feat: implement ipx image proxy + lru cache
Browse files Browse the repository at this point in the history
  • Loading branch information
ndom91 committed Aug 10, 2024
1 parent fc143e6 commit 0c105c6
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 39 deletions.
1 change: 1 addition & 0 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"hono-rate-limiter": "^0.4.0",
"ipx": "^3.0.1",
"jose": "^5.6.3",
"lru-cache": "^11.0.0",
"playwright-chromium": "^1.44.0",
"rss-parser": "^3.13.0",
"sharp": "^0.33.4",
Expand Down
50 changes: 16 additions & 34 deletions apps/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,51 +5,33 @@ import { logger } from "hono/logger"
import { prettyJSON } from "hono/pretty-json"
import { rateLimiter } from "hono-rate-limiter";

import {
createIPX,
createIPXWebServer,
ipxFSStorage,
ipxHttpStorage,
} from 'ipx';
import { updateJob } from "./jobs/cron-update.js"
import { imageProxyHandler } from "./lib/imageProxy.js"
import bookmark from "./routes/bookmark/index.js"
import feed from "./routes/feed/index.js"
import root from "./routes/root.js"
// import { ipxHandler } from "./lib/imageProxy.js"

const img = new Hono<{ Bindings: HttpBindings }>()
img.use("/*", imageProxyHandler)

const ipx = createIPX({
storage: ipxFSStorage(),
httpStorage: ipxHttpStorage({
allowAllDomains: true,
}),
});

const limiter = rateLimiter({
windowMs: 1 * 60 * 1000, // 5 minutes
limit: 5, // Limit each IP to 100 requests per `window`
standardHeaders: "draft-6",
keyGenerator: (c) => {
return c.req.header('X-Forwarded-For') || c.req.header('X-Real-IP') || c.req.header('CF-Connecting-IP') || '127.0.0.1'
}
});

const app = new Hono<{ Bindings: HttpBindings }>().basePath(
"/worker/v1",
)
const app = new Hono<{ Bindings: HttpBindings }>()
app.route('/img', img)

app.use(logger())
app.use(prettyJSON())
if (process.env.NODE_ENV === "production") {
app.use(limiter)
app.use(rateLimiter({
windowMs: 1 * 60 * 1000, // 1 minutes
limit: 25,
standardHeaders: "draft-6",
keyGenerator: (c) => {
return c.req.header('X-Forwarded-For') || c.req.header('X-Real-IP') || c.req.header('CF-Connecting-IP') || '127.0.0.1'
}
}))
}
app.use("/*", c => createIPXWebServer(ipx)(c.req.raw))

app.route("/bookmark", bookmark)
app.route("/feed", feed)
app.route("/", root)

app.get("*", c => c.notFound())
const BASE_PATH = "/worker/v1"
app.route(`${BASE_PATH}/bookmark`, bookmark)
app.route(`${BASE_PATH}/feed`, feed)

const port = process.env.PORT ? Number.parseInt(process.env.PORT) : 8000

Expand Down
36 changes: 32 additions & 4 deletions apps/backend/src/lib/imageProxy.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,46 @@
import { type Context } from "hono"
import {
createIPX,
createIPXWebServer,
ipxFSStorage,
ipxHttpStorage,
} from 'ipx';
import { LRUCache } from "lru-cache";

const ipx = createIPX({
storage: ipxFSStorage({ dir: './public/' }),
storage: ipxFSStorage(),
httpStorage: ipxHttpStorage({
allowAllDomains: true,
domains: ['images.unsplash.com']
}),
});

export const ipxHandler = createIPXWebServer(ipx)
const cache = new LRUCache({
max: 200,
});

export const imageProxyHandler = async (c: Context) => {
const targetUrl = c.req.raw.url.replace(/\/img/, "")

const cachedResponse = cache.get(targetUrl)
if (cachedResponse) {
return new Response(cachedResponse as Blob, {
status: 200,
headers: {
"x-cache": "HIT",
"Content-Type": "image/jpeg",
'cache-control': 'max-age=31536000, public, s-maxage=31536000',
},
})
}

const response = await createIPXWebServer(ipx)(new Request(targetUrl))

const clonedResponse = response.clone()
const data = await clonedResponse.blob()
cache.set(targetUrl, data)

// const app = new Hono().use('/', (c) => createIPXWebServer(ipx)(c.req.raw));
return new Response(response.body, {
status: response.status,
statusText: response.statusText
})
}
15 changes: 14 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 0c105c6

Please sign in to comment.