mirror of
https://github.com/nicotsx/ironmount.git
synced 2025-12-10 12:10:51 +01:00
feat(snapshots): list files in snapshots api
This commit is contained in:
@@ -8,10 +8,13 @@ import {
|
||||
listRepositoriesDto,
|
||||
listSnapshotsDto,
|
||||
listSnapshotsFilters,
|
||||
listSnapshotFilesDto,
|
||||
listSnapshotFilesQuery,
|
||||
type DeleteRepositoryDto,
|
||||
type GetRepositoryDto,
|
||||
type ListRepositoriesDto,
|
||||
type ListSnapshotsDto,
|
||||
type ListSnapshotFilesDto,
|
||||
} from "./repositories.dto";
|
||||
import { repositoriesService } from "./repositories.service";
|
||||
|
||||
@@ -68,4 +71,14 @@ export const repositoriesController = new Hono()
|
||||
c.header("Cache-Control", "max-age=30, stale-while-revalidate=300");
|
||||
|
||||
return c.json<ListSnapshotsDto>(response, 200);
|
||||
})
|
||||
.get("/:name/snapshots/:snapshotId/files", listSnapshotFilesDto, validator("query", listSnapshotFilesQuery), async (c) => {
|
||||
const { name, snapshotId } = c.req.param();
|
||||
const { path } = c.req.valid("query");
|
||||
|
||||
const result = await repositoriesService.listSnapshotFiles(name, snapshotId, path);
|
||||
|
||||
c.header("Cache-Control", "max-age=300, stale-while-revalidate=600");
|
||||
|
||||
return c.json<ListSnapshotFilesDto>(result, 200);
|
||||
});
|
||||
|
||||
@@ -164,3 +164,52 @@ export const listSnapshotsDto = describeRoute({
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* List files in a snapshot
|
||||
*/
|
||||
export const snapshotFileNodeSchema = type({
|
||||
name: "string",
|
||||
type: "string",
|
||||
path: "string",
|
||||
uid: "number?",
|
||||
gid: "number?",
|
||||
size: "number?",
|
||||
mode: "number?",
|
||||
mtime: "string?",
|
||||
atime: "string?",
|
||||
ctime: "string?",
|
||||
});
|
||||
|
||||
export const listSnapshotFilesResponse = type({
|
||||
snapshot: type({
|
||||
id: "string",
|
||||
short_id: "string",
|
||||
time: "string",
|
||||
hostname: "string",
|
||||
paths: "string[]",
|
||||
}),
|
||||
files: snapshotFileNodeSchema.array(),
|
||||
});
|
||||
|
||||
export type ListSnapshotFilesDto = typeof listSnapshotFilesResponse.infer;
|
||||
|
||||
export const listSnapshotFilesQuery = type({
|
||||
path: "string?",
|
||||
});
|
||||
|
||||
export const listSnapshotFilesDto = describeRoute({
|
||||
description: "List files and directories in a snapshot",
|
||||
tags: ["Repositories"],
|
||||
operationId: "listSnapshotFiles",
|
||||
responses: {
|
||||
200: {
|
||||
description: "List of files and directories in the snapshot",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(listSnapshotFilesResponse),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -134,10 +134,38 @@ const listSnapshots = async (name: string, volumeId?: number) => {
|
||||
return snapshots;
|
||||
};
|
||||
|
||||
const listSnapshotFiles = async (name: string, snapshotId: string, path?: string) => {
|
||||
const repository = await db.query.repositoriesTable.findFirst({
|
||||
where: eq(repositoriesTable.name, name),
|
||||
});
|
||||
|
||||
if (!repository) {
|
||||
throw new NotFoundError("Repository not found");
|
||||
}
|
||||
|
||||
const result = await restic.ls(repository.config, snapshotId, path);
|
||||
|
||||
if (!result.snapshot) {
|
||||
throw new NotFoundError("Snapshot not found or empty");
|
||||
}
|
||||
|
||||
return {
|
||||
snapshot: {
|
||||
id: result.snapshot.id,
|
||||
short_id: result.snapshot.short_id,
|
||||
time: result.snapshot.time,
|
||||
hostname: result.snapshot.hostname,
|
||||
paths: result.snapshot.paths,
|
||||
},
|
||||
files: result.nodes,
|
||||
};
|
||||
};
|
||||
|
||||
export const repositoriesService = {
|
||||
listRepositories,
|
||||
createRepository,
|
||||
getRepository,
|
||||
deleteRepository,
|
||||
listSnapshots,
|
||||
listSnapshotFiles,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user