core: improve file cleanup by extracting timestamp logic from ID and using Bun.Glob for efficient file scanning
parent
df4a973891
commit
f82f9221e6
|
|
@ -71,4 +71,12 @@ export namespace Identifier {
|
|||
|
||||
return prefixes[prefix] + "_" + timeBytes.toString("hex") + randomBase62(LENGTH - 12)
|
||||
}
|
||||
|
||||
/** Extract timestamp from an ascending ID. Does not work with descending IDs. */
|
||||
export function timestamp(id: string): number {
|
||||
const prefix = id.split("_")[0]
|
||||
const hex = id.slice(prefix.length + 1, prefix.length + 13)
|
||||
const encoded = BigInt("0x" + hex)
|
||||
return Number(encoded / BigInt(0x1000))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import fs from "fs/promises"
|
|||
import path from "path"
|
||||
import { Global } from "../global"
|
||||
import { Identifier } from "../id/id"
|
||||
import { iife } from "../util/iife"
|
||||
import { lazy } from "../util/lazy"
|
||||
import { PermissionNext } from "../permission/next"
|
||||
import type { Agent } from "../agent/agent"
|
||||
|
|
@ -25,20 +24,17 @@ export namespace Truncate {
|
|||
direction?: "head" | "tail"
|
||||
}
|
||||
|
||||
const init = lazy(async () => {
|
||||
const cutoff = Date.now() - RETENTION_MS
|
||||
const entries = await fs.readdir(DIR).catch(() => [] as string[])
|
||||
export async function cleanup() {
|
||||
const cutoff = Identifier.timestamp(Identifier.create("tool", false, Date.now() - RETENTION_MS))
|
||||
const glob = new Bun.Glob("tool_*")
|
||||
const entries = await Array.fromAsync(glob.scan({ cwd: DIR, onlyFiles: true })).catch(() => [] as string[])
|
||||
for (const entry of entries) {
|
||||
if (!entry.startsWith("tool_")) continue
|
||||
const timestamp = iife(() => {
|
||||
const hex = entry.slice(5, 17)
|
||||
const now = BigInt("0x" + hex)
|
||||
return Number(now / BigInt(0x1000))
|
||||
})
|
||||
if (timestamp >= cutoff) continue
|
||||
await fs.rm(path.join(DIR, entry), { force: true }).catch(() => {})
|
||||
if (Identifier.timestamp(entry) >= cutoff) continue
|
||||
await fs.unlink(path.join(DIR, entry)).catch(() => {})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const init = lazy(cleanup)
|
||||
|
||||
function hasTaskTool(agent?: Agent.Info): boolean {
|
||||
if (!agent?.permission) return false
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { describe, test, expect } from "bun:test"
|
||||
import { describe, test, expect, afterAll } from "bun:test"
|
||||
import { Truncate } from "../../src/tool/truncation"
|
||||
import { Identifier } from "../../src/id/id"
|
||||
import fs from "fs/promises"
|
||||
import path from "path"
|
||||
|
||||
const FIXTURES_DIR = path.join(import.meta.dir, "fixtures")
|
||||
|
|
@ -117,4 +119,39 @@ describe("Truncate", () => {
|
|||
expect(result.outputPath).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("cleanup", () => {
|
||||
const DAY_MS = 24 * 60 * 60 * 1000
|
||||
let oldFile: string
|
||||
let recentFile: string
|
||||
|
||||
afterAll(async () => {
|
||||
await fs.unlink(oldFile).catch(() => {})
|
||||
await fs.unlink(recentFile).catch(() => {})
|
||||
})
|
||||
|
||||
test("deletes files older than 7 days and preserves recent files", async () => {
|
||||
await fs.mkdir(Truncate.DIR, { recursive: true })
|
||||
|
||||
// Create an old file (10 days ago)
|
||||
const oldTimestamp = Date.now() - 10 * DAY_MS
|
||||
const oldId = Identifier.create("tool", false, oldTimestamp)
|
||||
oldFile = path.join(Truncate.DIR, oldId)
|
||||
await Bun.write(Bun.file(oldFile), "old content")
|
||||
|
||||
// Create a recent file (3 days ago)
|
||||
const recentTimestamp = Date.now() - 3 * DAY_MS
|
||||
const recentId = Identifier.create("tool", false, recentTimestamp)
|
||||
recentFile = path.join(Truncate.DIR, recentId)
|
||||
await Bun.write(Bun.file(recentFile), "recent content")
|
||||
|
||||
await Truncate.cleanup()
|
||||
|
||||
// Old file should be deleted
|
||||
expect(await Bun.file(oldFile).exists()).toBe(false)
|
||||
|
||||
// Recent file should still exist
|
||||
expect(await Bun.file(recentFile).exists()).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue