1
0
Fork 0
freesewing/sites/backend/src/utils/cloudflare-images.mjs

133 lines
3.7 KiB
JavaScript

import axios from 'axios'
import { Blob } from 'node:buffer'
import { log } from './log.mjs'
import { cloudflareImages as config } from '../config.mjs'
// We'll use this a bunch
const headers = { Authorization: `Bearer ${config.token}` }
/*
* Method that does the actual image upload to cloudflare
* Use this for a new image that does not yet exist
*/
export async function storeImage(props, isTest = false) {
if (isTest) return props.id || false
const form = getFormData(props)
let result
try {
result = await axios.post(config.api, form, { headers })
} catch (err) {
if (err.response.status == 409) {
/*
* Image already exists.
* Cloudflare does not support udating the image,
* so we need to delete it and upload again
*/
try {
log.warn(props.id, 'Called storeImage when replaceImage should have been used')
await axios.delete(`${config.api}/${props.id}`)
result = await axios.post(config.api, form, { headers })
} catch (err) {
console.log('Failed to replace image on cloudflare', err)
}
} else {
console.log('Failed to upload image to cloudflare', err)
}
}
return result.data?.result?.id ? result.data.result.id : false
}
/*
* Method that does the actual image upload to cloudflare
* Use this to replace an existing image
*/
export async function replaceImage(props, isTest = false) {
if (isTest) return props.id || false
const form = getFormData(props)
// Ignore errors on delete, probably means the image does not exist
try {
await axios.delete(`${config.api}/${props.id}`)
} catch (err) {
// It's fine
log.info(`Could not delete image ${props.id}`)
}
let result
try {
result = await axios.post(config.api, form, { headers })
} catch (err) {
console.log('Failed to replace image on cloudflare', err)
}
return result.data?.result?.id ? result.data.result.id : false
}
/*
* Method that uploads an image to cloudflare
* Use this to merely ensure the image exists (will fail silently if it does)
*/
export async function ensureImage(props, isTest = false) {
if (isTest) return props.id || false
const form = getFormData(props)
try {
await axios.post(config.api, form, { headers })
} catch (err) {
// It's fine
console.log(err)
}
return props.id
}
/*
* Method that imports and image from URL and does not bother waiting for the answer
*/
export async function importImage(props, isTest = false) {
if (isTest) return props.id || false
// Bypass slow ass upload when testing import
if (!config.import) return `default-avatar`
// Only upload user images for now
if (props.id.slice(0, 5) !== 'user-') return `default-avatar`
const form = getFormData(props)
/*
* The image may already exist, so swallow the error
*/
try {
await axios.post(config.api, form, { headers })
} catch {
// Do nothing
}
console.log('Imported img', props.id)
return props.id
}
/*
* Helper method to construct the form data for cloudflare
*/
function getFormData({ id, metadata, url = false, b64 = false, blob = false, notPublic = false }) {
const form = new FormData()
form.append('id', id)
form.append('metadata', JSON.stringify(metadata))
// Handle base-64 encoded data
if (b64) form.append('file', b64ToBlob(b64), id)
// Handle binary data
else if (blob) form.append('file', blob)
// Handle URL-based upload
else if (url) form.append('url', url)
// Handle requireSignedURLs
if (notPublic) form.append('requireSignedURLs', true)
return form
}
/*
* Helper method to turn a data-uri into binary data
*/
function b64ToBlob(dataUri) {
return new Blob([new Buffer.from(dataUri.split(';base64,').pop(), 'base64')])
}