refactor: decouple mail states from gzip

This commit is contained in:
dreamhunter2333
2026-08-26 00:28:33 +08:00
parent b809a5489f
commit fe73bbc54c
6 changed files with 22 additions and 23 deletions
+3 -2
View File
@@ -2,6 +2,7 @@ import { Context } from "hono";
import { handleMailListQuery } from "../common";
import { resolveRawEmailRow } from "../gzip";
import { getBooleanValue } from "../utils";
import { serializeMailState } from "../mail_flags";
export default {
getMails: async (c: Context<HonoCustomType>) => {
@@ -32,8 +33,8 @@ export default {
`SELECT * FROM raw_mails WHERE id = ?`
).bind(id).first();
if (!result) return c.json(null);
return c.json(await resolveRawEmailRow(
result,
return c.json(serializeMailState(
await resolveRawEmailRow(result),
getBooleanValue(c.env.ENABLE_MAIL_FLAGS),
));
},
+6 -4
View File
@@ -7,6 +7,7 @@ import { unbindTelegramByAddress } from './telegram_api/common';
import { CONSTANTS } from './constants';
import { AddressCreationSettings, AdminWebhookSettings, ExtractResult, WebhookMail, WebhookSettings } from './models';
import i18n from './i18n';
import { serializeMailState } from './mail_flags';
const DEFAULT_NAME_REGEX = /[^a-z0-9]/g;
const DEFAULT_RANDOM_SUBDOMAIN_LENGTH = 8;
@@ -720,14 +721,15 @@ export const handleMailListQuery = async (
const { results } = await c.env.DB.prepare(resultsQuery).bind(
...params, limit, offset
).all();
const resolvedResults = await resolveRawEmailList(
results,
const resolvedResults = await resolveRawEmailList(results);
const serializedResults = resolvedResults.map(row => serializeMailState(
row,
getBooleanValue(c.env.ENABLE_MAIL_FLAGS),
);
));
const count = offset == 0 ? await c.env.DB.prepare(
countQuery
).bind(...params).first("count") : 0;
return c.json({ results: resolvedResults, count });
return c.json({ results: serializedResults, count });
}
export const commonParseMail = async (parsedEmailContext: ParsedEmailContext): Promise<{
+4 -11
View File
@@ -4,7 +4,6 @@
*/
import { RawMailRow } from "./models";
import { serializeMailState } from "./mail_flags";
export async function compressText(text: string): Promise<ArrayBuffer> {
const stream = new Blob([text]).stream().pipeThrough(new CompressionStream('gzip'));
@@ -35,21 +34,15 @@ export async function resolveRawEmail(row: RawMailRow): Promise<string> {
/**
* Resolve a single row: decompress raw_blob if present, strip raw_blob from result.
*/
export async function resolveRawEmailRow(
row: RawMailRow,
enableMailStates = false,
): Promise<RawMailRow> {
export async function resolveRawEmailRow(row: RawMailRow): Promise<RawMailRow> {
const raw = await resolveRawEmail(row);
const { raw_blob: _, ...rest } = row;
return serializeMailState({ ...rest, raw }, enableMailStates);
return { ...rest, raw };
}
/**
* Batch resolve raw emails for list queries using Promise.all.
*/
export async function resolveRawEmailList(
rows: RawMailRow[],
enableMailStates = false,
): Promise<RawMailRow[]> {
return Promise.all(rows.map(row => resolveRawEmailRow(row, enableMailStates)));
export async function resolveRawEmailList(rows: RawMailRow[]): Promise<RawMailRow[]> {
return Promise.all(rows.map(row => resolveRawEmailRow(row)));
}
+3 -2
View File
@@ -9,6 +9,7 @@ import {
getMailStateQuery,
getMailStateOptions,
applyMailStateUpdate,
serializeMailState,
} from '../mail_flags';
const listMails = async (c: Context<HonoCustomType>) => {
@@ -45,8 +46,8 @@ const getMail = async (c: Context<HonoCustomType>) => {
`SELECT * FROM raw_mails where id = ? and address = ?`
).bind(mail_id, address).first();
if (!result) return c.json(null);
return c.json(await resolveRawEmailRow(
result,
return c.json(serializeMailState(
await resolveRawEmailRow(result),
getBooleanValue(c.env.ENABLE_MAIL_FLAGS),
));
};
+3 -2
View File
@@ -3,6 +3,7 @@ import { Context } from 'hono'
import { commonParseMail, handleMailListQuery, updateAddressUpdatedAt } from '../common'
import { resolveRawEmailRow } from '../gzip'
import { getBooleanValue } from '../utils';
import { serializeMailState } from '../mail_flags';
const toParsedMailRow = async (row: Record<string, unknown>): Promise<Record<string, unknown>> => {
const raw = typeof row.raw === 'string' ? row.raw : '';
@@ -46,8 +47,8 @@ const getParsedMail = async (c: Context<HonoCustomType>) => {
`SELECT * FROM raw_mails where id = ? and address = ?`
).bind(mail_id, address).first();
if (!row) return c.json(null);
const resolved = await resolveRawEmailRow(
row,
const resolved = serializeMailState(
await resolveRawEmailRow(row),
getBooleanValue(c.env.ENABLE_MAIL_FLAGS),
);
return c.json(await toParsedMailRow(resolved));
+3 -2
View File
@@ -6,6 +6,7 @@ import { checkCfTurnstile, checkIsAdmin, getBooleanValue } from "../utils";
import { resolveRawEmailRow } from "../gzip";
import { TelegramSettings } from "./settings";
import i18n from "../i18n";
import { serializeMailState } from "../mail_flags";
const encoder = new TextEncoder();
const TG_AUTH_TIMEOUT = 300;
@@ -145,7 +146,7 @@ async function getMail(c: Context<HonoCustomType>): Promise<Response> {
if (!result) {
return c.text("Mail not found", 404);
}
return c.json(await resolveRawEmailRow(result));
return c.json(serializeMailState(await resolveRawEmailRow(result), false));
}
const userId = await checkTelegramAuth(c, initData);
const jwtList = await c.env.KV.get<string[]>(`${CONSTANTS.TG_KV_PREFIX}:${userId}`, 'json') || [];
@@ -168,7 +169,7 @@ async function getMail(c: Context<HonoCustomType>): Promise<Response> {
return c.text(msgs.TgNoPermissionViewMailMsg, 403);
}
}
return c.json(await resolveRawEmailRow(result));
return c.json(serializeMailState(await resolveRawEmailRow(result), false));
}
catch (e) {
return c.text((e as Error).message, 400);