Files
DepressedCat 5f2aad00f4
Check extension and helper / check (push) Canceled after 0s
Publish YouTubeDL 1.4.5 and website on Gitea
2026-10-10 23:53:17 +03:00

58 lines
2.3 KiB
JavaScript

// A menu can outlive its MV3 service worker while the user runs the installer.
// Reopen the UI port on the next command; never replay requests already sent.
export function createUiConnection({ onEvent, onDisconnect, runtime = chrome.runtime }) {
const requests = new Map();
const disconnected = () => new Error("Связь с расширением прервана. Нажмите «Проверить подключение» или «Запустить» для повторного подключения.");
let port = null;
function drop(connection) {
if (port !== connection) return;
port = null;
for (const [id, request] of requests) {
if (request.port !== connection) continue;
requests.delete(id); request.reject(disconnected());
}
onDisconnect?.();
}
function connect() {
if (port) return port;
const connection = runtime.connect({ name: "ytdl-ui" });
port = connection;
connection.onMessage.addListener(message => {
if (port !== connection) return;
if (message.event) { onEvent?.(message); return; }
const request = requests.get(message.id);
if (!request || request.port !== connection) return;
requests.delete(message.id);
message.ok ? request.resolve(message.result) : request.reject(new Error(message.error));
});
connection.onDisconnect.addListener(() => {
// Read lastError in the callback to avoid an unchecked runtime error.
void runtime.lastError?.message;
drop(connection);
});
return connection;
}
function call(action, payload = {}) {
return new Promise((resolve, reject) => {
for (let attempt = 0; attempt < 2; attempt++) {
let connection, id;
try {
connection = connect(); id = crypto.randomUUID();
requests.set(id, { resolve, reject, port: connection });
connection.postMessage({ id, action, payload });
return;
} catch (error) {
if (id) requests.delete(id);
if (connection) drop(connection);
// A synchronous disconnected-port error means this command was not sent.
if (attempt === 0 && /disconnected port/i.test(error.message)) continue;
reject(/disconnected port/i.test(error.message) ? disconnected() : error);
return;
}
}
});
}
return { call };
}