mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
refactor(launcher): consolidate mpv socket readiness primitive
This commit is contained in:
@@ -19,7 +19,6 @@ import {
|
||||
stopOverlay,
|
||||
launchTexthookerOnly,
|
||||
findAppBinary,
|
||||
waitForSocket,
|
||||
loadSubtitleIntoMpv,
|
||||
runAppCommandWithInherit,
|
||||
launchMpvIdleDetached,
|
||||
@@ -361,7 +360,7 @@ async function main(): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
const ready = await waitForSocket(mpvSocketPath);
|
||||
const ready = await waitForUnixSocketReady(mpvSocketPath, 10000);
|
||||
const shouldStartOverlay = args.startOverlay || args.autoStartOverlay;
|
||||
if (shouldStartOverlay) {
|
||||
if (ready) {
|
||||
|
||||
61
launcher/mpv.test.ts
Normal file
61
launcher/mpv.test.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import net from 'node:net';
|
||||
import { EventEmitter } from 'node:events';
|
||||
import { waitForUnixSocketReady } from './mpv';
|
||||
import * as mpvModule from './mpv';
|
||||
|
||||
function createTempSocketPath(): { dir: string; socketPath: string } {
|
||||
const baseDir = path.join(process.cwd(), '.tmp', 'launcher-mpv-tests');
|
||||
fs.mkdirSync(baseDir, { recursive: true });
|
||||
const dir = fs.mkdtempSync(path.join(baseDir, 'case-'));
|
||||
return { dir, socketPath: path.join(dir, 'mpv.sock') };
|
||||
}
|
||||
|
||||
test('mpv module exposes only canonical socket readiness helper', () => {
|
||||
assert.equal('waitForSocket' in mpvModule, false);
|
||||
});
|
||||
|
||||
test('waitForUnixSocketReady returns false when socket never appears', async () => {
|
||||
const { dir, socketPath } = createTempSocketPath();
|
||||
try {
|
||||
const ready = await waitForUnixSocketReady(socketPath, 120);
|
||||
assert.equal(ready, false);
|
||||
} finally {
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('waitForUnixSocketReady returns false when path exists but is not socket', async () => {
|
||||
const { dir, socketPath } = createTempSocketPath();
|
||||
try {
|
||||
fs.writeFileSync(socketPath, 'not-a-socket');
|
||||
const ready = await waitForUnixSocketReady(socketPath, 200);
|
||||
assert.equal(ready, false);
|
||||
} finally {
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('waitForUnixSocketReady returns true when socket becomes connectable before timeout', async () => {
|
||||
const { dir, socketPath } = createTempSocketPath();
|
||||
fs.writeFileSync(socketPath, '');
|
||||
const originalCreateConnection = net.createConnection;
|
||||
try {
|
||||
net.createConnection = (() => {
|
||||
const socket = new EventEmitter() as net.Socket;
|
||||
socket.destroy = (() => socket) as net.Socket['destroy'];
|
||||
socket.setTimeout = (() => socket) as net.Socket['setTimeout'];
|
||||
setTimeout(() => socket.emit('connect'), 25);
|
||||
return socket;
|
||||
}) as typeof net.createConnection;
|
||||
|
||||
const ready = await waitForUnixSocketReady(socketPath, 400);
|
||||
assert.equal(ready, true);
|
||||
} finally {
|
||||
net.createConnection = originalCreateConnection;
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
@@ -416,23 +416,6 @@ export async function loadSubtitleIntoMpv(
|
||||
}
|
||||
}
|
||||
|
||||
export function waitForSocket(socketPath: string, timeoutMs = 10000): Promise<boolean> {
|
||||
const start = Date.now();
|
||||
return new Promise((resolve) => {
|
||||
const timer = setInterval(() => {
|
||||
if (fs.existsSync(socketPath)) {
|
||||
clearInterval(timer);
|
||||
resolve(true);
|
||||
return;
|
||||
}
|
||||
if (Date.now() - start >= timeoutMs) {
|
||||
clearInterval(timer);
|
||||
resolve(false);
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
export function startMpv(
|
||||
target: string,
|
||||
targetKind: 'file' | 'url',
|
||||
@@ -672,19 +655,6 @@ async function sleepMs(ms: number): Promise<void> {
|
||||
await new Promise<void>((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function waitForPathExists(filePath: string, timeoutMs: number): Promise<boolean> {
|
||||
const deadline = Date.now() + timeoutMs;
|
||||
while (Date.now() < deadline) {
|
||||
try {
|
||||
if (fs.existsSync(filePath)) return true;
|
||||
} catch {
|
||||
// ignore transient fs errors
|
||||
}
|
||||
await sleepMs(150);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function canConnectUnixSocket(socketPath: string): Promise<boolean> {
|
||||
return await new Promise<boolean>((resolve) => {
|
||||
const socket = net.createConnection(socketPath);
|
||||
@@ -713,10 +683,13 @@ export async function waitForUnixSocketReady(
|
||||
): Promise<boolean> {
|
||||
const deadline = Date.now() + timeoutMs;
|
||||
while (Date.now() < deadline) {
|
||||
const exists = await waitForPathExists(socketPath, 300);
|
||||
if (exists) {
|
||||
const ready = await canConnectUnixSocket(socketPath);
|
||||
if (ready) return true;
|
||||
try {
|
||||
if (fs.existsSync(socketPath)) {
|
||||
const ready = await canConnectUnixSocket(socketPath);
|
||||
if (ready) return true;
|
||||
}
|
||||
} catch {
|
||||
// ignore transient fs errors
|
||||
}
|
||||
await sleepMs(150);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user