dsh-tg-bridge 1.2.4 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bridge.mjs +22 -0
- package/control.mjs +11 -0
- package/package.json +1 -1
package/bridge.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from 'node:fs';
|
|
13
13
|
import { homedir } from 'node:os';
|
|
14
14
|
import { join, basename } from 'node:path';
|
|
15
|
+
import { fileURLToPath } from 'node:url';
|
|
15
16
|
// Force IPv4 for every fetch. DNS returns an AAAA next to the A record, and
|
|
16
17
|
// Happy Eyeballs happily picks the IPv6 path, which here costs ~5 s or dies
|
|
17
18
|
// outright ("fetch failed" every 6 s, measured 22.10.2026: IPv4 0.34 s, IPv6
|
|
@@ -36,6 +37,10 @@ const CRED = join(DSH_HOME, '.credentials.yaml');
|
|
|
36
37
|
const PENDING_DIR = join(DIR, 'pending');
|
|
37
38
|
const DONE_FILE = join(DIR, 'done.json');
|
|
38
39
|
const RESTART_MARKER = join(DIR, 'restart.pending');
|
|
40
|
+
// `/restart confirm` leaves a note here for the process that replaces it: the
|
|
41
|
+
// old code exits ~300 ms after spawning the new one, and without this the chat
|
|
42
|
+
// saw "Перезапускаю мост…" and then silence — no proof the bot came back.
|
|
43
|
+
const RESTART_NOTICE = join(fileURLToPath(new URL('.', import.meta.url)), 'restart-notice.json');
|
|
39
44
|
const DONE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
40
45
|
// dsh.cmd runs the Electron binary as Node against this CLI entrypoint; the
|
|
41
46
|
// bridge mirrors that exactly so no shell quoting of task text is needed.
|
|
@@ -1670,6 +1675,23 @@ async function main() {
|
|
|
1670
1675
|
const me = await tg('getMe');
|
|
1671
1676
|
botUsername = me.username || '';
|
|
1672
1677
|
log(`bot @${me.username}`);
|
|
1678
|
+
// Confirm the restart in the topic it was asked from, not in the DM: the
|
|
1679
|
+
// person who typed `/restart confirm` was looking at that thread.
|
|
1680
|
+
try {
|
|
1681
|
+
if (existsSync(RESTART_NOTICE)) {
|
|
1682
|
+
const notice = JSON.parse(readFileSync(RESTART_NOTICE, 'utf8'));
|
|
1683
|
+
unlinkSync(RESTART_NOTICE);
|
|
1684
|
+
if (Date.now() - Number(notice.at || 0) < 10 * 60 * 1000) {
|
|
1685
|
+
await send(
|
|
1686
|
+
notice.chatId,
|
|
1687
|
+
`✅ Мост перезапущен — на связи (pid ${process.pid}).\nТема и сессия прежние, можно продолжать.`,
|
|
1688
|
+
notice.threadId || 0,
|
|
1689
|
+
);
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
} catch (error) {
|
|
1693
|
+
log(`restart notice failed: ${error.message}`);
|
|
1694
|
+
}
|
|
1673
1695
|
for (const id of config.allowedUserIds) {
|
|
1674
1696
|
try { await send(id, `🤖 ${t(config.lang || 'ru', 'msg.started')}`); } catch {}
|
|
1675
1697
|
}
|
package/control.mjs
CHANGED
|
@@ -554,6 +554,17 @@ export async function handleControl(ctx) {
|
|
|
554
554
|
}
|
|
555
555
|
say('Перезапускаю мост…');
|
|
556
556
|
const bridge = fileURLToPath(new URL('./bridge.mjs', import.meta.url));
|
|
557
|
+
// Tell the replacement process where to confirm, so the chat does not go
|
|
558
|
+
// silent after "Перезапускаю мост…" (it did, twice on 2026-10-24).
|
|
559
|
+
try {
|
|
560
|
+
writeFileSync(
|
|
561
|
+
fileURLToPath(new URL('./restart-notice.json', import.meta.url)),
|
|
562
|
+
JSON.stringify({ chatId: ctx.chatId, threadId: ctx.threadId || 0, at: Date.now() }),
|
|
563
|
+
'utf8',
|
|
564
|
+
);
|
|
565
|
+
} catch (error) {
|
|
566
|
+
log(`restart notice not written: ${error.message}`);
|
|
567
|
+
}
|
|
557
568
|
spawn(process.execPath, [bridge], { detached: true, stdio: 'ignore', windowsHide: true }).unref();
|
|
558
569
|
setTimeout(() => process.exit(0), 300);
|
|
559
570
|
return true;
|
package/package.json
CHANGED