mirror of
https://github.com/Trollobot/Telemax.git
synced 2026-10-19 02:20:58 +00:00
1.3.0-beta.6: пульт «Файлы» — текст пользователя (что здесь хранится и сколько), файлы, которые ещё сохраняются из MAX, кнопка «Обновить»
This commit is contained in:
parent
94a988fc96
commit
9bdf4340dc
4 changed files with 29 additions and 7 deletions
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "telemax",
|
||||
"version": "1.3.0-beta.5",
|
||||
"version": "1.3.0-beta.6",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "telemax",
|
||||
"version": "1.3.0-beta.5",
|
||||
"version": "1.3.0-beta.6",
|
||||
"license": "AGPL-3.0-only",
|
||||
"dependencies": {
|
||||
"dotenv": "^17.2.3",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"name": "telemax",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0-only",
|
||||
"version": "1.3.0-beta.5",
|
||||
"version": "1.3.0-beta.6",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "tsx watch src/server/app.ts",
|
||||
|
|
|
|||
|
|
@ -123,6 +123,8 @@ export class FileShare {
|
|||
private chain: Promise<unknown> = Promise.resolve();
|
||||
private uploadHandler: ((t: UploadTicket, filePath: string, size: number, name: string) => Promise<void>) | null = null;
|
||||
private busyTokens = new Set<string>();
|
||||
/** Files being saved from MAX right now — the panel lists them before they're done. */
|
||||
private saving = new Map<string, { name: string; size: number; written: number }>();
|
||||
|
||||
constructor(
|
||||
dataDir: string,
|
||||
|
|
@ -200,6 +202,11 @@ export class FileShare {
|
|||
return this.index.tickets.find((t) => t.token === token);
|
||||
}
|
||||
|
||||
/** Files still being saved from MAX: name, declared size, bytes so far. */
|
||||
inProgress(): Array<{ name: string; size: number; written: number }> {
|
||||
return [...this.saving.values()];
|
||||
}
|
||||
|
||||
pendingUploads(): number {
|
||||
return this.index.tickets.length;
|
||||
}
|
||||
|
|
@ -286,9 +293,12 @@ export class FileShare {
|
|||
const part = path.join(dir, `${safe}.part`);
|
||||
let written = 0;
|
||||
const limit = Math.max(size, 0) + 1024 * 1024; // the declared size, a little slack
|
||||
const progress = { name: safe, size, written: 0 };
|
||||
this.saving.set(id, progress);
|
||||
const guard = new Transform({
|
||||
transform(chunk: Buffer, _enc, cb) {
|
||||
written += chunk.length;
|
||||
progress.written = written;
|
||||
onProgress?.(written);
|
||||
if (written > limit) cb(new Error(`file grew past its declared ${size} bytes`));
|
||||
else cb(null, chunk);
|
||||
|
|
@ -300,6 +310,8 @@ export class FileShare {
|
|||
} catch (err) {
|
||||
await rm(dir, { recursive: true, force: true });
|
||||
throw err;
|
||||
} finally {
|
||||
this.saving.delete(id);
|
||||
}
|
||||
return this.locked(() => this.addFile(id, safe, written, 'max2tg'));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,21 +161,31 @@ function filesView(files: FileShare): View {
|
|||
return { text: '📁 Пересылка больших файлов отключена: FILES=off в .env.', markup: Markup.inlineKeyboard([back]).reply_markup };
|
||||
}
|
||||
const list = files.list();
|
||||
const saving = files.inProgress();
|
||||
const pending = files.pendingUploads();
|
||||
const pendingLine = pending ? `\n\n⏳ Ждут загрузки по ссылке: ${pending}.` : '';
|
||||
const ttl = ttlText(files.opts.ttlMs);
|
||||
const savingLines = saving.map((x) => `⏳ Сохраняется: ${x.name} — ${formatBytes(x.written)} из ${formatBytes(x.size)}`);
|
||||
const pendingLine = pending ? `⏳ Ждут загрузки по ссылке: ${pending}` : '';
|
||||
const footer =
|
||||
'Здесь хранятся файлы, которые мост держит на сервере для скачивания по ссылке:\n' +
|
||||
'• файлы из MAX больше 50 МБ — Telegram не принимает от ботов такие файлы напрямую;\n' +
|
||||
'• загруженные для отправки в MAX, но не ушедшие из-за ошибки — их можно отправить ещё раз.\n\n' +
|
||||
'Файлы, которые уже ушли в MAX, на сервере не остаются.\n' +
|
||||
`Файлы со ссылкой хранятся ${ttl} от последней выданной ссылки, потом удаляются.`;
|
||||
const extra = [...savingLines, pendingLine].filter(Boolean).join('\n');
|
||||
if (list.length === 0) {
|
||||
return {
|
||||
text: `📁 Файлов нет.\n\nСюда попадают большие файлы, которые мост пересылает по ссылке: из MAX — больше 50 МБ, в MAX — больше 4 ГБ. Файл живёт ${ttl} от последней выданной ссылки, потом удаляется.${pendingLine}`,
|
||||
markup: Markup.inlineKeyboard([back]).reply_markup,
|
||||
text: `📁 Файлов нет.${extra ? `\n\n${extra}` : ''}\n\n${footer}`,
|
||||
markup: Markup.inlineKeyboard([[Markup.button.callback('🔄 Обновить', 'tlmx_panel:files')], back]).reply_markup,
|
||||
};
|
||||
}
|
||||
const total = list.reduce((s, f) => s + f.size, 0);
|
||||
const lines = list.map((f, i) => `${i + 1}. ${f.direction === 'max2tg' ? '⬇️' : '⬆️'} ${f.name} — ${formatBytes(f.size)}, до ${formatExpiry(f.expiresAt)}`);
|
||||
return {
|
||||
text: `📁 Файлы на сервере: ${list.length}, всего ${formatBytes(total)}.\n⬇️ — из MAX, ⬆️ — для MAX. Ссылка живёт ${ttl}, потом файл удаляется.\n\n${lines.join('\n')}${pendingLine}`,
|
||||
text: `📁 Файлы на сервере: ${list.length}, всего ${formatBytes(total)}.\n⬇️ — из MAX, ⬆️ — не ушли в MAX.\n\n${lines.join('\n')}${extra ? `\n\n${extra}` : ''}\n\n${footer}`,
|
||||
markup: Markup.inlineKeyboard([
|
||||
...list.slice(0, 20).map((f, i) => [Markup.button.callback(`${i + 1}. ${truncateUtf16(f.name, 48)}`, `tlmx_panel:file:${f.id}`)]),
|
||||
[Markup.button.callback('🔄 Обновить', 'tlmx_panel:files')],
|
||||
back,
|
||||
]).reply_markup,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue