Skip to content

Commit

Permalink
Merge pull request #250 from kodadot/fix-enable-cache-again
Browse files Browse the repository at this point in the history
fix: enable cache again
  • Loading branch information
vikiival authored Feb 14, 2024
2 parents b34d139 + 1730069 commit b83f0e3
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 106 deletions.
210 changes: 106 additions & 104 deletions image/src/routes/ipfs.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Hono } from 'hono'
import { cors } from 'hono/cors'
import { cache } from 'hono/cache'
import { CACHE_DAY, Env } from '../utils/constants'
import { fetchIPFS } from '../utils/ipfs'
import { getImageByPath, ipfsToCFI } from '../utils/cloudflare-images'
Expand All @@ -9,130 +10,131 @@ import type { ResponseType } from '../utils/types'
const app = new Hono<{ Bindings: Env }>()

app.use('/*', cors({ origin: allowedOrigin }))
app.get('/*', async (c) => {
const { original } = c.req.query()
const isOriginal = original === 'true'
const isHead = c.req.method === 'HEAD'

const url = new URL(c.req.url)
const path = url.pathname.replace('/ipfs/', '')
const fullPath = `${path}${url.search}`

// TODO: check response from cache
// related issue: TypeError: Can't modify immutable headers.
// ----------------------------------------
let response = undefined
console.log('response', response)

// contruct r2 object
const objectName = `ipfs/${path}`
const object = await c.env.MY_BUCKET.get(objectName)
// TODO: check which one is faster to get mimeType from r2 or kv (probably kv, because only store mimeType string on kv)
const mimeType = object?.httpMetadata?.contentType
console.log('object', object)
console.log('mime type', mimeType)

// 1. check existing image on cf-images && !isOriginal
// ----------------------------------------
console.log('step 1')
if (mimeType?.includes('image') && !isOriginal && !isHead) {
const publicUrl = await getImageByPath({
token: c.env.IMAGE_API_TOKEN,
imageAccount: c.env.CF_IMAGE_ACCOUNT,
path: fullPath,
})
app.get(
'/*',
cache({
cacheName: 'ipfs-path',
cacheControl: 'max-age=86400, stale-while-revalidate=3600',
}),
async (c) => {
const { original } = c.req.query()
const isOriginal = original === 'true'
const isHead = c.req.method === 'HEAD'

const url = new URL(c.req.url)
const path = url.pathname.replace('/ipfs/', '')
const fullPath = `${path}${url.search}`

// contruct r2 object
const objectName = `ipfs/${path}`
const object = await c.env.MY_BUCKET.get(objectName)
// TODO: check which one is faster to get mimeType from r2 or kv (probably kv, because only store mimeType string on kv)
const mimeType = object?.httpMetadata?.contentType
console.log('object', object)
console.log('mime type', mimeType)

// 1. check existing image on cf-images && !isOriginal
// ----------------------------------------
console.log('step 1')
if (mimeType?.includes('image') && !isOriginal && !isHead) {
const publicUrl = await getImageByPath({
token: c.env.IMAGE_API_TOKEN,
imageAccount: c.env.CF_IMAGE_ACCOUNT,
path: fullPath,
})

if (publicUrl) {
return c.redirect(publicUrl)
if (publicUrl) {
return c.redirect(publicUrl)
}
}
}

// 2. check object from r2
// ----------------------------------------
console.log('step 2')
const renderR2Object = (r2Object: R2ObjectBody, mime?: string) => {
// add trailing slash for html
if (mime?.includes('html')) {
// add trailing slash
if (!url.pathname.endsWith('/')) {
return c.redirect(`${url.pathname}/${url.search}`)
// 2. check object from r2
// ----------------------------------------
console.log('step 2')
const renderR2Object = (r2Object: R2ObjectBody, mime?: string) => {
// add trailing slash for html
if (mime?.includes('html')) {
// add trailing slash
if (!url.pathname.endsWith('/')) {
return c.redirect(`${url.pathname}/${url.search}`)
}
}
}

const headers = new Headers()
r2Object.writeHttpMetadata(headers)
headers.set('etag', r2Object.httpEtag)
const headers = new Headers()
r2Object.writeHttpMetadata(headers)
headers.set('etag', r2Object.httpEtag)

const statusCode = c.req.raw.headers.get('range') !== null ? 206 : 200
const statusCode = c.req.raw.headers.get('range') !== null ? 206 : 200

response = new Response(r2Object.body, {
headers,
status: r2Object.body ? statusCode : 304,
})
const response = new Response(r2Object.body, {
headers,
status: r2Object.body ? statusCode : 304,
})

response.headers.append('cache-control', `s-maxage=${CACHE_DAY}`)
response.headers.append(
'content-range',
`bytes 0-${r2Object.size - 1}/${r2Object.size}`
)
response.headers.append('cache-control', `s-maxage=${CACHE_DAY}`)
response.headers.append(
'content-range',
`bytes 0-${r2Object.size - 1}/${r2Object.size}`
)

return response
}
return response
}

if (object !== null) {
return renderR2Object(object, mimeType)
}
if (object !== null) {
return renderR2Object(object, mimeType)
}

// 3. upload object to r2
// ----------------------------------------
console.log('step 3')
if (object === null) {
const status = await fetchIPFS({
path: fullPath,
gateway1: c.env.DEDICATED_GATEWAY,
gateway2: c.env.DEDICATED_BACKUP_GATEWAY,
})
// 3. upload object to r2
// ----------------------------------------
console.log('step 3')
if (object === null) {
const status = await fetchIPFS({
path: fullPath,
gateway1: c.env.DEDICATED_GATEWAY,
gateway2: c.env.DEDICATED_BACKUP_GATEWAY,
})

const contentLength = status.response?.headers.get('content-length')
const contentLength = status.response?.headers.get('content-length')

if (status.ok && status.response?.body && status.response?.headers) {
let body
if (status.ok && status.response?.body && status.response?.headers) {
let body

if (contentLength === null) {
body = await status.response?.text()
} else {
body = status.response.body as ResponseType
}
if (contentLength === null) {
body = await status.response?.text()
} else {
body = status.response.body as ResponseType
}

await c.env.MY_BUCKET.put(objectName, body, {
httpMetadata: status.response.headers,
})
await c.env.MY_BUCKET.put(objectName, body, {
httpMetadata: status.response.headers,
})
}
}
}

// 4. upload images to cf-images and return it if !isOriginal
// ----------------------------------------
console.log('step 4')
const imageUrl = await ipfsToCFI({
path,
token: c.env.IMAGE_API_TOKEN,
gateway: c.env.DEDICATED_GATEWAY,
imageAccount: c.env.CF_IMAGE_ACCOUNT,
})

if (imageUrl && !isOriginal && !isHead) {
return c.redirect(imageUrl)
}
// 4. upload images to cf-images and return it if !isOriginal
// ----------------------------------------
console.log('step 4')
const imageUrl = await ipfsToCFI({
path,
token: c.env.IMAGE_API_TOKEN,
gateway: c.env.DEDICATED_GATEWAY,
imageAccount: c.env.CF_IMAGE_ACCOUNT,
})

// 5. return object from r2
// ----------------------------------------
console.log('step 5')
const newObject = await c.env.MY_BUCKET.get(objectName)
if (imageUrl && !isOriginal && !isHead) {
return c.redirect(imageUrl)
}

// 5. return object from r2
// ----------------------------------------
console.log('step 5')
const newObject = await c.env.MY_BUCKET.get(objectName)

if (newObject !== null) {
return renderR2Object(newObject, newObject?.httpMetadata?.contentType)
if (newObject !== null) {
return renderR2Object(newObject, newObject?.httpMetadata?.contentType)
}
}
})
)

app.delete('/*', async (c) => {
const url = new URL(c.req.url)
Expand Down
4 changes: 2 additions & 2 deletions image/src/tests/ipfs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ test('ipfs - 302 - html', async () => {
expect(data).toMatchInlineSnapshot(`
Blob {
Symbol(kHandle): Blob {},
Symbol(kLength): 657,
Symbol(kLength): 656,
Symbol(kType): "text/html",
}
`)
Expand All @@ -136,7 +136,7 @@ test('ipfs - 200 - html', async () => {
expect(data).toMatchInlineSnapshot(`
Blob {
Symbol(kHandle): Blob {},
Symbol(kLength): 657,
Symbol(kLength): 656,
Symbol(kType): "text/html",
}
`)
Expand Down

0 comments on commit b83f0e3

Please sign in to comment.