Last round of prettier: npx prettier --write src/
This commit is contained in:
@@ -9,14 +9,14 @@ The native implementation lives in a separate repo:
|
||||
## Technical Manual
|
||||
|
||||
For detailed architecture, lifecycle, and IPC specifications, see:
|
||||
[PROJECT__AE_Events_Launcher_Native_integration.md](../../../documentation/PROJECT__AE_Events_Launcher_Native_integration.md)
|
||||
[PROJECT\_\_AE_Events_Launcher_Native_integration.md](../../../documentation/PROJECT__AE_Events_Launcher_Native_integration.md)
|
||||
|
||||
## File Manifest
|
||||
|
||||
| File | Role | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| `electron_relay.ts` | **Active — Messenger** | The TypeScript API used by Svelte components. Standardizes all IPC calls to `snake_case`. This is the only file in this directory that should be imported. |
|
||||
| `electron_native.js` | **DEPRECATED — Do not import** | Legacy V2/V4 reference file. The active native logic lives in `aether_app_native_electron/`. Kept for historical reference only. |
|
||||
| File | Role | Description |
|
||||
| :------------------- | :----------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `electron_relay.ts` | **Active — Messenger** | The TypeScript API used by Svelte components. Standardizes all IPC calls to `snake_case`. This is the only file in this directory that should be imported. |
|
||||
| `electron_native.js` | **DEPRECATED — Do not import** | Legacy V2/V4 reference file. The active native logic lives in `aether_app_native_electron/`. Kept for historical reference only. |
|
||||
|
||||
## Usage Example
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// [DEPRECATED] 2026-02-10: This file is a legacy reference from Aether V2/V4.
|
||||
// Do NOT import this into the SvelteKit frontend.
|
||||
// [DEPRECATED] 2026-02-10: This file is a legacy reference from Aether V2/V4.
|
||||
// Do NOT import this into the SvelteKit frontend.
|
||||
// The active native logic resides in the 'aether_app_native_electron' repository.
|
||||
|
||||
// @ts-nocheck
|
||||
@@ -51,7 +51,8 @@ let default_osit_sync_app_root_path = path.join(
|
||||
let default_osit_sync_native_app_relative_path =
|
||||
'OSIT/Speaker Ready System/Admin Share/Custom Applications/osit_binaries/osit_aether.current.app'; // Mainly for macOS laptops
|
||||
let default_native_app_relative_path = 'OSIT/native_app/osit_aether.app'; // Mainly for macOS laptops
|
||||
let default_current_native_app_relative_path = 'OSIT/native_app/osit_aether.current.app'; // Mainly for macOS laptops
|
||||
let default_current_native_app_relative_path =
|
||||
'OSIT/native_app/osit_aether.current.app'; // Mainly for macOS laptops
|
||||
let test_native_app_relative_path = 'OSIT/native_app/osit_aether.remote.app'; // Mainly for macOS laptops
|
||||
|
||||
// exports.check_for_native_app_update = function () {
|
||||
@@ -115,7 +116,10 @@ exports.load_init_config = function () {
|
||||
config_directory = path.join(home_directory, 'OSIT/native_app');
|
||||
console.log('macOS config directory: ' + config_directory);
|
||||
|
||||
let electron_app_path = path.join(home_directory, default_native_app_relative_path);
|
||||
let electron_app_path = path.join(
|
||||
home_directory,
|
||||
default_native_app_relative_path
|
||||
);
|
||||
let test_stats = fs.statSync(electron_app_path);
|
||||
console.log(test_stats);
|
||||
} else if (os.platform == 'linux') {
|
||||
@@ -140,8 +144,13 @@ exports.load_init_config = function () {
|
||||
|
||||
// Attempt to open the config file. The preferred location is based on the OS's config directory.
|
||||
if (fs.existsSync(config_path)) {
|
||||
console.log(`Config file (ae_native_app_config.json) found under ${config_directory}`);
|
||||
} else if (!fs.existsSync(config_path) && fs.existsSync(default_config_path)) {
|
||||
console.log(
|
||||
`Config file (ae_native_app_config.json) found under ${config_directory}`
|
||||
);
|
||||
} else if (
|
||||
!fs.existsSync(config_path) &&
|
||||
fs.existsSync(default_config_path)
|
||||
) {
|
||||
fs.copyFileSync(default_config_path, config_path);
|
||||
console.log('Default config file copied: ' + config_directory);
|
||||
|
||||
@@ -163,11 +172,16 @@ exports.load_init_config = function () {
|
||||
|
||||
fs.copyFileSync(found_config_path, config_path);
|
||||
console.log(`Found config file copied: ${config_directory}`);
|
||||
} else if (fs.existsSync(path.join(cwd, 'ae_native_app_config.current.json'))) {
|
||||
} else if (
|
||||
fs.existsSync(path.join(cwd, 'ae_native_app_config.current.json'))
|
||||
) {
|
||||
console.log(
|
||||
`Config file (config.json) not found under ${config_directory} or CWD. Using default config in CWD. ${cwd}`
|
||||
);
|
||||
default_config_path = path.join(cwd, 'ae_native_app_config.current.json');
|
||||
default_config_path = path.join(
|
||||
cwd,
|
||||
'ae_native_app_config.current.json'
|
||||
);
|
||||
|
||||
fs.copyFileSync(default_config_path, config_path);
|
||||
console.log(`Default config file copied: ${config_directory}`);
|
||||
@@ -186,31 +200,53 @@ exports.load_init_config = function () {
|
||||
config.home_directory = home_directory; // From the OS platform
|
||||
config.tmp_directory = tmp_directory; // From the OS platform
|
||||
|
||||
config.app_root_path = config.app_root_path.replace('[home]', home_directory);
|
||||
config.app_root_path = config.app_root_path.replace(
|
||||
'[home]',
|
||||
home_directory
|
||||
);
|
||||
config.app_root_path = config.app_root_path.replace('[tmp]', tmp_directory);
|
||||
console.log(`App Root Path: ${config.app_root_path}`);
|
||||
|
||||
config.local_file_cache_path = config.local_file_cache_path.replace('[home]', home_directory);
|
||||
config.local_file_cache_path = config.local_file_cache_path.replace('[tmp]', tmp_directory);
|
||||
config.local_file_cache_path = config.local_file_cache_path.replace(
|
||||
'[home]',
|
||||
home_directory
|
||||
);
|
||||
config.local_file_cache_path = config.local_file_cache_path.replace(
|
||||
'[tmp]',
|
||||
tmp_directory
|
||||
);
|
||||
console.log(`Local File Cache Path: ${config.local_file_cache_path}`);
|
||||
if (fs.existsSync(config.local_file_cache_path)) {
|
||||
} else {
|
||||
fs.mkdirSync(config.local_file_cache_path);
|
||||
console.log(`Host file cache directory created: ${config.local_file_cache_path}`);
|
||||
console.log(
|
||||
`Host file cache directory created: ${config.local_file_cache_path}`
|
||||
);
|
||||
}
|
||||
|
||||
config.host_file_temp_path = config.host_file_temp_path.replace('[home]', home_directory);
|
||||
config.host_file_temp_path = config.host_file_temp_path.replace('[tmp]', tmp_directory);
|
||||
config.host_file_temp_path = config.host_file_temp_path.replace(
|
||||
'[home]',
|
||||
home_directory
|
||||
);
|
||||
config.host_file_temp_path = config.host_file_temp_path.replace(
|
||||
'[tmp]',
|
||||
tmp_directory
|
||||
);
|
||||
console.log(`Host file temp path: ${config.host_file_temp_path}`);
|
||||
if (fs.existsSync(config.host_file_temp_path)) {
|
||||
} else {
|
||||
fs.mkdirSync(config.host_file_temp_path);
|
||||
console.log(`Host file temp directory created: ${config.host_file_temp_path}`);
|
||||
console.log(
|
||||
`Host file temp directory created: ${config.host_file_temp_path}`
|
||||
);
|
||||
}
|
||||
|
||||
// NOTE: This is not ideal...
|
||||
if (!config.account_id) {
|
||||
if (config.event_id == 'pjrcghqwert' || config.event_id == 'nmBfuGFeR0k') {
|
||||
if (
|
||||
config.event_id == 'pjrcghqwert' ||
|
||||
config.event_id == 'nmBfuGFeR0k'
|
||||
) {
|
||||
config.account_id = '_XY7DXtc9MY';
|
||||
} else if (config.event_id == 'r8c-rr-I4-52') {
|
||||
// CMSC
|
||||
@@ -235,11 +271,13 @@ exports.load_init_config = function () {
|
||||
}
|
||||
}
|
||||
|
||||
let import_config_to_ipc_result = ipcRenderer.invoke('import_config', config).then((result) => {
|
||||
console.log('IPC import config finished');
|
||||
// console.log(result);
|
||||
return result; // Result should be "true"
|
||||
});
|
||||
let import_config_to_ipc_result = ipcRenderer
|
||||
.invoke('import_config', config)
|
||||
.then((result) => {
|
||||
console.log('IPC import config finished');
|
||||
// console.log(result);
|
||||
return result; // Result should be "true"
|
||||
});
|
||||
|
||||
//console.log(config);
|
||||
return config;
|
||||
@@ -263,37 +301,52 @@ exports.load_full_config = function (init_config) {
|
||||
new_config.event_location_id = cfg.event_location_id;
|
||||
new_config.event_session_id = cfg.event_session_id;
|
||||
|
||||
new_config.check_event_device_loop_period = cfg.check_event_device_loop_period;
|
||||
new_config.check_event_location_loop_period = cfg.check_event_location_loop_period;
|
||||
new_config.check_event_device_loop_period =
|
||||
cfg.check_event_device_loop_period;
|
||||
new_config.check_event_location_loop_period =
|
||||
cfg.check_event_location_loop_period;
|
||||
new_config.check_event_loop_period = cfg.check_event_loop_period;
|
||||
new_config.check_event_session_loop_period = cfg.check_event_session_loop_period;
|
||||
new_config.check_event_session_loop_period =
|
||||
cfg.check_event_session_loop_period;
|
||||
|
||||
new_config.record_audio = cfg.record_audio;
|
||||
new_config.record_video = cfg.record_video;
|
||||
new_config.recording_path = cfg.recording_path;
|
||||
new_config.recording_path = new_config.recording_path.replace('[home]', home_directory);
|
||||
new_config.recording_path = new_config.recording_path.replace('[tmp]', home_directory);
|
||||
new_config.recording_path = new_config.recording_path.replace(
|
||||
'[home]',
|
||||
home_directory
|
||||
);
|
||||
new_config.recording_path = new_config.recording_path.replace(
|
||||
'[tmp]',
|
||||
home_directory
|
||||
);
|
||||
|
||||
new_config.home_directory = home_directory; // From the OS platform
|
||||
new_config.tmp_directory = tmp_directory; // From the OS platform
|
||||
|
||||
new_config.app_root_path = new_config.app_root_path.replace('[home]', home_directory);
|
||||
new_config.app_root_path = new_config.app_root_path.replace('[tmp]', tmp_directory);
|
||||
console.log(`App Root Path: ${new_config.app_root_path}`);
|
||||
|
||||
new_config.local_file_cache_path = new_config.local_file_cache_path.replace(
|
||||
new_config.app_root_path = new_config.app_root_path.replace(
|
||||
'[home]',
|
||||
home_directory
|
||||
);
|
||||
new_config.local_file_cache_path = new_config.local_file_cache_path.replace(
|
||||
new_config.app_root_path = new_config.app_root_path.replace(
|
||||
'[tmp]',
|
||||
tmp_directory
|
||||
);
|
||||
console.log(`Local File Cache Path: ${new_config.local_file_cache_path}`);
|
||||
console.log(`App Root Path: ${new_config.app_root_path}`);
|
||||
|
||||
new_config.local_file_cache_path =
|
||||
new_config.local_file_cache_path.replace('[home]', home_directory);
|
||||
new_config.local_file_cache_path =
|
||||
new_config.local_file_cache_path.replace('[tmp]', tmp_directory);
|
||||
console.log(
|
||||
`Local File Cache Path: ${new_config.local_file_cache_path}`
|
||||
);
|
||||
if (fs.existsSync(new_config.local_file_cache_path)) {
|
||||
} else {
|
||||
fs.mkdirSync(new_config.local_file_cache_path);
|
||||
console.log(`Host file cache directory created: ${new_config.local_file_cache_path}`);
|
||||
console.log(
|
||||
`Host file cache directory created: ${new_config.local_file_cache_path}`
|
||||
);
|
||||
}
|
||||
|
||||
new_config.host_file_temp_path = new_config.host_file_temp_path.replace(
|
||||
@@ -308,7 +361,9 @@ exports.load_full_config = function (init_config) {
|
||||
if (fs.existsSync(new_config.host_file_temp_path)) {
|
||||
} else {
|
||||
fs.mkdirSync(new_config.host_file_temp_path);
|
||||
console.log(`Host file temp directory created: ${new_config.host_file_temp_path}`);
|
||||
console.log(
|
||||
`Host file temp directory created: ${new_config.host_file_temp_path}`
|
||||
);
|
||||
}
|
||||
|
||||
let import_config_to_ipc_result = ipcRenderer
|
||||
@@ -374,9 +429,13 @@ async function get_url_cfg(cfg) {
|
||||
|
||||
let return_data = response.data['data'];
|
||||
if (Array.isArray(return_data)) {
|
||||
console.log(`Data result is an array/list. Array length: ${return_data.length}`);
|
||||
console.log(
|
||||
`Data result is an array/list. Array length: ${return_data.length}`
|
||||
);
|
||||
} else {
|
||||
console.log(`Data result is a dictionary/object, not an array/list.`);
|
||||
console.log(
|
||||
`Data result is a dictionary/object, not an array/list.`
|
||||
);
|
||||
}
|
||||
return return_data;
|
||||
})
|
||||
@@ -423,7 +482,10 @@ exports.check_local_file = async function ({ local_file_path, filename }) {
|
||||
// Used by Svelte Event Launcher
|
||||
// NOTE: Trying to replace this with something directly in the Svelte app part. 2022-10-11
|
||||
// Updated 2022-05-06
|
||||
exports.check_hash_file_cache = async function ({ local_file_cache_path, hash }) {
|
||||
exports.check_hash_file_cache = async function ({
|
||||
local_file_cache_path,
|
||||
hash
|
||||
}) {
|
||||
// console.log('*** Electron framework export: check_hash_file_cache() ***');
|
||||
// console.log('Check local hash file cache');
|
||||
console.log(
|
||||
@@ -436,7 +498,9 @@ exports.check_hash_file_cache = async function ({ local_file_cache_path, hash })
|
||||
let subdirectory_path = path.join(local_file_cache_path, subdirectory);
|
||||
if (fs.existsSync(subdirectory_path)) {
|
||||
} else {
|
||||
console.log(`Hashed file subdirectory not found in cache: ${subdirectory_path}`);
|
||||
console.log(
|
||||
`Hashed file subdirectory not found in cache: ${subdirectory_path}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -461,12 +525,16 @@ exports.check_hash_file_cache_v2 = async function ({
|
||||
verify_hash = false
|
||||
}) {
|
||||
console.log('*** Aether App Native export: check_hash_file_cache_v2() ***');
|
||||
console.log(`Local File Cache Path: ${local_file_cache_path}; Hash: ${hash}`);
|
||||
console.log(
|
||||
`Local File Cache Path: ${local_file_cache_path}; Hash: ${hash}`
|
||||
);
|
||||
|
||||
if (fs.existsSync(local_file_cache_path)) {
|
||||
} else {
|
||||
// This should not happen. The directory needs to be created.
|
||||
console.log(`Cache directory for hashed files was not found: ${local_file_cache_path}`);
|
||||
console.log(
|
||||
`Cache directory for hashed files was not found: ${local_file_cache_path}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -478,7 +546,9 @@ exports.check_hash_file_cache_v2 = async function ({
|
||||
if (fs.existsSync(subdirectory_path)) {
|
||||
} else {
|
||||
// This should not happen. The subdirectory needs to be created.
|
||||
console.log(`Hashed file subdirectory not found in cache directory: ${subdirectory_path}`);
|
||||
console.log(
|
||||
`Hashed file subdirectory not found in cache directory: ${subdirectory_path}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -589,7 +659,9 @@ exports.download_hash_file_to_cache_v2 = async function ({
|
||||
verify_hash = true,
|
||||
overwrite_existing = false
|
||||
}) {
|
||||
console.log('*** Aether App Native export: download_hash_file_to_cache_v2() ***');
|
||||
console.log(
|
||||
'*** Aether App Native export: download_hash_file_to_cache_v2() ***'
|
||||
);
|
||||
console.log(
|
||||
`Base URL: ${api_base_url}; Base URL Backup: ${api_base_url_backup}; Host File Cache Path: ${local_file_cache_path}; Event File ID: ${event_file_id}; Hash: ${hash}`
|
||||
);
|
||||
@@ -597,7 +669,9 @@ exports.download_hash_file_to_cache_v2 = async function ({
|
||||
if (fs.existsSync(local_file_cache_path)) {
|
||||
} else {
|
||||
// This should not happen. The directory needs to be created.
|
||||
console.log(`Cache directory for hashed files was not found: ${local_file_cache_path}`);
|
||||
console.log(
|
||||
`Cache directory for hashed files was not found: ${local_file_cache_path}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -668,7 +742,9 @@ exports.download_hash_file_to_cache_v2 = async function ({
|
||||
|
||||
let current_datetime = new Date();
|
||||
let offset_minutes = 3; // In minutes. 5 minutes of no changes to the file content seems reasonable? Trying with 3 minutes 2022-10-12
|
||||
let offset_datetime = new Date(current_datetime.getTime() - offset_minutes * 60000);
|
||||
let offset_datetime = new Date(
|
||||
current_datetime.getTime() - offset_minutes * 60000
|
||||
);
|
||||
|
||||
// console.log(`Times: ${current_datetime} ${offset_datetime} | File ${stats.mtime}`);
|
||||
if (stats.mtime < offset_datetime) {
|
||||
@@ -696,10 +772,15 @@ exports.download_hash_file_to_cache_v2 = async function ({
|
||||
)
|
||||
.then(async (result) => {
|
||||
if (result) {
|
||||
console.log(`IPC API download file process finished successfully: ${hash}`);
|
||||
console.log(
|
||||
`IPC API download file process finished successfully: ${hash}`
|
||||
);
|
||||
return true;
|
||||
} else if (result == null) {
|
||||
console.log(`IPC API download result (file not found?):`, result);
|
||||
console.log(
|
||||
`IPC API download result (file not found?):`,
|
||||
result
|
||||
);
|
||||
return null;
|
||||
} else if (result === 'in_progress') {
|
||||
console.log(`IPC API primary download IN PROGRESS: ${hash}`);
|
||||
@@ -744,7 +825,9 @@ exports.download_hash_file_to_cache_v2 = async function ({
|
||||
console.log(
|
||||
`IPC API primary download FAILED! Trying again with backup API server. API Backup: ${api_base_url_backup}`
|
||||
);
|
||||
console.log(`Trying IPC API backup download from: ${api_base_url_backup}`);
|
||||
console.log(
|
||||
`Trying IPC API backup download from: ${api_base_url_backup}`
|
||||
);
|
||||
let download_backup_file_result = await ipcRenderer
|
||||
.invoke(
|
||||
'download_file',
|
||||
@@ -832,12 +915,20 @@ exports.open_hash_file_to_temp = async function ({
|
||||
let subdirectory_path = path.join(local_file_cache_path, subdirectory);
|
||||
if (fs.existsSync(subdirectory_path)) {
|
||||
} else {
|
||||
console.log(`Hashed file subdirectory not found in cache: ${subdirectory_path}`);
|
||||
console.log(
|
||||
`Hashed file subdirectory not found in cache: ${subdirectory_path}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
let open_hash_file_to_temp_result = await ipcRenderer
|
||||
.invoke('open_hash_file_to_temp', subdirectory_path, hash, host_file_temp_path, filename)
|
||||
.invoke(
|
||||
'open_hash_file_to_temp',
|
||||
subdirectory_path,
|
||||
hash,
|
||||
host_file_temp_path,
|
||||
filename
|
||||
)
|
||||
.then((result) => {
|
||||
console.log('IPC open hash file to temp finished');
|
||||
console.log(result);
|
||||
@@ -868,7 +959,9 @@ exports.open_hash_file_to_temp_v2 = async function ({
|
||||
filename,
|
||||
verify_hash = true
|
||||
}) {
|
||||
console.log('*** Aether App Native export: open_hash_file_to_temp_v2() ***');
|
||||
console.log(
|
||||
'*** Aether App Native export: open_hash_file_to_temp_v2() ***'
|
||||
);
|
||||
console.log(
|
||||
`Local File Cache Path: ${local_file_cache_path}; Hash: ${hash}; Local File Temp Path: ${host_file_temp_path}; Filename: ${filename}`
|
||||
);
|
||||
@@ -878,7 +971,9 @@ exports.open_hash_file_to_temp_v2 = async function ({
|
||||
if (fs.existsSync(local_file_cache_path)) {
|
||||
} else {
|
||||
// This should not happen. The directory needs to be created.
|
||||
console.log(`Cache directory for hashed files was not found: ${local_file_cache_path}`);
|
||||
console.log(
|
||||
`Cache directory for hashed files was not found: ${local_file_cache_path}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -890,7 +985,9 @@ exports.open_hash_file_to_temp_v2 = async function ({
|
||||
if (fs.existsSync(subdirectory_path)) {
|
||||
} else {
|
||||
// This should not happen. The subdirectory needs to be created.
|
||||
console.log(`Hashed file subdirectory not found in cache directory: ${subdirectory_path}`);
|
||||
console.log(
|
||||
`Hashed file subdirectory not found in cache directory: ${subdirectory_path}`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1066,7 +1163,12 @@ exports.open_local_file = async function ({ local_file_path, filename }) {
|
||||
|
||||
// Check local file cache and download from server if needed. Must use IPC to Main to download file. Set a Promise to wait for download_file_reply.
|
||||
// Updated 2022-03-09
|
||||
async function check_file_cache({ api_base_url, local_file_cache_path, event_file_id, hash }) {
|
||||
async function check_file_cache({
|
||||
api_base_url,
|
||||
local_file_cache_path,
|
||||
event_file_id,
|
||||
hash
|
||||
}) {
|
||||
console.log('*** Electron framework: check_file_cache() ***');
|
||||
// console.log('Check local file cache and download from server if needed.');
|
||||
console.log(
|
||||
@@ -1083,9 +1185,17 @@ async function check_file_cache({ api_base_url, local_file_cache_path, event_fil
|
||||
console.log('Hashed file cache already exists: ' + save_path);
|
||||
return true;
|
||||
} else {
|
||||
console.log('Hashed file not found in local cache. Downloading file: ' + save_path);
|
||||
console.log(
|
||||
'Hashed file not found in local cache. Downloading file: ' +
|
||||
save_path
|
||||
);
|
||||
let endpoint = `/event/file/${event_file_id}/download`;
|
||||
let result = await ipcRenderer.send('download_file', api_base_url, endpoint, save_path); // Must download file using main node.js thread.
|
||||
let result = await ipcRenderer.send(
|
||||
'download_file',
|
||||
api_base_url,
|
||||
endpoint,
|
||||
save_path
|
||||
); // Must download file using main node.js thread.
|
||||
console.log(result);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -1122,7 +1232,12 @@ async function check_file_cache({ api_base_url, local_file_cache_path, event_fil
|
||||
|
||||
// IPC to Main: Open local file cache if available. Copy to temp directory with given filename first.
|
||||
// Updated 2022-03-09
|
||||
async function open_local_file({ local_file_cache_path, hash, host_file_temp_path, filename }) {
|
||||
async function open_local_file({
|
||||
local_file_cache_path,
|
||||
hash,
|
||||
host_file_temp_path,
|
||||
filename
|
||||
}) {
|
||||
console.log('*** Electron framework: open_local_file() ***');
|
||||
// console.log('Open local file cache if available. Copy to temp directory with given filename first.');
|
||||
console.log(
|
||||
@@ -1153,7 +1268,9 @@ exports.check_file_cache_and_open_local_file = async function ({
|
||||
host_file_temp_path,
|
||||
filename
|
||||
}) {
|
||||
console.log('*** Electron framework: check_file_cache_and_open_local_file() ***');
|
||||
console.log(
|
||||
'*** Electron framework: check_file_cache_and_open_local_file() ***'
|
||||
);
|
||||
console.log(
|
||||
'Checking the local file cache against the remote server and then opening the local file.'
|
||||
);
|
||||
@@ -1349,7 +1466,9 @@ exports.run_cmd = async function ({
|
||||
// Resolve placeholders in the command string
|
||||
let cleaned_cmd = cmd;
|
||||
if (cmd && typeof cmd === 'string') {
|
||||
cleaned_cmd = cmd.replace(/\[home\]/g, home_directory).replace(/\[tmp\]/g, tmp_directory);
|
||||
cleaned_cmd = cmd
|
||||
.replace(/\[home\]/g, home_directory)
|
||||
.replace(/\[tmp\]/g, tmp_directory);
|
||||
}
|
||||
|
||||
console.log(`Command String: ${cleaned_cmd}`);
|
||||
@@ -1402,13 +1521,19 @@ exports.run_cmd = async function ({
|
||||
|
||||
// Run raw command sync
|
||||
// Updated 2026-01-26
|
||||
exports.run_cmd_sync = function ({ cmd = null, return_stdout = null, return_stdin = null }) {
|
||||
exports.run_cmd_sync = function ({
|
||||
cmd = null,
|
||||
return_stdout = null,
|
||||
return_stdin = null
|
||||
}) {
|
||||
console.log('*** Electron framework export: run_cmd_sync() ***');
|
||||
|
||||
// Resolve placeholders in the command string
|
||||
let cleaned_cmd = cmd;
|
||||
if (cmd && typeof cmd === 'string') {
|
||||
cleaned_cmd = cmd.replace(/\[home\]/g, home_directory).replace(/\[tmp\]/g, tmp_directory);
|
||||
cleaned_cmd = cmd
|
||||
.replace(/\[home\]/g, home_directory)
|
||||
.replace(/\[tmp\]/g, tmp_directory);
|
||||
}
|
||||
|
||||
console.log(`Command String: ${cleaned_cmd}`);
|
||||
@@ -1451,7 +1576,7 @@ exports.get_device_info = async function () {
|
||||
data['release'] = os.release();
|
||||
data['uptime'] = os.uptime();
|
||||
data['version'] = os.version();
|
||||
|
||||
|
||||
// Add directory info for placeholder resolution in UI
|
||||
data['home_directory'] = home_directory;
|
||||
data['tmp_directory'] = tmp_directory;
|
||||
@@ -1465,19 +1590,23 @@ exports.get_device_info = async function () {
|
||||
* Moves a file from the hashed cache to the operational temp directory
|
||||
* and triggers the system launcher.
|
||||
*/
|
||||
exports.launch_from_cache = async function ({
|
||||
cache_root,
|
||||
hash,
|
||||
temp_root,
|
||||
filename,
|
||||
hash_prefix_length = 2
|
||||
exports.launch_from_cache = async function ({
|
||||
cache_root,
|
||||
hash,
|
||||
temp_root,
|
||||
filename,
|
||||
hash_prefix_length = 2
|
||||
}) {
|
||||
console.log('*** Aether App Native export: launch_from_cache() ***');
|
||||
|
||||
|
||||
// 1. Resolve Path Placeholders (using global regex)
|
||||
const clean_cache_root = cache_root.replace(/\[home\]/g, home_directory).replace(/\[tmp\]/g, tmp_directory);
|
||||
const clean_temp_root = temp_root.replace(/\[home\]/g, home_directory).replace(/\[tmp\]/g, tmp_directory);
|
||||
|
||||
const clean_cache_root = cache_root
|
||||
.replace(/\[home\]/g, home_directory)
|
||||
.replace(/\[tmp\]/g, tmp_directory);
|
||||
const clean_temp_root = temp_root
|
||||
.replace(/\[home\]/g, home_directory)
|
||||
.replace(/\[tmp\]/g, tmp_directory);
|
||||
|
||||
const hash_filename = `${hash}.file`;
|
||||
const prefix = hash.substring(0, hash_prefix_length);
|
||||
const source_path = path.join(clean_cache_root, prefix, hash_filename);
|
||||
@@ -1506,15 +1635,14 @@ exports.launch_from_cache = async function ({
|
||||
const is_pres = ['pptx', 'ppt', 'key', 'pdf', 'odp'].includes(ext);
|
||||
|
||||
if (is_pres) {
|
||||
return await exports.launch_presentation({
|
||||
path: dest_path,
|
||||
app: ext === 'key' ? 'keynote' : 'default'
|
||||
return await exports.launch_presentation({
|
||||
path: dest_path,
|
||||
app: ext === 'key' ? 'keynote' : 'default'
|
||||
});
|
||||
}
|
||||
|
||||
// 6. Default Fallback
|
||||
return await ipcRenderer.invoke('open_local_file', '', dest_path);
|
||||
|
||||
} catch (err) {
|
||||
console.error('Launch Error:', err);
|
||||
return { success: false, error: err.message };
|
||||
@@ -1523,23 +1651,25 @@ exports.launch_from_cache = async function ({
|
||||
|
||||
/**
|
||||
* Specialized Presentation Launcher (Phase 5)
|
||||
* Handles platform-specific application selection (LibreOffice on Linux,
|
||||
* Handles platform-specific application selection (LibreOffice on Linux,
|
||||
* PowerPoint/Keynote on macOS).
|
||||
* Updated 2026-01-26
|
||||
*/
|
||||
exports.launch_presentation = async function ({
|
||||
path: raw_path,
|
||||
exports.launch_presentation = async function ({
|
||||
path: raw_path,
|
||||
app = 'default',
|
||||
os_platform = 'auto'
|
||||
}) {
|
||||
console.log('*** Aether App Native export: launch_presentation() ***');
|
||||
|
||||
|
||||
// Resolve placeholders if they exist in the incoming path (using global regex)
|
||||
let cleaned_path = raw_path
|
||||
.replace(/\[home\]/g, home_directory)
|
||||
.replace(/\[tmp\]/g, tmp_directory);
|
||||
|
||||
console.log(`Raw Path: ${raw_path}; Cleaned Path: ${cleaned_path}; App: ${app}; OS: ${os_platform}`);
|
||||
console.log(
|
||||
`Raw Path: ${raw_path}; Cleaned Path: ${cleaned_path}; App: ${app}; OS: ${os_platform}`
|
||||
);
|
||||
|
||||
// 1. Detect OS
|
||||
let platform = os_platform;
|
||||
@@ -1549,9 +1679,11 @@ exports.launch_presentation = async function ({
|
||||
|
||||
// 2. Handle Linux (LibreOffice Testing)
|
||||
if (platform === 'linux') {
|
||||
console.log(`Native: Launching LibreOffice on Linux for path: ${cleaned_path}`);
|
||||
console.log(
|
||||
`Native: Launching LibreOffice on Linux for path: ${cleaned_path}`
|
||||
);
|
||||
const cmd = `libreoffice --impress "${cleaned_path}"`;
|
||||
|
||||
|
||||
return new Promise((resolve) => {
|
||||
child_process.exec(cmd, (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
@@ -1570,7 +1702,7 @@ exports.launch_presentation = async function ({
|
||||
const script = `tell application "Keynote" to open POSIX file "${cleaned_path}"`;
|
||||
return exports.run_osascript({ cmd: script });
|
||||
}
|
||||
|
||||
|
||||
// Default to shell open
|
||||
return ipcRenderer.invoke('open_local_file', '', cleaned_path);
|
||||
}
|
||||
@@ -1622,7 +1754,9 @@ exports.check_and_get_updated_native_app_config = function ({
|
||||
file_path = 'device_configs/ae_native_app_config.default.json',
|
||||
overwrite = false
|
||||
}) {
|
||||
console.log('*** Aether App Native export: check_and_get_updated_native_app_config() ***');
|
||||
console.log(
|
||||
'*** Aether App Native export: check_and_get_updated_native_app_config() ***'
|
||||
);
|
||||
|
||||
if (os.platform == 'darwin') {
|
||||
let default_osit_sync_app_config_path = path.join(
|
||||
@@ -1630,17 +1764,33 @@ exports.check_and_get_updated_native_app_config = function ({
|
||||
file_path
|
||||
);
|
||||
|
||||
let default_app_config_path = path.join(app_root_path, 'ae_native_app_config.default.json');
|
||||
console.log('macOS app root and config directory: ' + default_app_config_path);
|
||||
let default_app_config_path = path.join(
|
||||
app_root_path,
|
||||
'ae_native_app_config.default.json'
|
||||
);
|
||||
console.log(
|
||||
'macOS app root and config directory: ' + default_app_config_path
|
||||
);
|
||||
|
||||
fs.copyFileSync(default_osit_sync_app_config_path, default_app_config_path);
|
||||
fs.copyFileSync(
|
||||
default_osit_sync_app_config_path,
|
||||
default_app_config_path
|
||||
);
|
||||
|
||||
if (overwrite) {
|
||||
console.log('Overwriting the current active config file...');
|
||||
let active_app_config_path = path.join(app_root_path, 'ae_native_app_config.json');
|
||||
console.log('macOS app root and config directory: ' + active_app_config_path);
|
||||
let active_app_config_path = path.join(
|
||||
app_root_path,
|
||||
'ae_native_app_config.json'
|
||||
);
|
||||
console.log(
|
||||
'macOS app root and config directory: ' + active_app_config_path
|
||||
);
|
||||
|
||||
fs.copyFileSync(default_osit_sync_app_config_path, active_app_config_path);
|
||||
fs.copyFileSync(
|
||||
default_osit_sync_app_config_path,
|
||||
active_app_config_path
|
||||
);
|
||||
}
|
||||
} else if (os.platform == 'linux') {
|
||||
app_root_path = path.join(home_directory, '.config/OSIT');
|
||||
|
||||
@@ -7,51 +7,107 @@ import { ae_loc, ae_api, ae_sess, slct } from '$lib/stores/ae_stores';
|
||||
* Standardizes all IPC calls to snake_case.
|
||||
*/
|
||||
|
||||
const native = (typeof window !== 'undefined') ? (window as any).aetherNative : null;
|
||||
const native =
|
||||
typeof window !== 'undefined' ? (window as any).aetherNative : null;
|
||||
|
||||
export const is_native = !!native;
|
||||
|
||||
// 1. Core Config
|
||||
export async function get_device_config() {
|
||||
if (!native) return null;
|
||||
return await native.get_device_config();
|
||||
if (!native) return null;
|
||||
return await native.get_device_config();
|
||||
}
|
||||
|
||||
export async function get_device_info() {
|
||||
if (!native) return null;
|
||||
return await native.get_device_info();
|
||||
if (!native) return null;
|
||||
return await native.get_device_info();
|
||||
}
|
||||
|
||||
// 2. File & Cache Management
|
||||
export async function check_hash_file_cache({ cache_root, hash, hash_prefix_length = 2, verify_hash = false }: any) {
|
||||
if (!native) return false;
|
||||
return await native.check_cache({ cache_root, hash, hash_prefix_length, verify_hash });
|
||||
export async function check_hash_file_cache({
|
||||
cache_root,
|
||||
hash,
|
||||
hash_prefix_length = 2,
|
||||
verify_hash = false
|
||||
}: any) {
|
||||
if (!native) return false;
|
||||
return await native.check_cache({
|
||||
cache_root,
|
||||
hash,
|
||||
hash_prefix_length,
|
||||
verify_hash
|
||||
});
|
||||
}
|
||||
|
||||
export async function download_to_cache({ url, cache_root, hash, api_key, account_id, hash_prefix_length = 2 }: any) {
|
||||
if (!native) return { success: false, error: 'Native bridge not available' };
|
||||
return await native.download_to_cache({ url, cache_root, hash, api_key, account_id, hash_prefix_length });
|
||||
export async function download_to_cache({
|
||||
url,
|
||||
cache_root,
|
||||
hash,
|
||||
api_key,
|
||||
account_id,
|
||||
hash_prefix_length = 2
|
||||
}: any) {
|
||||
if (!native)
|
||||
return { success: false, error: 'Native bridge not available' };
|
||||
return await native.download_to_cache({
|
||||
url,
|
||||
cache_root,
|
||||
hash,
|
||||
api_key,
|
||||
account_id,
|
||||
hash_prefix_length
|
||||
});
|
||||
}
|
||||
|
||||
export async function launch_from_cache({ cache_root, hash, temp_root, filename, hash_prefix_length = 2 }: any) {
|
||||
if (!native) return { success: false, error: 'Native bridge not available' };
|
||||
return await native.launch_from_cache({ cache_root, hash, temp_root, filename, hash_prefix_length });
|
||||
export async function launch_from_cache({
|
||||
cache_root,
|
||||
hash,
|
||||
temp_root,
|
||||
filename,
|
||||
hash_prefix_length = 2
|
||||
}: any) {
|
||||
if (!native)
|
||||
return { success: false, error: 'Native bridge not available' };
|
||||
return await native.launch_from_cache({
|
||||
cache_root,
|
||||
hash,
|
||||
temp_root,
|
||||
filename,
|
||||
hash_prefix_length
|
||||
});
|
||||
}
|
||||
|
||||
// 3. OS Shell Commands (Phase 3)
|
||||
export async function open_folder(path: string) {
|
||||
if (!native) return { success: false, error: 'Native bridge not available' };
|
||||
return await native.open_folder(path);
|
||||
if (!native)
|
||||
return { success: false, error: 'Native bridge not available' };
|
||||
return await native.open_folder(path);
|
||||
}
|
||||
|
||||
export async function run_cmd({ cmd, timeout = 30000, return_stdout = true }: { cmd: string, timeout?: number, return_stdout?: boolean }) {
|
||||
if (!native) return { success: false, error: 'Native bridge not available' };
|
||||
return await native.run_cmd({ cmd, timeout, return_stdout });
|
||||
export async function run_cmd({
|
||||
cmd,
|
||||
timeout = 30000,
|
||||
return_stdout = true
|
||||
}: {
|
||||
cmd: string;
|
||||
timeout?: number;
|
||||
return_stdout?: boolean;
|
||||
}) {
|
||||
if (!native)
|
||||
return { success: false, error: 'Native bridge not available' };
|
||||
return await native.run_cmd({ cmd, timeout, return_stdout });
|
||||
}
|
||||
|
||||
export async function run_cmd_sync({ cmd, return_stdout = true }: { cmd: string, return_stdout?: boolean }) {
|
||||
if (!native) return { success: false, error: 'Native bridge not available' };
|
||||
return await native.run_cmd_sync({ cmd, return_stdout });
|
||||
export async function run_cmd_sync({
|
||||
cmd,
|
||||
return_stdout = true
|
||||
}: {
|
||||
cmd: string;
|
||||
return_stdout?: boolean;
|
||||
}) {
|
||||
if (!native)
|
||||
return { success: false, error: 'Native bridge not available' };
|
||||
return await native.run_cmd_sync({ cmd, return_stdout });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,30 +116,44 @@ export async function run_cmd_sync({ cmd, return_stdout = true }: { cmd: string,
|
||||
* Called at launcher startup to prevent cache directory bloat from interrupted downloads.
|
||||
* Default: 1440 minutes = 24 hours.
|
||||
*/
|
||||
export async function cleanup_tmp_files({ cache_root, max_age_minutes = 1440 }: { cache_root: string, max_age_minutes?: number }) {
|
||||
if (!native) return { success: false, error: 'Native bridge not available' };
|
||||
export async function cleanup_tmp_files({
|
||||
cache_root,
|
||||
max_age_minutes = 1440
|
||||
}: {
|
||||
cache_root: string;
|
||||
max_age_minutes?: number;
|
||||
}) {
|
||||
if (!native)
|
||||
return { success: false, error: 'Native bridge not available' };
|
||||
const cmd = `find "${cache_root}" -name "*.tmp" -mmin +${max_age_minutes} -type f -delete`;
|
||||
return await native.run_cmd({ cmd, timeout: 30000, return_stdout: false });
|
||||
}
|
||||
|
||||
export async function run_osascript(script: string) {
|
||||
if (!native) return { success: false, error: 'Native bridge not available' };
|
||||
return await native.run_osascript(script);
|
||||
if (!native)
|
||||
return { success: false, error: 'Native bridge not available' };
|
||||
return await native.run_osascript(script);
|
||||
}
|
||||
|
||||
export async function kill_processes({ process_name_li = [] }: { process_name_li: string[] }) {
|
||||
if (!native) return { success: false, error: 'Native bridge not available' };
|
||||
return await native.kill_processes({ process_name_li });
|
||||
export async function kill_processes({
|
||||
process_name_li = []
|
||||
}: {
|
||||
process_name_li: string[];
|
||||
}) {
|
||||
if (!native)
|
||||
return { success: false, error: 'Native bridge not available' };
|
||||
return await native.kill_processes({ process_name_li });
|
||||
}
|
||||
|
||||
export async function open_local_file_v2(path: string) {
|
||||
if (!native) return { success: false, error: 'Native bridge not available' };
|
||||
return await native.open_local_file_v2(path);
|
||||
if (!native)
|
||||
return { success: false, error: 'Native bridge not available' };
|
||||
return await native.open_local_file_v2(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized Presentation Launcher (Phase 5)
|
||||
* Handles platform-specific application selection (LibreOffice on Linux,
|
||||
* Handles platform-specific application selection (LibreOffice on Linux,
|
||||
* PowerPoint/Keynote on macOS).
|
||||
*/
|
||||
export async function launch_presentation({
|
||||
@@ -92,36 +162,49 @@ export async function launch_presentation({
|
||||
os = 'auto',
|
||||
log_lvl = 0
|
||||
}: {
|
||||
path: string,
|
||||
app?: 'default' | 'powerpoint' | 'keynote' | 'libreoffice',
|
||||
os?: 'auto' | 'linux' | 'darwin' | 'win32',
|
||||
log_lvl?: number
|
||||
path: string;
|
||||
app?: 'default' | 'powerpoint' | 'keynote' | 'libreoffice';
|
||||
os?: 'auto' | 'linux' | 'darwin' | 'win32';
|
||||
log_lvl?: number;
|
||||
}) {
|
||||
if (!native) return { success: false, error: 'Native bridge not available' };
|
||||
if (!native)
|
||||
return { success: false, error: 'Native bridge not available' };
|
||||
|
||||
// 1. Detect OS if set to auto
|
||||
let platform = os;
|
||||
if (platform === 'auto') {
|
||||
const info = await get_device_info();
|
||||
platform = info?.platform || 'linux';
|
||||
platform = info?.platform || 'linux';
|
||||
}
|
||||
|
||||
// 2. Prefer the Native Bridge implementation (Atomic Copy-and-Launch)
|
||||
// This delegates to the hardened logic in electron_native.js
|
||||
if (native.launch_presentation) {
|
||||
if (log_lvl) console.log('Relay: Using native.launch_presentation');
|
||||
return await native.launch_presentation({ path, app, os_platform: platform });
|
||||
return await native.launch_presentation({
|
||||
path,
|
||||
app,
|
||||
os_platform: platform
|
||||
});
|
||||
}
|
||||
|
||||
// 3. Relay-side Fallback (Mock/Legacy)
|
||||
// Manually resolve placeholders using all available context
|
||||
const info = await get_device_info();
|
||||
const loc = get(ae_loc);
|
||||
|
||||
|
||||
// Attempt to find home/tmp from bridge info OR local hydrated store
|
||||
const home = info?.home_directory || loc.home_directory || loc.native_device?.home_directory || '';
|
||||
const tmp = info?.tmp_directory || loc.tmp_directory || loc.native_device?.tmp_directory || '';
|
||||
|
||||
const home =
|
||||
info?.home_directory ||
|
||||
loc.home_directory ||
|
||||
loc.native_device?.home_directory ||
|
||||
'';
|
||||
const tmp =
|
||||
info?.tmp_directory ||
|
||||
loc.tmp_directory ||
|
||||
loc.native_device?.tmp_directory ||
|
||||
'';
|
||||
|
||||
if (log_lvl) console.log('Relay Debug:', { home, tmp, raw_path: path });
|
||||
|
||||
// CRITICAL: Resolve all instances of placeholders using global regex
|
||||
@@ -129,22 +212,33 @@ export async function launch_presentation({
|
||||
if (home) cleaned_path = cleaned_path.replace(/\[home\]/g, home);
|
||||
if (tmp) cleaned_path = cleaned_path.replace(/\[tmp\]/g, tmp);
|
||||
|
||||
if (log_lvl) console.log(`Relay Fallback: Resolving ${path} -> ${cleaned_path}`);
|
||||
if (log_lvl)
|
||||
console.log(`Relay Fallback: Resolving ${path} -> ${cleaned_path}`);
|
||||
|
||||
// If path still contains [home] or [tmp], it means we failed to resolve it.
|
||||
if (cleaned_path.includes('[home]') || cleaned_path.includes('[tmp]')) {
|
||||
console.error('Relay Error: Could not resolve path placeholders. Home or Tmp directory unknown.', { home, tmp });
|
||||
console.error(
|
||||
'Relay Error: Could not resolve path placeholders. Home or Tmp directory unknown.',
|
||||
{ home, tmp }
|
||||
);
|
||||
return { success: false, error: 'Could not resolve path placeholders' };
|
||||
}
|
||||
|
||||
if (platform === 'linux') {
|
||||
if (log_lvl) console.log(`Relay: Launching LibreOffice on Linux for path: ${cleaned_path}`);
|
||||
return await run_cmd({ cmd: `libreoffice --impress "${cleaned_path}"` });
|
||||
if (log_lvl)
|
||||
console.log(
|
||||
`Relay: Launching LibreOffice on Linux for path: ${cleaned_path}`
|
||||
);
|
||||
return await run_cmd({
|
||||
cmd: `libreoffice --impress "${cleaned_path}"`
|
||||
});
|
||||
}
|
||||
|
||||
if (platform === 'darwin') {
|
||||
if (app === 'keynote') {
|
||||
return await run_osascript(`tell application "Keynote" to open POSIX file "${cleaned_path}"`);
|
||||
return await run_osascript(
|
||||
`tell application "Keynote" to open POSIX file "${cleaned_path}"`
|
||||
);
|
||||
}
|
||||
return await open_local_file_v2(cleaned_path);
|
||||
}
|
||||
@@ -160,11 +254,12 @@ export async function control_presentation({
|
||||
app,
|
||||
action
|
||||
}: {
|
||||
app: 'powerpoint' | 'keynote',
|
||||
action: 'next' | 'prev' | 'start' | 'stop'
|
||||
app: 'powerpoint' | 'keynote';
|
||||
action: 'next' | 'prev' | 'start' | 'stop';
|
||||
}) {
|
||||
if (!native) return { success: false, error: 'Native bridge not available' };
|
||||
|
||||
if (!native)
|
||||
return { success: false, error: 'Native bridge not available' };
|
||||
|
||||
// Check if the native bridge has the direct implementation
|
||||
if (native.control_presentation) {
|
||||
return await native.control_presentation({ app, action });
|
||||
@@ -174,17 +269,37 @@ export async function control_presentation({
|
||||
let script = '';
|
||||
if (app === 'powerpoint') {
|
||||
switch (action) {
|
||||
case 'next': script = 'tell application "Microsoft PowerPoint" to next slide of slide show view of active presentation'; break;
|
||||
case 'prev': script = 'tell application "Microsoft PowerPoint" to previous slide of slide show view of active presentation'; break;
|
||||
case 'start': script = 'tell application "Microsoft PowerPoint" to run slide show of active presentation'; break;
|
||||
case 'stop': script = 'tell application "Microsoft PowerPoint" to stop slide show of active presentation'; break;
|
||||
case 'next':
|
||||
script =
|
||||
'tell application "Microsoft PowerPoint" to next slide of slide show view of active presentation';
|
||||
break;
|
||||
case 'prev':
|
||||
script =
|
||||
'tell application "Microsoft PowerPoint" to previous slide of slide show view of active presentation';
|
||||
break;
|
||||
case 'start':
|
||||
script =
|
||||
'tell application "Microsoft PowerPoint" to run slide show of active presentation';
|
||||
break;
|
||||
case 'stop':
|
||||
script =
|
||||
'tell application "Microsoft PowerPoint" to stop slide show of active presentation';
|
||||
break;
|
||||
}
|
||||
} else if (app === 'keynote') {
|
||||
switch (action) {
|
||||
case 'next': script = 'tell application "Keynote" to show next'; break;
|
||||
case 'prev': script = 'tell application "Keynote" to show previous'; break;
|
||||
case 'start': script = 'tell application "Keynote" to start (front document)'; break;
|
||||
case 'stop': script = 'tell application "Keynote" to stop'; break;
|
||||
case 'next':
|
||||
script = 'tell application "Keynote" to show next';
|
||||
break;
|
||||
case 'prev':
|
||||
script = 'tell application "Keynote" to show previous';
|
||||
break;
|
||||
case 'start':
|
||||
script = 'tell application "Keynote" to start (front document)';
|
||||
break;
|
||||
case 'stop':
|
||||
script = 'tell application "Keynote" to stop';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,43 +307,106 @@ export async function control_presentation({
|
||||
return await run_osascript(script);
|
||||
}
|
||||
|
||||
return { success: false, error: `Unsupported app or action: ${app}/${action}` };
|
||||
return {
|
||||
success: false,
|
||||
error: `Unsupported app or action: ${app}/${action}`
|
||||
};
|
||||
}
|
||||
|
||||
// 4. System Management (Phase 5+)
|
||||
|
||||
export async function set_wallpaper({ path }: { path: string }) {
|
||||
if (!native || !native.set_wallpaper) return { success: false, error: 'Native handler set_wallpaper not available' };
|
||||
if (!native || !native.set_wallpaper)
|
||||
return {
|
||||
success: false,
|
||||
error: 'Native handler set_wallpaper not available'
|
||||
};
|
||||
return await native.set_wallpaper({ path });
|
||||
}
|
||||
|
||||
export async function update_app(args: { source: 'url' | 'file', url?: string, path?: string }) {
|
||||
if (!native || !native.update_app) return { success: false, error: 'Native handler update_app not available' };
|
||||
export async function update_app(args: {
|
||||
source: 'url' | 'file';
|
||||
url?: string;
|
||||
path?: string;
|
||||
}) {
|
||||
if (!native || !native.update_app)
|
||||
return {
|
||||
success: false,
|
||||
error: 'Native handler update_app not available'
|
||||
};
|
||||
return await native.update_app(args);
|
||||
}
|
||||
|
||||
export async function window_control({ action, value }: { action: string, value?: any }) {
|
||||
if (!native || !native.window_control) return { success: false, error: 'Native handler window_control not available' };
|
||||
export async function window_control({
|
||||
action,
|
||||
value
|
||||
}: {
|
||||
action: string;
|
||||
value?: any;
|
||||
}) {
|
||||
if (!native || !native.window_control)
|
||||
return {
|
||||
success: false,
|
||||
error: 'Native handler window_control not available'
|
||||
};
|
||||
return await native.window_control({ action, value });
|
||||
}
|
||||
|
||||
export async function manage_recording({ action, options }: { action: 'start' | 'stop' | 'status', options?: any }) {
|
||||
if (!native || !native.manage_recording) return { success: false, error: 'Native handler manage_recording not available' };
|
||||
export async function manage_recording({
|
||||
action,
|
||||
options
|
||||
}: {
|
||||
action: 'start' | 'stop' | 'status';
|
||||
options?: any;
|
||||
}) {
|
||||
if (!native || !native.manage_recording)
|
||||
return {
|
||||
success: false,
|
||||
error: 'Native handler manage_recording not available'
|
||||
};
|
||||
return await native.manage_recording({ action, options });
|
||||
}
|
||||
|
||||
export async function set_display_layout({ mode, configStr }: { mode: 'mirror' | 'extend', configStr?: string }) {
|
||||
if (!native || !native.set_display_layout) return { success: false, error: 'Native handler set_display_layout not available' };
|
||||
export async function set_display_layout({
|
||||
mode,
|
||||
configStr
|
||||
}: {
|
||||
mode: 'mirror' | 'extend';
|
||||
configStr?: string;
|
||||
}) {
|
||||
if (!native || !native.set_display_layout)
|
||||
return {
|
||||
success: false,
|
||||
error: 'Native handler set_display_layout not available'
|
||||
};
|
||||
return await native.set_display_layout({ mode, configStr });
|
||||
}
|
||||
|
||||
export async function power_control({ action }: { action: 'shutdown' | 'reboot' | 'sleep' }) {
|
||||
if (!native || !native.power_control) return { success: false, error: 'Native handler power_control not available' };
|
||||
export async function power_control({
|
||||
action
|
||||
}: {
|
||||
action: 'shutdown' | 'reboot' | 'sleep';
|
||||
}) {
|
||||
if (!native || !native.power_control)
|
||||
return {
|
||||
success: false,
|
||||
error: 'Native handler power_control not available'
|
||||
};
|
||||
return await native.power_control({ action });
|
||||
}
|
||||
|
||||
export async function open_external({ url, app }: { url: string, app?: 'chrome' | 'firefox' | 'default' }) {
|
||||
if (!native || !native.open_external) return { success: false, error: 'Native handler open_external not available' };
|
||||
export async function open_external({
|
||||
url,
|
||||
app
|
||||
}: {
|
||||
url: string;
|
||||
app?: 'chrome' | 'firefox' | 'default';
|
||||
}) {
|
||||
if (!native || !native.open_external)
|
||||
return {
|
||||
success: false,
|
||||
error: 'Native handler open_external not available'
|
||||
};
|
||||
return await native.open_external({ url, app });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user