v2: модульный монолит — очередь, персистентность, безопасность, SSE, тесты
Some checks failed
test / test (push) Failing after 24s
Some checks failed
test / test (push) Failing after 24s
Реализация целевого дизайна (docs/architecture/target-design.md): - src/: модульная структура (config, logger, errors, http, core: auth/history/jobs/engines/comfy/codex/images) - Очередь заданий: FIFO, кониурентность codex=1 / comfy-upscale=2, MAX_QUEUED_JOBS=5, JSONL-журнал и восстановление после рестарта (running → interrupted, upscale requeue) - Персистентные сессии (sha256-хеши токенов), scrypt-хеш пароля, rate-limit входа, Origin-проверка, magic-byte валидация аплоадов - Атомарная запись манифеста истории, каскадное удаление, URL с фактическим расширением + 302-алиас /image.jpg, миграция history/ → data/history - Даунскейл sharp до 1024px перед Codex + масштабирование области референса - SSE /api/events с фолбэком на polling, фронтенд переведён на ES-модули (public/js/) - Тесты node:test + supertest (27), CI workflow test.yml, Docker/деплой: том kadr-data - Документация: README, docs/architecture/
This commit is contained in:
71
src/core/images/sniff.js
Normal file
71
src/core/images/sniff.js
Normal file
@@ -0,0 +1,71 @@
|
||||
"use strict";
|
||||
|
||||
const PNG_SIGNATURE = "89504e470d0a1a0a";
|
||||
|
||||
const HEIC_BRANDS = new Set([
|
||||
"heic",
|
||||
"heix",
|
||||
"hevc",
|
||||
"hevx",
|
||||
"heim",
|
||||
"heis",
|
||||
"hevm",
|
||||
"hevs",
|
||||
"mif1",
|
||||
"msf1",
|
||||
"heif",
|
||||
]);
|
||||
|
||||
/**
|
||||
* Определяет тип изображения по сигнатуре первых байтов (magic bytes).
|
||||
* @param {Buffer} buffer
|
||||
* @returns {'jpeg' | 'png' | 'webp' | 'heic' | null}
|
||||
*/
|
||||
function sniffImageType(buffer) {
|
||||
if (!Buffer.isBuffer(buffer) || buffer.length < 12) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// JPEG: FF D8 FF
|
||||
if (buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) {
|
||||
return "jpeg";
|
||||
}
|
||||
|
||||
// PNG: 89 50 4E 47 0D 0A 1A 0A
|
||||
if (buffer.subarray(0, 8).toString("hex") === PNG_SIGNATURE) {
|
||||
return "png";
|
||||
}
|
||||
|
||||
// WebP: RIFF....WEBP
|
||||
if (
|
||||
buffer.toString("ascii", 0, 4) === "RIFF" &&
|
||||
buffer.toString("ascii", 8, 12) === "WEBP"
|
||||
) {
|
||||
return "webp";
|
||||
}
|
||||
|
||||
// HEIC / HEIF: ftyp box
|
||||
if (buffer.toString("ascii", 4, 8) === "ftyp") {
|
||||
const majorBrand = buffer.toString("ascii", 8, 12).toLowerCase();
|
||||
if (HEIC_BRANDS.has(majorBrand)) {
|
||||
return "heic";
|
||||
}
|
||||
|
||||
// Check compatible brands
|
||||
const boxLength = buffer.readUInt32BE(0);
|
||||
const limit = Math.min(buffer.length, boxLength > 0 ? boxLength : 64);
|
||||
for (let offset = 16; offset + 4 <= limit; offset += 4) {
|
||||
const brand = buffer.toString("ascii", offset, offset + 4).toLowerCase();
|
||||
if (HEIC_BRANDS.has(brand)) {
|
||||
return "heic";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sniffImageType,
|
||||
HEIC_BRANDS,
|
||||
};
|
||||
Reference in New Issue
Block a user