diff --git a/src/main/file_handlers.ts b/src/main/file_handlers.ts index 7b6a732..f8a1c45 100644 --- a/src/main/file_handlers.ts +++ b/src/main/file_handlers.ts @@ -1,6 +1,8 @@ import { ipcMain, shell } from 'electron'; import * as fs from 'fs'; import * as path from 'path'; +import * as os from 'os'; +import { exec } from 'child_process'; import axios from 'axios'; import { expandPath } from './file_utils'; @@ -64,8 +66,43 @@ export function registerFileHandlers() { const source = get_organized_hashed_path(cache_root, hash, hash_prefix_length); const expanded_temp = expandPath(temp_root); const target = path.join(expanded_temp, filename); + + console.log(`Native: Launching from Cache -> ${filename}`); + if (!fs.existsSync(expanded_temp)) fs.mkdirSync(expanded_temp, { recursive: true }); + + // 1. Copy the file to temp folder with original name fs.copyFileSync(source, target); + + // 2. Determine file type + const ext = path.extname(filename).toLowerCase().replace('.', ''); + const is_pres = ['pptx', 'ppt', 'key', 'pdf', 'odp'].includes(ext); + + // 3. Optimized Launch (LibreOffice / AppleScript) + if (is_pres) { + if (os.platform() === 'linux') { + console.log(`Native: Launching LibreOffice (--impress) for ${target}`); + return new Promise((resolve) => { + exec(`libreoffice --impress "${target}"`, (err) => { + if (err) resolve({ success: false, error: err.message }); + else resolve({ success: true }); + }); + }); + } + + if (os.platform() === 'darwin' && ext === 'key') { + console.log(`Native: Launching Keynote via AppleScript for ${target}`); + const script = `tell application "Keynote" to open POSIX file "${target}"`; + return new Promise((resolve) => { + exec(`osascript -e "${script.replace(/"/g, '\"')}"`, (err) => { + if (err) resolve({ success: false, error: err.message }); + else resolve({ success: true }); + }); + }); + } + } + + // 4. Default Fallback await shell.openPath(target); return { success: true }; } catch (error: any) { diff --git a/src/main/file_utils.ts b/src/main/file_utils.ts index 038f1a1..1de0e53 100644 --- a/src/main/file_utils.ts +++ b/src/main/file_utils.ts @@ -3,10 +3,10 @@ import * as path from 'path'; export function expandPath(filePath: string): string { if (!filePath) return filePath; - if (filePath.startsWith('[home]')) { - return path.join(os.homedir(), filePath.replace('[home]', '')); - } - return filePath; + // Resolve all instances of [home] and [tmp] using global regex + return filePath + .replace(/\[home\]/g, os.homedir()) + .replace(/\[tmp\]/g, os.tmpdir()); } export function getHashedPath(cacheRoot: string, hash: string): string { diff --git a/src/main/index.ts b/src/main/index.ts index 258a7b3..1d1dc37 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -18,7 +18,7 @@ async function createWindow() { } mainWindow = new BrowserWindow({ - width: 1400, + width: 1600, height: 900, title: 'OSIT Aether Launcher (Native)', webPreferences: { @@ -38,6 +38,7 @@ async function createWindow() { targetUrl = `http://${useHost}/events/${eventId}/launcher/${locationId}`; } + mainWindow.webContents.openDevTools(); mainWindow.loadURL(targetUrl).catch(() => { mainWindow?.loadURL('https://dev-demo.oneskyit.com/'); }); @@ -79,6 +80,8 @@ ipcMain.handle('get-device-info', async () => { cpus: os.cpus().length, total_mem: os.totalmem(), free_mem: os.freemem(), - ip_addresses: addresses + ip_addresses: addresses, + home_directory: os.homedir(), + tmp_directory: os.tmpdir() }; }); diff --git a/src/main/shell_handlers.ts b/src/main/shell_handlers.ts index ef77639..6e981a9 100644 --- a/src/main/shell_handlers.ts +++ b/src/main/shell_handlers.ts @@ -2,24 +2,28 @@ import { ipcMain, shell } from 'electron'; import { exec, execSync } from 'child_process'; import * as fs from 'fs'; import * as os from 'os'; +import { expandPath } from './file_utils'; export function registerShellHandlers() { ipcMain.handle('native:open-folder', async (event, folderPath: string) => { - const error = await shell.openPath(folderPath); + const cleanPath = expandPath(folderPath); + const error = await shell.openPath(cleanPath); return { success: !error, error }; }); ipcMain.handle('native:run-cmd', async (event, { cmd, timeout = 30000 }) => { + const cleanCmd = expandPath(cmd); return new Promise((resolve) => { - exec(cmd, { timeout }, (error, stdout, stderr) => { + exec(cleanCmd, { timeout }, (error, stdout, stderr) => { resolve({ success: !error, stdout: stdout.trim(), stderr: stderr.trim(), error: error ? error.message : null }); }); }); }); ipcMain.handle('native:run-cmd-sync', async (event, { cmd }) => { + const cleanCmd = expandPath(cmd); try { - const stdout = execSync(cmd).toString(); + const stdout = execSync(cleanCmd).toString(); return { success: true, stdout: stdout.trim() }; } catch (error: any) { return { success: false, error: error.message, stderr: error.stderr?.toString() }; @@ -55,7 +59,39 @@ export function registerShellHandlers() { }); ipcMain.handle('native:open-local-file-v2', async (event, filePath: string) => { - const error = await shell.openPath(filePath); + const cleanPath = expandPath(filePath); + const error = await shell.openPath(cleanPath); + return { success: !error, error }; + }); + + ipcMain.handle('native:launch-presentation', async (event, { path: rawPath, app: appType = 'default' }) => { + const cleanedPath = expandPath(rawPath); + console.log(`Native: Launching Presentation -> ${cleanedPath} (App: ${appType})`); + + if (os.platform() === 'linux') { + const cmd = `libreoffice --impress "${cleanedPath}"`; + return new Promise((resolve) => { + exec(cmd, (err, stdout, stderr) => { + if (err) resolve({ success: false, error: err.message }); + else resolve({ success: true, stdout, stderr }); + }); + }); + } + + if (os.platform() === 'darwin') { + if (appType === 'keynote') { + const script = `tell application "Keynote" to open POSIX file "${cleanedPath}"`; + const escapedScript = script.replace(/"/g, '\\"'); + return new Promise((resolve) => { + exec(`osascript -e "${escapedScript}"`, (err, stdout, stderr) => { + if (err) resolve({ success: false, error: err.message }); + else resolve({ success: true }); + }); + }); + } + } + + const error = await shell.openPath(cleanedPath); return { success: !error, error }; }); } diff --git a/src/preload/index.ts b/src/preload/index.ts index d7a4aee..df95263 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -16,4 +16,5 @@ contextBridge.exposeInMainWorld('aetherNative', { check_cache: (args: any) => ipcRenderer.invoke('native:check-cache', args), download_to_cache: (args: any) => ipcRenderer.invoke('native:download-to-cache', args), launch_from_cache: (args: any) => ipcRenderer.invoke('native:launch-from-cache', args), + launch_presentation: (args: any) => ipcRenderer.invoke('native:launch-presentation', args), });