add: endpoint /timeline & /frame/:id in backend server

improve: simplify the migration code
This commit is contained in:
alikia2x (寒寒) 2024-12-29 21:37:36 +08:00
parent fb70acab00
commit f53616f345
Signed by: alikia2x
GPG Key ID: 56209E0CCD8420C6
3 changed files with 78 additions and 20 deletions

View File

@ -12,26 +12,23 @@ function migrateTo(version: number, db: Database) {
}
}
function getVersion(db: Database): number {
const stmt = db.prepare(`SELECT value FROM config WHERE key = 'version';`);
const data = stmt.get() as { value: string };
const version = data.value;
return parseInt(version);
}
export function migrate(db: Database) {
const configTableExists =
db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='config';`).get()
!== undefined;
db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='config';`).get() !==
undefined;
if (!configTableExists) {
migrateToV2(db);
}
let databaseVersion = parseInt(
(
db.prepare(`SELECT value FROM config WHERE key = 'version';`).get() as
{ value: any }
).value
);
let databaseVersion = getVersion(db);
while (databaseVersion < CURRENT_VERSION) {
migrateTo(databaseVersion, db);
databaseVersion = parseInt(
(
db.prepare(`SELECT value FROM config WHERE key = 'version';`).get() as
{ value: any }
).value
);
databaseVersion = getVersion(db);
}
}

View File

@ -96,6 +96,7 @@ app.on("ready", () => {
setInterval(processEncodingTasks, 10000, db);
setInterval(deleteEncodedScreenshots, 5000, db);
dbConnection = db;
cache.put("server:dbConnection", dbConnection);
});
mainWindow = createMainWindow(port, () => (mainWindow = null));
settingsWindow = createSettingsWindow(port, () => (settingsWindow = null));
@ -107,6 +108,8 @@ app.on("ready", () => {
app.on("will-quit", () => {
dbConnection?.close();
if (screenshotInterval)
clearInterval(screenshotInterval);
});
// app.on("window-all-closed", () => {

View File

@ -1,17 +1,75 @@
import { Hono } from 'hono'
import { Hono } from "hono";
import cache from "memory-cache";
import { join } from "path";
import fs from "fs";
import { Database } from "better-sqlite3";
import type { Frame } from "../backend/schema";
import { getScreenshotsDir } from "../utils/backend.js";
const app = new Hono();
app.use(async (c, next) => {
const key = cache.get("server:APIKey");
if (key && c.req.header("x-api-key") !== key) {
c.res = undefined
c.res = undefined;
c.res = c.json({ error: "Invalid API key" }, 401);
}
await next();
})
});
app.get('/ping', (c) => c.text('pong'))
app.get("/ping", (c) => c.text("pong"));
app.get("/timeline", async (c) => {
const { offset = 0, limit = 50 } = c.req.query();
const db = cache.get("server:dbConnection");
const frames = db
.prepare(
`
SELECT id, createdAt, imgFilename, videoPath, videoFrameIndex
FROM frame
ORDER BY createdAt DESC
LIMIT ? OFFSET ?
`
)
.all(limit, offset);
return c.json(frames);
});
app.get("/frame/:id", async (c) => {
const { id } = c.req.param();
const db: Database = cache.get("server:dbConnection");
const frame = db
.prepare(
`
SELECT imgFilename, videoPath, videoFrameIndex
FROM frame
WHERE id = ?
`
)
.get(id) as Frame;
if (!frame) {
return c.json({ error: "Frame not found" }, 404);
}
// If frame is from video, decode and return frame
if (frame.videoPath) {
// TODO: Implement video frame extraction
return c.json({ error: "Video frame extraction not implemented" }, 501);
}
// Return image file
const imagePath = join(getScreenshotsDir(), frame.imgFilename);
const imageBuffer = fs.readFileSync(imagePath);
return new Response(imageBuffer, {
status: 200,
headers: {
"Content-Type": "image/png"
}
});
});
export default app;