board backups to R2
This commit is contained in:
parent
c2abfcd3e3
commit
acc12363be
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
export interface Environment {
|
||||
TLDRAW_BUCKET: R2Bucket
|
||||
BOARD_BACKUPS_BUCKET: R2Bucket
|
||||
TLDRAW_DURABLE_OBJECT: DurableObjectNamespace
|
||||
DAILY_API_KEY: string;
|
||||
DAILY_DOMAIN: string;
|
||||
|
|
|
|||
|
|
@ -180,5 +180,61 @@ const router = AutoRouter<IRequest, [env: Environment, ctx: ExecutionContext]>({
|
|||
}
|
||||
})
|
||||
|
||||
async function backupAllBoards(env: Environment) {
|
||||
try {
|
||||
// List all room files from TLDRAW_BUCKET
|
||||
const roomsList = await env.TLDRAW_BUCKET.list({ prefix: 'rooms/' })
|
||||
|
||||
const date = new Date().toISOString().split('T')[0]
|
||||
|
||||
// Process each room
|
||||
for (const room of roomsList.objects) {
|
||||
try {
|
||||
// Get the room data
|
||||
const roomData = await env.TLDRAW_BUCKET.get(room.key)
|
||||
if (!roomData) continue
|
||||
|
||||
// Get the data as text since it's already stringified JSON
|
||||
const jsonData = await roomData.text()
|
||||
|
||||
// Create backup key with date only
|
||||
const backupKey = `${date}/${room.key}`
|
||||
|
||||
// Store in backup bucket as JSON
|
||||
await env.BOARD_BACKUPS_BUCKET.put(backupKey, jsonData)
|
||||
|
||||
console.log(`Backed up ${room.key} to ${backupKey}`)
|
||||
} catch (error) {
|
||||
console.error(`Failed to backup room ${room.key}:`, error)
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up old backups (keep last 30 days)
|
||||
const thirtyDaysAgo = new Date()
|
||||
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30)
|
||||
|
||||
const oldBackups = await env.BOARD_BACKUPS_BUCKET.list({
|
||||
prefix: thirtyDaysAgo.toISOString().split('T')[0]
|
||||
})
|
||||
|
||||
for (const backup of oldBackups.objects) {
|
||||
await env.BOARD_BACKUPS_BUCKET.delete(backup.key)
|
||||
}
|
||||
|
||||
return { success: true, message: 'Backup completed successfully' }
|
||||
} catch (error) {
|
||||
console.error('Backup failed:', error)
|
||||
return { success: false, message: (error as Error).message }
|
||||
}
|
||||
}
|
||||
|
||||
router
|
||||
.get("/backup", async (_, env) => {
|
||||
const result = await backupAllBoards(env)
|
||||
return new Response(JSON.stringify(result), {
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
})
|
||||
})
|
||||
|
||||
// export our router for cloudflare
|
||||
export default router
|
||||
|
|
|
|||
|
|
@ -27,6 +27,15 @@ binding = 'TLDRAW_BUCKET'
|
|||
bucket_name = 'jeffemmett-canvas'
|
||||
preview_bucket_name = 'jeffemmett-canvas-preview'
|
||||
|
||||
[[r2_buckets]]
|
||||
binding = 'BOARD_BACKUPS_BUCKET'
|
||||
bucket_name = 'board-backups'
|
||||
preview_bucket_name = 'board-backups-preview'
|
||||
|
||||
[observability]
|
||||
enabled = true
|
||||
head_sampling_rate = 1
|
||||
head_sampling_rate = 1
|
||||
|
||||
[triggers]
|
||||
crons = ["0 0 * * *"] # Run at midnight UTC every day
|
||||
# crons = ["*/10 * * * *"] # Run every 10 minutes
|
||||
Loading…
Reference in New Issue