fix: remove element protocol support and update related functionality
This commit is contained in:
2
cinny
2
cinny
Submodule cinny updated: a4a0fa6758...d1626e3585
@@ -39,7 +39,7 @@
|
|||||||
"protocols": [
|
"protocols": [
|
||||||
{
|
{
|
||||||
"name": "Paarrot URL",
|
"name": "Paarrot URL",
|
||||||
"schemes": ["paarrot", "element"]
|
"schemes": ["paarrot"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"linux": {
|
"linux": {
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
"Name": "Paarrot",
|
"Name": "Paarrot",
|
||||||
"GenericName": "Matrix Client",
|
"GenericName": "Matrix Client",
|
||||||
"Comment": "A Matrix client built with Cinny",
|
"Comment": "A Matrix client built with Cinny",
|
||||||
"MimeType": "x-scheme-handler/paarrot;x-scheme-handler/element;",
|
"MimeType": "x-scheme-handler/paarrot;",
|
||||||
"Categories": "Network;InstantMessaging;",
|
"Categories": "Network;InstantMessaging;",
|
||||||
"Keywords": "matrix;chat;messaging;",
|
"Keywords": "matrix;chat;messaging;",
|
||||||
"StartupWMClass": "paarrot"
|
"StartupWMClass": "paarrot"
|
||||||
|
|||||||
225
electron/main.js
225
electron/main.js
@@ -1,7 +1,7 @@
|
|||||||
const { app, BrowserWindow, ipcMain, shell, Tray, Menu, nativeImage, clipboard, session, desktopCapturer } = require('electron');
|
const { app, BrowserWindow, ipcMain, shell, Tray, Menu, nativeImage, clipboard, session, desktopCapturer } = require('electron');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const { exec, execFile } = require('child_process');
|
const { exec, execFile, execFileSync } = require('child_process');
|
||||||
const { promisify } = require('util');
|
const { promisify } = require('util');
|
||||||
const Store = require('electron-store');
|
const Store = require('electron-store');
|
||||||
const open = require('open');
|
const open = require('open');
|
||||||
@@ -19,24 +19,19 @@ const PORT = 44548;
|
|||||||
const execAsync = promisify(exec);
|
const execAsync = promisify(exec);
|
||||||
const execFileAsync = promisify(execFile);
|
const execFileAsync = promisify(execFile);
|
||||||
const store = new Store();
|
const store = new Store();
|
||||||
const PAARROT_PROTOCOL = 'paarrot';
|
const PROTOCOL_SCHEME = 'paarrot';
|
||||||
const ELEMENT_PROTOCOL = 'element';
|
|
||||||
const PRIMARY_PROTOCOL = PAARROT_PROTOCOL;
|
|
||||||
const SUPPORTED_PROTOCOLS = [PAARROT_PROTOCOL, ELEMENT_PROTOCOL];
|
|
||||||
|
|
||||||
let mainWindow = null;
|
let mainWindow = null;
|
||||||
let tray = null;
|
let tray = null;
|
||||||
let isQuitting = false;
|
let isQuitting = false;
|
||||||
let apiServer = null;
|
let apiServer = null;
|
||||||
let pendingDeepLink = null;
|
let pendingDeepLink = null;
|
||||||
let protocolRegistrationState = Object.fromEntries(
|
let protocolRegistrationState = {
|
||||||
SUPPORTED_PROTOCOLS.map((scheme) => [scheme, {
|
before: false,
|
||||||
before: false,
|
registerCall: false,
|
||||||
registerCall: false,
|
after: false,
|
||||||
after: false,
|
error: null,
|
||||||
error: null,
|
};
|
||||||
}])
|
|
||||||
);
|
|
||||||
|
|
||||||
// Allow audio playback without requiring a prior user gesture (needed for notification sounds)
|
// Allow audio playback without requiring a prior user gesture (needed for notification sounds)
|
||||||
app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required');
|
app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required');
|
||||||
@@ -151,7 +146,7 @@ if (!gotTheLock) {
|
|||||||
pendingDeepLink = extractDeepLinkFromArgv(process.argv);
|
pendingDeepLink = extractDeepLinkFromArgv(process.argv);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts a supported deep link URL from argv.
|
* Extracts a paarrot:// deep link URL from argv.
|
||||||
* @param {string[]} argv - Process argument vector.
|
* @param {string[]} argv - Process argument vector.
|
||||||
* @returns {string|null} The deep link URL or null.
|
* @returns {string|null} The deep link URL or null.
|
||||||
*/
|
*/
|
||||||
@@ -160,20 +155,13 @@ function extractDeepLinkFromArgv(argv) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const match = argv.find((arg) => {
|
const match = argv.find((arg) => typeof arg === 'string' && arg.toLowerCase().startsWith(`${PROTOCOL_SCHEME}://`));
|
||||||
if (typeof arg !== 'string') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lowerArg = arg.toLowerCase();
|
|
||||||
return SUPPORTED_PROTOCOLS.some((scheme) => lowerArg.startsWith(`${scheme}://`));
|
|
||||||
});
|
|
||||||
|
|
||||||
return match || null;
|
return match || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a supported deep link into an in-app hash route.
|
* Converts a paarrot:// deep link into an in-app hash route.
|
||||||
* @param {string} deepLink - The incoming protocol URL.
|
* @param {string} deepLink - The incoming protocol URL.
|
||||||
* @returns {string|null} Hash route value without leading #.
|
* @returns {string|null} Hash route value without leading #.
|
||||||
*/
|
*/
|
||||||
@@ -182,9 +170,7 @@ function deepLinkToHashRoute(deepLink) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lowerDeepLink = deepLink.toLowerCase();
|
if (!deepLink.toLowerCase().startsWith(`${PROTOCOL_SCHEME}://`)) {
|
||||||
const isSupported = SUPPORTED_PROTOCOLS.some((scheme) => lowerDeepLink.startsWith(`${scheme}://`));
|
|
||||||
if (!isSupported) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,26 +223,34 @@ function applyDeepLink(deepLink) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the app as handler for a URL scheme.
|
* Registers the app as handler for paarrot:// links.
|
||||||
* @param {string} scheme - URL protocol scheme name.
|
|
||||||
* @returns {{ before: boolean; registerCall: boolean; after: boolean; error: string | null }}
|
* @returns {{ before: boolean; registerCall: boolean; after: boolean; error: string | null }}
|
||||||
*/
|
*/
|
||||||
function registerProtocolScheme(scheme) {
|
function registerAppProtocol() {
|
||||||
const before = app.isDefaultProtocolClient(scheme);
|
const before = app.isDefaultProtocolClient(PROTOCOL_SCHEME);
|
||||||
let registered = false;
|
let registered = false;
|
||||||
let error = null;
|
let error = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (process.defaultApp) {
|
if (process.defaultApp) {
|
||||||
registered = app.setAsDefaultProtocolClient(scheme, process.execPath, [path.resolve(process.argv[1])]);
|
registered = app.setAsDefaultProtocolClient(PROTOCOL_SCHEME, process.execPath, [path.resolve(process.argv[1])]);
|
||||||
} else {
|
} else {
|
||||||
registered = app.setAsDefaultProtocolClient(scheme);
|
registered = app.setAsDefaultProtocolClient(PROTOCOL_SCHEME);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error = err instanceof Error ? err.message : String(err);
|
error = err instanceof Error ? err.message : String(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
const after = app.isDefaultProtocolClient(scheme);
|
let after = app.isDefaultProtocolClient(PROTOCOL_SCHEME);
|
||||||
|
// In Windows dev mode, default ownership may stay false even when registry command points to this app.
|
||||||
|
if (!after && process.platform === 'win32') {
|
||||||
|
const currentCommand = getExpectedWindowsProtocolCommand();
|
||||||
|
const hkcuCommand = queryWindowsRegistryDefaultSync(`HKCU\\Software\\Classes\\${PROTOCOL_SCHEME}\\shell\\open\\command`);
|
||||||
|
if (hkcuCommand && normalizeWindowsCommand(hkcuCommand) === normalizeWindowsCommand(currentCommand)) {
|
||||||
|
after = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
before,
|
before,
|
||||||
registerCall: registered,
|
registerCall: registered,
|
||||||
@@ -266,14 +260,48 @@ function registerProtocolScheme(scheme) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers all supported URL protocol schemes.
|
* Gets the command that should be registered for paarrot:// on Windows.
|
||||||
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function registerAppProtocols() {
|
function getExpectedWindowsProtocolCommand() {
|
||||||
SUPPORTED_PROTOCOLS.forEach((scheme) => {
|
return process.defaultApp && process.argv[1]
|
||||||
const schemeState = registerProtocolScheme(scheme);
|
? `"${process.execPath}" "${path.resolve(process.argv[1])}" "%1"`
|
||||||
protocolRegistrationState[scheme] = schemeState;
|
: `"${process.execPath}" "%1"`;
|
||||||
console.log(`[Protocol] ${scheme}:// before=${schemeState.before} registerCall=${schemeState.registerCall} after=${schemeState.after}${schemeState.error ? ` error=${schemeState.error}` : ''}`);
|
}
|
||||||
});
|
|
||||||
|
/**
|
||||||
|
* Normalizes a Windows command string for reliable comparisons.
|
||||||
|
* @param {string} command - Command string to normalize.
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function normalizeWindowsCommand(command) {
|
||||||
|
return String(command).replace(/\\/g, '/').replace(/\s+/g, ' ').trim().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the default Windows registry value synchronously.
|
||||||
|
* @param {string} keyPath - Registry key path.
|
||||||
|
* @returns {string|null} Default value content.
|
||||||
|
*/
|
||||||
|
function queryWindowsRegistryDefaultSync(keyPath) {
|
||||||
|
try {
|
||||||
|
const stdout = execFileSync('reg.exe', ['query', keyPath, '/ve'], { encoding: 'utf8' });
|
||||||
|
const lines = stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
||||||
|
const valueLine = lines.find((line) => line.startsWith('(Default)'));
|
||||||
|
if (!valueLine) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsed = valueLine.split(/\s{2,}/).filter(Boolean);
|
||||||
|
return parsed.length >= 3 ? parsed.slice(2).join(' ') : null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncProtocolRegistrationState() {
|
||||||
|
protocolRegistrationState = registerAppProtocol();
|
||||||
|
console.log(`[Protocol] ${PROTOCOL_SCHEME}:// before=${protocolRegistrationState.before} registerCall=${protocolRegistrationState.registerCall} after=${protocolRegistrationState.after}${protocolRegistrationState.error ? ` error=${protocolRegistrationState.error}` : ''}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -320,13 +348,16 @@ async function queryWindowsRegistryDefault(keyPath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides Windows-specific protocol association diagnostics for one scheme.
|
* Provides Windows-specific protocol association diagnostics for paarrot://.
|
||||||
* @param {string} scheme - URL protocol scheme.
|
|
||||||
* @returns {Promise<{userChoiceProgId: string | null; userChoiceCommand: string | null; hkcuCommand: string | null; hklmCommand: string | null}>}
|
* @returns {Promise<{userChoiceProgId: string | null; userChoiceCommand: string | null; hkcuCommand: string | null; hklmCommand: string | null}>}
|
||||||
*/
|
*/
|
||||||
async function getWindowsProtocolDiagnosticsForScheme(scheme) {
|
async function getWindowsProtocolDiagnostics() {
|
||||||
|
if (process.platform !== 'win32') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const userChoiceProgId = await queryWindowsRegistryValue(
|
const userChoiceProgId = await queryWindowsRegistryValue(
|
||||||
`HKCU\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\${scheme}\\UserChoice`,
|
`HKCU\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\${PROTOCOL_SCHEME}\\UserChoice`,
|
||||||
'ProgId'
|
'ProgId'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -337,8 +368,8 @@ async function getWindowsProtocolDiagnosticsForScheme(scheme) {
|
|||||||
(await queryWindowsRegistryDefault(`HKLM\\Software\\Classes\\${userChoiceProgId}\\shell\\open\\command`));
|
(await queryWindowsRegistryDefault(`HKLM\\Software\\Classes\\${userChoiceProgId}\\shell\\open\\command`));
|
||||||
}
|
}
|
||||||
|
|
||||||
const hkcuCommand = await queryWindowsRegistryDefault(`HKCU\\Software\\Classes\\${scheme}\\shell\\open\\command`);
|
const hkcuCommand = await queryWindowsRegistryDefault(`HKCU\\Software\\Classes\\${PROTOCOL_SCHEME}\\shell\\open\\command`);
|
||||||
const hklmCommand = await queryWindowsRegistryDefault(`HKLM\\Software\\Classes\\${scheme}\\shell\\open\\command`);
|
const hklmCommand = await queryWindowsRegistryDefault(`HKLM\\Software\\Classes\\${PROTOCOL_SCHEME}\\shell\\open\\command`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
userChoiceProgId,
|
userChoiceProgId,
|
||||||
@@ -349,25 +380,22 @@ async function getWindowsProtocolDiagnosticsForScheme(scheme) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures Windows has user-level URL protocol class entries for a scheme
|
* Ensures Windows has user-level URL protocol class entries for paarrot://
|
||||||
* so the scheme appears in Default Apps link associations.
|
* so the scheme appears in Default Apps link associations.
|
||||||
* @param {string} scheme - URL protocol scheme.
|
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async function ensureWindowsRegistryEntriesForScheme(scheme) {
|
async function ensureWindowsProtocolRegistryEntries() {
|
||||||
if (process.platform !== 'win32') {
|
if (process.platform !== 'win32') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const openCommand = process.defaultApp && process.argv[1]
|
const openCommand = getExpectedWindowsProtocolCommand();
|
||||||
? `"${process.execPath}" "${path.resolve(process.argv[1])}" "%1"`
|
|
||||||
: `"${process.execPath}" "%1"`;
|
|
||||||
const iconValue = `"${process.execPath}",0`;
|
const iconValue = `"${process.execPath}",0`;
|
||||||
const protocolDisplayName = `URL:${scheme} Protocol`;
|
const protocolDisplayName = `URL:${PROTOCOL_SCHEME} Protocol`;
|
||||||
|
|
||||||
await execFileAsync('reg.exe', [
|
await execFileAsync('reg.exe', [
|
||||||
'add',
|
'add',
|
||||||
`HKCU\\Software\\Classes\\${scheme}`,
|
`HKCU\\Software\\Classes\\${PROTOCOL_SCHEME}`,
|
||||||
'/ve',
|
'/ve',
|
||||||
'/t',
|
'/t',
|
||||||
'REG_SZ',
|
'REG_SZ',
|
||||||
@@ -378,7 +406,7 @@ async function ensureWindowsRegistryEntriesForScheme(scheme) {
|
|||||||
|
|
||||||
await execFileAsync('reg.exe', [
|
await execFileAsync('reg.exe', [
|
||||||
'add',
|
'add',
|
||||||
`HKCU\\Software\\Classes\\${scheme}`,
|
`HKCU\\Software\\Classes\\${PROTOCOL_SCHEME}`,
|
||||||
'/v',
|
'/v',
|
||||||
'URL Protocol',
|
'URL Protocol',
|
||||||
'/t',
|
'/t',
|
||||||
@@ -390,7 +418,7 @@ async function ensureWindowsRegistryEntriesForScheme(scheme) {
|
|||||||
|
|
||||||
await execFileAsync('reg.exe', [
|
await execFileAsync('reg.exe', [
|
||||||
'add',
|
'add',
|
||||||
`HKCU\\Software\\Classes\\${scheme}\\DefaultIcon`,
|
`HKCU\\Software\\Classes\\${PROTOCOL_SCHEME}\\DefaultIcon`,
|
||||||
'/ve',
|
'/ve',
|
||||||
'/t',
|
'/t',
|
||||||
'REG_SZ',
|
'REG_SZ',
|
||||||
@@ -401,7 +429,7 @@ async function ensureWindowsRegistryEntriesForScheme(scheme) {
|
|||||||
|
|
||||||
await execFileAsync('reg.exe', [
|
await execFileAsync('reg.exe', [
|
||||||
'add',
|
'add',
|
||||||
`HKCU\\Software\\Classes\\${scheme}\\shell\\open\\command`,
|
`HKCU\\Software\\Classes\\${PROTOCOL_SCHEME}\\shell\\open\\command`,
|
||||||
'/ve',
|
'/ve',
|
||||||
'/t',
|
'/t',
|
||||||
'REG_SZ',
|
'REG_SZ',
|
||||||
@@ -411,51 +439,20 @@ async function ensureWindowsRegistryEntriesForScheme(scheme) {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides Windows diagnostics for all supported schemes.
|
|
||||||
* @returns {Promise<null|Record<string, {userChoiceProgId: string | null; userChoiceCommand: string | null; hkcuCommand: string | null; hklmCommand: string | null}>>}
|
|
||||||
*/
|
|
||||||
async function getWindowsProtocolDiagnostics() {
|
|
||||||
if (process.platform !== 'win32') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const diagnostics = {};
|
|
||||||
for (const scheme of SUPPORTED_PROTOCOLS) {
|
|
||||||
diagnostics[scheme] = await getWindowsProtocolDiagnosticsForScheme(scheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
return diagnostics;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns renderer-friendly protocol diagnostics payload.
|
* Returns renderer-friendly protocol diagnostics payload.
|
||||||
* @returns {Promise<{ success: boolean; data: { platform: string; primaryScheme: string; schemes: Record<string, {isDefault: boolean; before: boolean; registerCall: boolean; error: string | null}>; windows: null | Record<string, {userChoiceProgId: string | null; userChoiceCommand: string | null; hkcuCommand: string | null; hklmCommand: string | null}> } }>}
|
* @returns {Promise<{ success: boolean; data: { scheme: string; platform: string; isDefault: boolean; before: boolean; registerCall: boolean; error: string | null; windows: null | {userChoiceProgId: string | null; userChoiceCommand: string | null; hkcuCommand: string | null; hklmCommand: string | null} } }>}
|
||||||
*/
|
*/
|
||||||
async function getProtocolStatusPayload() {
|
async function getProtocolStatusPayload() {
|
||||||
const schemes = {};
|
|
||||||
for (const scheme of SUPPORTED_PROTOCOLS) {
|
|
||||||
const state = protocolRegistrationState[scheme] || {
|
|
||||||
before: false,
|
|
||||||
registerCall: false,
|
|
||||||
after: false,
|
|
||||||
error: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
schemes[scheme] = {
|
|
||||||
isDefault: app.isDefaultProtocolClient(scheme),
|
|
||||||
before: state.before,
|
|
||||||
registerCall: state.registerCall,
|
|
||||||
error: state.error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
data: {
|
data: {
|
||||||
|
scheme: PROTOCOL_SCHEME,
|
||||||
platform: process.platform,
|
platform: process.platform,
|
||||||
primaryScheme: PRIMARY_PROTOCOL,
|
isDefault: app.isDefaultProtocolClient(PROTOCOL_SCHEME),
|
||||||
schemes,
|
before: protocolRegistrationState.before,
|
||||||
|
registerCall: protocolRegistrationState.registerCall,
|
||||||
|
error: protocolRegistrationState.error,
|
||||||
windows: await getWindowsProtocolDiagnostics(),
|
windows: await getWindowsProtocolDiagnostics(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -826,7 +823,13 @@ function createTray() {
|
|||||||
|
|
||||||
// App lifecycle
|
// App lifecycle
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
registerAppProtocols();
|
if (process.platform === 'win32') {
|
||||||
|
ensureWindowsProtocolRegistryEntries().catch((error) => {
|
||||||
|
console.warn('[Protocol] Startup registry ensure failed:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
syncProtocolRegistrationState();
|
||||||
|
|
||||||
createWindow();
|
createWindow();
|
||||||
createTray();
|
createTray();
|
||||||
@@ -940,47 +943,31 @@ ipcMain.handle('window:is-maximized', () => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns protocol registration health for the renderer settings page.
|
* Returns protocol registration health for the renderer settings page.
|
||||||
* @returns {Promise<{ success: boolean; data: { platform: string; primaryScheme: string; schemes: Record<string, {isDefault: boolean; before: boolean; registerCall: boolean; error: string | null}>; windows: null | Record<string, {userChoiceProgId: string | null; userChoiceCommand: string | null; hkcuCommand: string | null; hklmCommand: string | null}> } }>}
|
* @returns {Promise<{ success: boolean; data: { scheme: string; platform: string; isDefault: boolean; before: boolean; registerCall: boolean; error: string | null; windows: null | {userChoiceProgId: string | null; userChoiceCommand: string | null; hkcuCommand: string | null; hklmCommand: string | null} } }>}
|
||||||
*/
|
*/
|
||||||
ipcMain.handle('protocol:get-status', () => {
|
ipcMain.handle('protocol:get-status', () => {
|
||||||
return getProtocolStatusPayload();
|
return getProtocolStatusPayload();
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Re-runs protocol registration and opens OS default-apps page when manual selection is required.
|
* Re-runs protocol registry ensure and protocol registration.
|
||||||
* @returns {Promise<{ success: boolean; data: { openedSettings: boolean; platform: string; primaryScheme: string; schemes: Record<string, {isDefault: boolean; before: boolean; registerCall: boolean; error: string | null}>; windows: null | Record<string, {userChoiceProgId: string | null; userChoiceCommand: string | null; hkcuCommand: string | null; hklmCommand: string | null}> } }>}
|
* @returns {Promise<{ success: boolean; data: { scheme: string; platform: string; isDefault: boolean; before: boolean; registerCall: boolean; error: string | null; windows: null | {userChoiceProgId: string | null; userChoiceCommand: string | null; hkcuCommand: string | null; hklmCommand: string | null} } }>}
|
||||||
*/
|
*/
|
||||||
ipcMain.handle('protocol:repair', async () => {
|
ipcMain.handle('protocol:repair', async () => {
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
for (const scheme of SUPPORTED_PROTOCOLS) {
|
|
||||||
try {
|
|
||||||
await ensureWindowsRegistryEntriesForScheme(scheme);
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(`[Protocol] Failed to write Windows URL protocol registry entries for ${scheme}:`, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
registerAppProtocols();
|
|
||||||
|
|
||||||
let openedSettings = false;
|
|
||||||
const isDefault = app.isDefaultProtocolClient(PRIMARY_PROTOCOL);
|
|
||||||
if (process.platform === 'win32' && !isDefault) {
|
|
||||||
try {
|
try {
|
||||||
await shell.openExternal('ms-settings:defaultapps');
|
await ensureWindowsProtocolRegistryEntries();
|
||||||
openedSettings = true;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('[Protocol] Failed to open Windows default apps settings:', error);
|
console.warn('[Protocol] Failed to write Windows URL protocol registry entries:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syncProtocolRegistrationState();
|
||||||
|
|
||||||
const status = await getProtocolStatusPayload();
|
const status = await getProtocolStatusPayload();
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
data: {
|
data: status.data,
|
||||||
openedSettings,
|
|
||||||
...status.data,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user