Files
OSIT-AE-App-Svelte/src/lib/electron/electron_native.js
Scott Idem b5b44e4016 feat(launcher): harden native caching and telemetry; consolidate documentation
- Implemented SHA-256 integrity checks and stale temp purge in native download logic.\n- Enabled strict hash verification in background sync cycle.\n- Made CPU load gauge dynamic using real-time loadavg metadata.\n- Consolidated native app documentation into single master manual.\n- Marked legacy electron_native.js as deprecated.\n- Updated roadmap with temp cleanup and launch protection tasks.
2026-02-10 14:07:45 -05:00

1656 lines
62 KiB
JavaScript

// [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
'use strict';
/* This should only contain functions that can not be pulled easily into Svelte */
/*
Exported functions in use:
* load_config()
* check_hash_file_cache()
* download_hash_file_to_cache()
* open_hash_file_to_temp()
* open_local_file()
* kill_processes()
* run_osascript()
* run_cmd()
* get_device_info
Local functions in use:
* open_local_file()
*/
const child_process = require('child_process');
const crypto = require('crypto');
const fs = require('fs');
const fs_promises = require('node:fs/promises');
const os = require('os');
const path = require('path');
const { ipcRenderer } = require('electron');
// import psList from 'ps-list';
// const ps_list = require('ps-list');
let home_directory = require('os').homedir();
console.log('Home: ' + home_directory);
let tmp_directory = require('os').tmpdir();
console.log('Temporary: ' + tmp_directory);
let app_root_path = path.join(home_directory, 'OSIT/native_app'); // macOS default
let config = null;
let default_osit_sync_app_root_relative_path =
'OSIT/Speaker Ready System/Admin Share/Custom Applications'; // Mainly for macOS laptops
let default_osit_sync_app_root_path = path.join(
home_directory,
default_osit_sync_app_root_relative_path
); // macOS default
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 test_native_app_relative_path = 'OSIT/native_app/osit_aether.remote.app'; // Mainly for macOS laptops
// exports.check_for_native_app_update = function () {
// console.log('*** Aether App Native export: check_for_native_app_update() ***');
//
// let config_directory = null;
//
// if (os.platform == 'darwin') {
// 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 test_stats = fs.statSync(electron_app_path);
// console.log(test_stats);
//
// if (test_stats.ctimeMs < 1684182140759) {
// console.log(`This may be an old version!`);
// }
// } else if (os.platform == 'linux') {
// config_directory = path.join(home_directory, '.config/OSIT');
// console.log('Linux config directory: '+config_directory);
// } else {
// console.log('Unknown OS... Is this Windows?');
// return false;
// }
//
// }
exports.load_init_config = function () {
console.log('*** Aether App Native export: load_init_config() ***');
let cwd = process.cwd();
console.log(`CWD: ${cwd}`);
try {
if (cwd == '/') {
cwd = home_directory;
}
let directory_list = fs.readdirSync(cwd);
console.log('CWD Contents:', directory_list);
} catch (err) {
console.error(err);
}
// let home_directory = require('os').homedir();
// console.log('Home: '+home_directory);
// let tmp_directory = require('os').tmpdir();
// console.log('Temporary: '+tmp_directory);
// let config = null;
let config_directory = null;
// let default_config_path = path.join(process.cwd(),'ae_native_app_config.current.json');
let default_config_path = 'ae_native_app_config.current.json';
console.log(`Default Config File (path): ${default_config_path}`);
let config_path = null;
// Set the config path for macOS or Linux
if (os.platform == 'darwin') {
// config_directory = path.join(home_directory, 'Library/Application Support/OSIT');
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 test_stats = fs.statSync(electron_app_path);
console.log(test_stats);
} else if (os.platform == 'linux') {
config_directory = path.join(home_directory, '.config/OSIT');
console.log('Linux config directory: ' + config_directory);
}
// Look for the config file and copy the default if not found.
if (fs.existsSync(config_directory)) {
console.log('Config directory found: ' + config_directory);
} else {
fs.mkdirSync(config_directory);
console.log('Config directory created: ' + config_directory);
//default_config_path = path.join(process.cwd(),'ae_native_app_config.current.json');
// config_path = path.join(config_directory, 'ae_native_app_config.json');
// fs.copyFileSync(default_config_path, config_path);
// console.log('Default config file copied: '+config_directory);
}
config_path = path.join(config_directory, 'ae_native_app_config.json');
// 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)) {
fs.copyFileSync(default_config_path, config_path);
console.log('Default config file copied: ' + config_directory);
// config = JSON.parse(fs.readFileSync(config_path));
// console.log('Config file read.');
} else if (fs.existsSync(path.join(cwd, 'ae_native_app_config.json'))) {
//fs.copyFileSync(default_config_path, config_path);
//console.log('Default config file copied: '+config_directory);
console.log(
`Config file (config.json) not found under ${config_directory}. Using config in CWD. ${cwd}`
);
config_path = path.join(cwd, 'ae_native_app_config.json');
console.log(
`Config file (config.json) not found under ${config_directory}. Using config in CWD. ${cwd}`
);
let found_config_path = path.join(cwd, 'ae_native_app_config.json');
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'))) {
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');
fs.copyFileSync(default_config_path, config_path);
console.log(`Default config file copied: ${config_directory}`);
} else {
console.log('Can not find a config file.');
return false;
}
let local_config = JSON.parse(fs.readFileSync(config_path));
console.log('Config file read.', local_config);
config = local_config;
// Do some quick clean up.
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('[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);
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}`);
}
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}`);
}
// NOTE: This is not ideal...
if (!config.account_id) {
if (config.event_id == 'pjrcghqwert' || config.event_id == 'nmBfuGFeR0k') {
config.account_id = '_XY7DXtc9MY';
} else if (config.event_id == 'r8c-rr-I4-52') {
// CMSC
config.account_id = '8Gfxbxr19Nw';
} else if (config.event_id == 'NeC-hm-MF-Q3') {
// LCI
config.account_id = 'xFP7AhU8Zlc';
} else if (config.event_id == 'Y7v-Zg-fe-gu') {
// NCSD
config.account_id = 'FrodrLD7B4w';
} else if (config.event_id == '9jW-Db-SF-wt') {
// AAPOR
config.account_id = 'j5EBhRDqPuw';
} else if (config.event_id == 'zJP-Ld-A7-I4') {
// BGH
config.account_id = 'GpLf_bnywCs';
} else {
console.log(
'WARNING WARNING WARNING: The account ID could not be guessed. Using the default of 1. <<< WARNING'
);
config.account_id = '_XY7DXtc9MY';
}
}
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;
};
exports.load_full_config = function (init_config) {
console.log('*** Aether App Native export: load_config() ***');
console.log('Init config.', init_config);
// config = init_config;
config = get_url_cfg(init_config).then((cfg) => {
console.log('URL config file downloaded.', cfg);
let new_config = init_config;
// Update with remote device config settings from API.
new_config.account_id = cfg.account_id_random;
new_config.event_id = cfg.event_id_random;
new_config.event_device_id = cfg.event_device_id;
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_loop_period = cfg.check_event_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.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(
'[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}`);
}
new_config.host_file_temp_path = new_config.host_file_temp_path.replace(
'[home]',
home_directory
);
new_config.host_file_temp_path = new_config.host_file_temp_path.replace(
'[tmp]',
tmp_directory
);
console.log(`Host file temp path: ${new_config.host_file_temp_path}`);
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}`);
}
let import_config_to_ipc_result = ipcRenderer
.invoke('import_config', new_config)
.then((result) => {
console.log('IPC import config finished');
// console.log(result);
return result; // Result should be "true"
});
return new_config;
});
//console.log(config);
return config;
};
async function get_url_cfg(cfg) {
let base_url = `${cfg.api_protocol}://${cfg.api_server}:${cfg.api_port}/${cfg.api_path}`;
let axios_api = axios.create({
baseURL: base_url,
timeout: 60000 // in milliseconds; 60000 = 60 seconds
/* other custom settings */
});
// axios_api.defaults.headers = cfg['headers'];
// axios.defaults.baseURL = `${cfg.api_protocol}://${cfg.api_server}:${cfg.api_port}/${cfg.api_path}`;
axios_api.defaults.headers.common['Access-Control-Allow-Origin'] =
cfg.access_control_allow_origin; // '*'; // app_cfg.access_control_allow_origin;
axios_api.defaults.headers.common['Content-Type'] = 'application/json';
axios_api.defaults.headers.common['x-aether-api-key'] = cfg.api_secret_key;
// axios_api.defaults.headers.common['x-account-id'] = cfg.account_id;
let event_device_id = 'dbgMWS3KEHE';
let endpoint = `/event/device/${event_device_id}`;
let params = { event_device_code: 'asdf' };
let response_data_promise = await axios_api
.get(endpoint, {
params: params,
onDownloadProgress: (progressEvent) => {
let percent_completed = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(
'GET Data Timestamp:',
progressEvent.timeStamp,
'Total:',
progressEvent.total,
'Loaded:',
progressEvent.loaded,
'Percent Completed',
percent_completed
);
// temp_get_object_percent_completed = percent_completed;
}
})
.then(function (response) {
console.log(`Response: ${response}`);
let return_data = response.data['data'];
if (Array.isArray(return_data)) {
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.`);
}
return return_data;
})
.catch(function (error) {
console.log(`Base URL: ${base_url} | Endpoint: ${endpoint}`);
console.log('Error Message:', error.message); // Is this needed here or below in the in the else portion???
if (error.response) {
console.log(
`Response Status: ${error.response.status}; Status Text: ${error.response.statusText}`
);
} else {
console.log('Error:', error);
}
if (error.response && error.response.status === 404) {
return null; // Returning null since there were no results
}
return false; // Returning false since something may have gone wrong. Also more in line with what the API returns.
});
return response_data_promise;
}
// Check for local file
// Updated 2022-05-06
exports.check_local_file = async function ({ local_file_path, filename }) {
console.log('*** Electron framework export: check_local_file() ***');
// console.log('Check for local file');
console.log(`Local File Path: ${local_file_path}; Filename: ${filename}`);
let full_local_file_path = path.join(local_file_path, filename);
console.log(full_local_file_path);
if (fs.existsSync(full_local_file_path)) {
console.log(`Local file exists: ${full_local_file_path}`);
return true;
} else {
return false;
}
};
// Check local hash file cache
// 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 }) {
// console.log('*** Electron framework export: check_hash_file_cache() ***');
// console.log('Check local hash file cache');
console.log(
`*** Electron framework export: check_hash_file_cache() *** Host File Cache Path: ${local_file_cache_path}; Hash: ${hash}`
);
let hash_filename = `${hash}.file`;
let subdirectory = hash_filename.substring(0, 2);
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}`);
return false;
}
let hash_file_cache_path = path.join(subdirectory_path, hash_filename);
// console.log(hash_file_cache_path);
if (fs.existsSync(hash_file_cache_path)) {
// console.log(`Hashed file exists in cache: ${hash_file_cache_path}`);
return true;
} else {
console.log(`Hashed file not found in cache: ${hash_file_cache_path}`);
return false;
}
};
// Check local hash file cache
// Used by Svelte Event Launcher
// Updated 2022-10-12
exports.check_hash_file_cache_v2 = async function ({
local_file_cache_path,
hash,
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}`);
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}`);
return false;
}
let hash_filename = `${hash}.file`;
let hash_subdirectory = hash_filename.substring(0, 2);
let subdirectory_path = path.join(local_file_cache_path, hash_subdirectory);
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}`);
return false;
}
let full_cached_hash_path = path.join(subdirectory_path, hash_filename);
if (fs.existsSync(full_cached_hash_path)) {
// console.log(`Hashed file exists in cache: ${full_cached_hash_path}`);
if (verify_hash) {
const file_buffer = fs.readFileSync(full_cached_hash_path);
const file_hash_sha256 = crypto.createHash('sha256');
file_hash_sha256.update(file_buffer);
const file_hash_sha256_check = file_hash_sha256.digest('hex');
if (file_hash_sha256_check == hash) {
console.log('File hash match', file_hash_sha256_check);
} else {
// This should only happen if the file is actively being downloaded or it is corrupt.
console.log('File hash does not match', file_hash_sha256_check);
return false;
}
}
return true;
} else {
console.log(`Hashed file not found in cache: ${full_cached_hash_path}`);
return null;
}
};
// Download hash file to cache
// Used by Svelte Event Launcher
// Updated 2022-05-06
exports.download_hash_file_to_cache = async function ({
api_base_url,
local_file_cache_path,
event_file_id = null,
hash = null
}) {
// console.log('*** Electron framework export: download_hash_file_to_cache() ***');
// console.log('Download hash file to cache');
console.log(
`*** Electron framework export: download_hash_file_to_cache() *** Base URL: ${api_base_url}; Host File Cache Path: ${local_file_cache_path}; Event File ID: ${event_file_id}; Hash: ${hash}`
);
let endpoint = `/event/file/${event_file_id}/download`;
let hash_filename = `${hash}.file`;
let subdirectory = hash_filename.substring(0, 2);
let subdirectory_path = path.join(local_file_cache_path, subdirectory);
if (fs.existsSync(subdirectory_path)) {
} else {
fs.mkdirSync(subdirectory_path);
console.log(`Subdirectory directory created: ${subdirectory_path}`);
}
let hash_file_cache_path = path.join(subdirectory_path, hash_filename);
if (fs.existsSync(hash_file_cache_path)) {
if (check_hash) {
const file_buffer = fs.readFileSync(hash_file_cache_path);
const file_hash_sha256 = crypto.createHash('sha256');
file_hash_sha256.update(file_buffer);
const file_hash_sha256_check = file_hash_sha256.digest('hex');
S;
if (file_hash_sha256_check == hash) {
console.log('File hash match', file_hash_sha256_check);
return true;
} else {
// This should only happen if the file is actively being downloaded or it is corrupt.
console.log('File hash does not match', file_hash_sha256_check);
return false;
}
}
}
// console.log(`!!!ABOUT TO CALL DOWNLOAD FILE HANDLER!!! exports.download_hash_file_to_cache(); Base URL: ${api_base_url}`);
let download_file_result = await ipcRenderer
.invoke('download_file', api_base_url, endpoint, hash_file_cache_path)
.then((result) => {
if (result) {
console.log('IPC download file process finished successfully');
return true;
} else if (result == null) {
console.log('IPC Download Result (file not found?):', result);
return null;
} else {
console.log(
'IPC Download Result (file being downloaded or something went wrong):',
result
);
return false;
}
});
// console.log(`!!!DONE WITH DOWNLOAD FILE HANDLER!!! exports.download_hash_file_to_cache(); Base URL: ${api_base_url}`);
return download_file_result;
};
// Download hash file to cache
// Used by Svelte Event Launcher
// Updated 2023-05-26
exports.download_hash_file_to_cache_v2 = async function ({
api_base_url,
api_base_url_backup,
local_file_cache_path,
event_file_id = null,
hash = null,
verify_hash = true,
overwrite_existing = false
}) {
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}`
);
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}`);
return false;
}
let endpoint = `/event/file/${event_file_id}/download`;
let hash_filename = `${hash}.file`;
let hash_subdirectory = hash_filename.substring(0, 2);
let subdirectory_path = path.join(local_file_cache_path, hash_subdirectory);
if (fs.existsSync(subdirectory_path)) {
} else {
fs.mkdirSync(subdirectory_path);
console.log(
`Hashed file subdirectory directory created in cache directory: ${subdirectory_path}`
);
}
let full_cached_hash_path = path.join(subdirectory_path, hash_filename);
if (fs.existsSync(full_cached_hash_path)) {
console.log(`Hashed file exists in cache: ${full_cached_hash_path}`);
if (verify_hash) {
const file_buffer = fs.readFileSync(full_cached_hash_path);
const file_hash_sha256 = crypto.createHash('sha256');
file_hash_sha256.update(file_buffer);
const file_hash_sha256_check = file_hash_sha256.digest('hex');
if (file_hash_sha256_check == hash) {
// console.log('File hash match', file_hash_sha256_check);
if (overwrite_existing) {
console.log(
'Going to overwrite the existing file even though the hash matches.'
);
} else {
return true;
}
} else {
// This should only happen if the file is actively being copied or it is corrupt.
console.log('File hash does not match', file_hash_sha256_check);
if (overwrite_existing) {
console.log(
'Going to overwrite the existing file because the hash does not match.'
);
} else {
return false;
}
}
}
}
const tmp_full_save_path = full_cached_hash_path + '.tmp';
if (fs.existsSync(tmp_full_save_path)) {
console.log(`A temp download file was found! ${tmp_full_save_path}`);
let stats = null;
try {
stats = fs.statSync(tmp_full_save_path);
// console.log(`File Accessed Last: ${stats.atime}`); // File data last changed (actual contents)
console.log(`File Data Last Modified: ${stats.mtime}`); // File data last changed (actual contents)
console.log(`File Metadata Last Modified: ${stats.ctime}`); // File metadata last changed (filename, permissions, etc)
} catch (error) {
console.log(error);
}
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);
// console.log(`Times: ${current_datetime} ${offset_datetime} | File ${stats.mtime}`);
if (stats.mtime < offset_datetime) {
// console.log(`Marking as expired temp file based on modified datetime. Expire after: ${offset_minutes} minutes`);
// overwrite_existing = true;
} else {
console.log(
`Temp download file has not expired yet. Expire after: ${offset_minutes} minutes`
);
// return false;
return 'tmp';
}
}
console.log(`Trying IPC API download from: ${api_base_url}`);
let download_file_result = await ipcRenderer
.invoke(
'download_file',
api_base_url,
endpoint,
full_cached_hash_path,
hash,
verify_hash,
overwrite_existing
)
.then(async (result) => {
if (result) {
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);
return null;
} else if (result === 'in_progress') {
console.log(`IPC API primary download IN PROGRESS: ${hash}`);
// return false; // Should return result instead???
return result;
} else if (result === 'tmp') {
console.log(`IPC API primary download FOUND TMP: ${hash}`);
// return false; // Should return result instead???
return result;
} else {
console.log(
`IPC API download result (file being downloaded or something went wrong): ${hash}`,
result
);
return false;
// if (api_base_url_backup) {
// console.log(`Download FAILED! Trying again with backup API server. API Backup: ${api_base_url_backup}`);
// let download_backup_file_result = await ipcRenderer.invoke('download_file', api_base_url_backup, endpoint, full_cached_hash_path, hash, verify_hash, overwrite_existing).then((result_backup) => {
// if (result_backup) {
// console.log('IPC download file (from backup) process finished successfully');
// return true;
// } else if (result_backup == null) {
// console.log('IPC Download Result (from backup) (file not found?):', result_backup);
// return null;
// } else {
// console.log('IPC Download Result (from backup) (file being downloaded or something went wrong):', result_backup);
// return false;
// }
// });
// } else {
// return false;
// }
}
return true;
// });
})
.then(async (result) => {
if (result === false) {
console.log(`IPC API primary download FAILED!`); // Trying again with backup API server. API Backup: ${api_base_url_backup}`);
if (api_base_url_backup) {
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}`);
let download_backup_file_result = await ipcRenderer
.invoke(
'download_file',
api_base_url_backup,
endpoint,
full_cached_hash_path,
hash,
verify_hash,
overwrite_existing
)
.then((result_backup) => {
if (result_backup) {
console.log(
`IPC API backup download file (from backup) process finished successfully: ${hash}`
);
return true;
} else if (result_backup == null) {
console.log(
'IPC API backup download result (file not found?):',
result_backup
);
return null;
} else {
console.log(
`IPC API backup download result (file being downloaded or something went wrong): ${hash}`,
result_backup
);
return false;
}
});
return download_backup_file_result;
} else {
console.log(
`IPC Download FAILED! No backup API server passed. Returning false.`
);
return false;
}
} else if (result === 'in_progress') {
console.log(`IPC API primary download IN PROGRESS: ${hash}`);
return false; // Should return result instead???
} else if (result === 'tmp') {
console.log(`IPC API primary download FOUND TMP: ${hash}`);
return false; // Should return result instead???
} else {
return result;
}
});
// if (download_file_result === false) {
// console.log(`Download FAILED! Trying again with backup API server. API Backup: ${api_base_url_backup}`)
// download_file_result = await ipcRenderer.invoke('download_file', api_base_url_backup, endpoint, full_cached_hash_path, hash, verify_hash, overwrite_existing).then((result) => {
// if (result) {
// console.log('IPC download file (from backup) process finished successfully');
// return true;
// } else if (result == null) {
// console.log('IPC Download Result (from backup) (file not found?):', result);
// return null;
// } else {
// console.log('IPC Download Result (from backup) (file being downloaded or something went wrong):', result);
// return false;
// }
// });
// }
return download_file_result;
};
// Open cached hash file after copying to temp directory
// 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.open_hash_file_to_temp = async function ({
local_file_cache_path,
hash,
host_file_temp_path,
filename
}) {
console.log('*** Electron framework export: open_hash_file_to_temp() ***');
// console.log('Open cached hash file after copying to temp directory');
console.log(
`Host File Cache Path: ${local_file_cache_path}; Hash: ${hash}; Host File Temp Path: ${host_file_temp_path}; Filename: ${filename}`
);
let subdirectory = hash.substring(0, 2);
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}`);
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)
.then((result) => {
console.log('IPC open hash file to temp finished');
console.log(result);
return true;
});
// let result = await ipcRenderer.send('open_local_file', local_file_cache_path, hash, host_file_temp_path, filename);
// console.log(result);
console.log(open_hash_file_to_temp_result);
console.log('End: open_hash_file_to_temp()');
if (open_hash_file_to_temp_result) {
console.log('File opened successfully');
return true;
} else {
console.log('File was not opened successfully');
return false;
}
};
// Open cached hash file after copying to temp directory
// Used by Svelte Event Launcher
// Updated 2022-10-12
exports.open_hash_file_to_temp_v2 = async function ({
local_file_cache_path,
hash,
host_file_temp_path,
filename,
verify_hash = true
}) {
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}`
);
// console.log('Process: Check local hash file cache, Download hash file to cache, and Open cached hash file after copying to temp directory');
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}`);
return false;
}
let hash_filename = `${hash}.file`;
let hash_subdirectory = hash_filename.substring(0, 2);
let subdirectory_path = path.join(local_file_cache_path, hash_subdirectory);
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}`);
return false;
}
let full_cached_hash_path = path.join(subdirectory_path, hash_filename);
if (fs.existsSync(full_cached_hash_path)) {
console.log(`Hashed file exists in cache: ${full_cached_hash_path}`);
if (verify_hash) {
const file_buffer = fs.readFileSync(full_cached_hash_path);
const file_hash_sha256 = crypto.createHash('sha256');
file_hash_sha256.update(file_buffer);
const file_hash_sha256_check = file_hash_sha256.digest('hex');
if (file_hash_sha256_check == hash) {
// console.log('File hash match', file_hash_sha256_check);
} else {
// This should only happen if the file is actively being downloaded or it is corrupt.
console.log('File hash does not match', file_hash_sha256_check);
return false;
}
}
} else {
console.log(`Hashed file not found in cache: ${full_cached_hash_path}`);
return null;
}
let local_file_cache_path_w_sub = subdirectory_path; // I need to go back and clean up the variable names related file directory and file paths.
// NOTE: Setting check_hash to false since by default it was checked above.
let open_hash_file_to_temp_result = await ipcRenderer
.invoke(
'open_hash_file_to_temp',
local_file_cache_path_w_sub,
hash,
host_file_temp_path,
filename,
(verify_hash = false)
)
.then((result) => {
console.log('IPC open hash file to temp finished');
if (result) {
console.log('Local hash file was opened from temp directory.');
return result;
} else {
console.log(
'Local hash file was not opened from the temp directory. Something went wrong.'
);
console.log(result);
return false;
}
});
// let result = await ipcRenderer.send('open_local_file', local_file_cache_path, hash, host_file_temp_path, filename);
// console.log(result);
// console.log(open_hash_file_to_temp_result);
// console.log('End: open_hash_file_to_temp()');
// if (open_hash_file_to_temp_result) {
// console.log('File opened successfully');
// return true;
// } else {
// console.log('File was not opened successfully');
// 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).then((result) => {
// console.log('IPC open hash file to temp finished');
// if (result) {
// console.log('Local hash file was opened from temp directory.');
// return result;
// } else {
// console.log('Local hash file was not opened from the temp directory. Something went wrong.');
// console.log(result);
// return false;
// }
// })
return open_hash_file_to_temp_result;
};
// Open local file
// Used by Svelte Event Launcher
// NOTE: Trying to replace this with something directly in the Svelte app part. 2022-10-11
// Updated 2022-03-10
exports.open_local_file = async function ({ local_file_path, filename }) {
console.log('*** Electron framework export: open_local_file() ***');
// console.log('Open local file');
console.log(`Local File Path: ${local_file_path}; Filename: ${filename}`);
// let full_local_file_path = path.join(local_file_path, filename);
// console.log(full_local_file_path);
// if (fs.existsSync(full_local_file_path)) {
// console.log(`Local file exists: ${full_local_file_path}`);
// // return true;
// } else {
// return false;
// }
let open_local_file_result = await ipcRenderer
.invoke('open_local_file', local_file_path, filename)
.then((result) => {
console.log('IPC open local file finished');
console.log(result);
return true;
});
console.log(open_local_file_result);
console.log('End: open_local_file()');
if (open_local_file_result) {
console.log('File opened successfully');
return true;
} else {
console.log('File was not opened successfully');
return false;
}
};
// // Check local file cache and download from server if needed.
// // Updated 2022-03-09
// // exports.check_file_cache = async function ({local_file_cache_path, event_file_id, hash}) {
// exports.check_file_cache = async function ({api_base_url, local_file_cache_path, event_file_id, hash}) {
// console.log('*** Electron framework export: check_file_cache() ***');
// // console.log('Check local file cache and download from server if needed.');
// console.log(`Host File Cache Path: ${local_file_cache_path}; Event File ID: ${event_file_id}; Hash: ${hash}`);
// // NOTE: event_file_id is the event_file.id_random or event_file.event_file_id_random
// let hash_filename = hash+'.file';
// let save_path = path.join(local_file_cache_path, hash_filename);
// console.log(save_path);
// if (fs.existsSync(save_path)) {
// 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);
// 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.
// console.log(result);
// return new Promise((resolve, reject) => {
// ipcRenderer.once('download_file_reply', function(event, response){
// console.log(response);
// return response;
// })
// resolve(true);
// });
// // await ipcRenderer.once('download_file_reply', function(event, response){
// // console.log(response);
// // return response;
// // });
// // result.then(function (response) {
// // console.log('Downloaded!!!???');
// // return true;
// // }).catch(function (error: any) {
// // console.log(error);
// // return false;
// // });
// // return result;
// // console.log(result);
// // if (result) {
// // return true;
// // } else {
// // return false;
// // }
// }
// }
// 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 }) {
console.log('*** Electron framework: check_file_cache() ***');
// console.log('Check local file cache and download from server if needed.');
console.log(
`Host File Cache Path: ${local_file_cache_path}; Event File ID: ${event_file_id}; Hash: ${hash}`
);
// NOTE: event_file_id is the event_file.id_random or event_file.event_file_id_random
let hash_filename = hash + '.file';
let save_path = path.join(local_file_cache_path, hash_filename);
console.log(save_path);
if (fs.existsSync(save_path)) {
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);
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.
console.log(result);
return new Promise((resolve, reject) => {
ipcRenderer.once('download_file_reply', function (event, response) {
console.log(response);
return response;
});
resolve(true);
});
// await ipcRenderer.once('download_file_reply', function(event, response){
// console.log(response);
// return response;
// });
// result.then(function (response) {
// console.log('Downloaded!!!???');
// return true;
// }).catch(function (error: any) {
// console.log(error);
// return false;
// });
// return result;
// console.log(result);
// if (result) {
// return true;
// } else {
// return false;
// }
}
}
// 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 }) {
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(
`Host File Cache Path: ${local_file_cache_path}; Hash: ${hash}; Host File Temp Path: ${host_file_temp_path}; Filename: ${filename}`
);
console.log(local_file_cache_path);
console.log(hash);
console.log(filename);
let result = await ipcRenderer.send(
'open_local_file',
local_file_cache_path,
hash,
host_file_temp_path,
filename
);
console.log(result);
return true;
}
// No longer needed? Not referenced as of 2022-10-11
exports.check_file_cache_and_open_local_file = async function ({
local_file_cache_path,
event_file_id,
hash,
host_file_temp_path,
filename
}) {
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.'
);
let check_file_cache_result = check_file_cache({
local_file_cache_path: local_file_cache_path,
event_file_id: event_file_id,
hash: hash
});
console.log(check_file_cache_result);
if (check_file_cache_result) {
let open_local_file_result = open_local_file({
local_file_cache_path: local_file_cache_path,
hash: hash,
host_file_temp_path: host_file_temp_path,
filename: filename
});
console.log(open_local_file_result);
return open_local_file_result;
}
ipcRenderer.once('download_file_reply', function (event, response) {
console.log(response);
let open_local_file_result = open_local_file({
local_file_cache_path: local_file_cache_path,
hash: hash,
host_file_temp_path: host_file_temp_path,
filename: filename
});
console.log(open_local_file_result);
return open_local_file_result;
});
};
// Kill processes
// Signals: HUP (hang up), INT (interrupt), QUIT (quit), ABRT (abort), KILL (non-catchable, non-ignoraable kill), ALRMn (alarm clock), TERM (default; software termination signal)
// Updated 2022-05-07
exports.kill_processes = async function ({
process_name = null,
process_id = null,
signal = null
}) {
console.log('*** Electron framework export: kill_processes() ***');
console.log(process_name); // process_name or grep pattern
let cmd = '';
if (os.platform == 'darwin') {
if (signal == 'HUP') {
cmd = `killall -HUP '${process_name}'`;
} else if (signal == 'INT') {
cmd = `killall -INT '${process_name}'`;
} else if (signal == 'QUIT') {
cmd = `killall -QUIT '${process_name}'`;
} else if (signal == 'ABRT') {
cmd = `killall -ABRT '${process_name}'`;
} else if (signal == 'KILL') {
cmd = `killall -KILL '${process_name}'`;
} else if (signal == 'ALRM') {
cmd = `killall -ALRM '${process_name}'`;
} else if (signal == 'TERM') {
cmd = `killall -TERM '${process_name}'`;
} else if (process_id && signal == 'HUP') {
cmd = `killall -HUP ${process_id}`;
} else if (process_id && signal == 'INT') {
cmd = `killall -INT ${process_id}`;
} else if (process_id && signal == 'QUIT') {
cmd = `killall -QUIT ${process_id}`;
} else if (process_id && signal == 'ABRT') {
cmd = `killall -ABRT ${process_id}`;
} else if (process_id && signal == 'KILL') {
cmd = `killall -KILL ${process_id}`;
} else if (process_id && signal == 'ALRM') {
cmd = `killall -ALRM ${process_id}`;
} else if (process_id && signal == 'TERM') {
cmd = `killall -TERM ${process_id}`;
} else {
// cmd = `osascript -e 'quit app "${process_name}" saving no'`;
cmd = `osascript -e 'quit application "${process_name}" saving no'`;
}
} else {
cmd = `pkill ${process_name}`;
}
child_process.exec(cmd, (err, stdout, stdin) => {
// if (err) throw err;
if (err) console.log(err);
console.log(stdout);
});
console.log(`Killed processes matching ${process_name}`);
if (os.platform == 'darwin') {
if (process_name == 'Parallels:Acrobat Reader') {
// Regular expression: (Parallels).*(Acrobat Reader)
// This will find any process with Parallels and Acrobat Reader in the name
cmd = `pkill -i -f '(Parallels).*(Acrobat Reader)'`;
child_process.exec(cmd, (err, stdout, stdin) => {
if (err) throw err;
console.log(stdout);
});
console.log('Killed Parallels Acrobat Reader process');
}
if (process_name == 'Parallels:PowerPoint') {
// Regular expression: (Parallels).*(PowerPoint)
// This will find any process with Parallels and PowerPoint in the name
cmd = `pkill -i -f '(Parallels).*(PowerPoint)'`;
child_process.exec(cmd, (err, stdout, stdin) => {
if (err) throw err;
console.log(stdout);
});
console.log('Killed Parallels PowerPoint process');
}
}
// let signal = 'SIGTERM'; // 'SIGTERM', 'SIGINT', 'SIGHUP'
// process.kill(pid, signal);
// process.kill(pid, 0); // Special case test if process exists
return true;
};
// Run raw osascript
// Updated 2022-05-07
exports.run_osascript = async function ({
cmd = null,
interactive = false,
language = null,
flags = 'h',
program_file = null
}) {
console.log('*** Electron framework export: run_osascript() ***');
console.log(cmd);
if (os.platform == 'darwin') {
} else {
console.log('Not available for this platform. macOS (darwin) only.');
return false;
}
let osascript_str = '';
if (Array.isArray(cmd)) {
console.log('List of cmd strings');
let cmds_str = '';
for (let i = 0; i < cmd.length; i++) {
cmds_str += `-e '${cmd[i]}'`;
}
osascript_str = `osascript ${cmds_str}`;
} else if (typeof cmd === 'string') {
console.log('Single cmd string');
osascript_str = `osascript -e '${cmd}'`;
} else {
return false;
}
if (language) {
console.log(`Language: ${language}`);
osascript_str = `${osascript_str} -l ${language}`;
}
if (flags) {
console.log(`Flags: ${flags}`);
osascript_str = `${osascript_str} -s ${flags}`;
}
console.log(`OSA Script String: ${osascript_str}`);
child_process.exec(osascript_str, (err, stdout, stdin) => {
if (err) throw err;
console.log(stdout);
console.log(stdin);
});
console.log('Finished');
return true;
};
// Run raw command
// Updated 2026-01-26
exports.run_cmd = async function ({
cmd = null,
return_stdout = null,
return_stdin = null,
sync = null
}) {
console.log('*** Electron framework export: run_cmd() ***');
// 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);
}
console.log(`Command String: ${cleaned_cmd}`);
let result;
if (!sync) {
result = child_process.exec(cleaned_cmd, (err, stdout, stdin) => {
// if (err) throw err;
if (err) {
console.log('Error:', err);
return false;
}
console.log('stdout:', stdout);
// console.log('stdin:', stdin);
if (return_stdout) {
console.log('Finished and returning stdout');
return stdout;
} else {
console.log('Finished and returning true');
return true;
}
});
} else {
result = child_process.execSync(cleaned_cmd, (err, stdout, stdin) => {
// if (err) throw err;
if (err) {
console.log('Error:', err);
return false;
}
console.log('stdout:', stdout);
// console.log('stdin:', stdin);
if (return_stdout) {
console.log('Finished and returning stdout');
return stdout;
} else {
console.log('Finished and returning true');
return true;
}
});
}
console.log('Result:', result);
return result;
};
// Run raw command sync
// Updated 2026-01-26
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);
}
console.log(`Command String: ${cleaned_cmd}`);
let stdout;
try {
stdout = child_process.execSync(cleaned_cmd, { encoding: 'utf8' });
console.log('Std Out:', stdout);
} catch (err) {
console.error('Error:', err);
return false;
}
if (return_stdout) {
console.log('Finished and returning stdout');
return stdout;
} else {
console.log('Finished and returning true');
return true;
}
};
// Run raw command
// Updated 2026-01-26
exports.get_device_info = async function () {
console.log('*** Electron framework export: get_device_info() ***');
// https://nodejs.org/api/os.html
let data = {};
data['arch'] = os.arch();
data['hostname'] = os.hostname();
data['cpus'] = os.cpus();
data['freemem'] = os.freemem();
data['totalmem'] = os.totalmem();
data['loadavg'] = os.loadavg();
data['networkInterfaces'] = os.networkInterfaces();
data['platform'] = os.platform();
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;
console.log(data);
return data;
};
/**
* Atomic Copy-and-Launch (Phase 2/5)
* 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
}) {
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 hash_filename = `${hash}.file`;
const prefix = hash.substring(0, hash_prefix_length);
const source_path = path.join(clean_cache_root, prefix, hash_filename);
const dest_path = path.join(clean_temp_root, filename);
console.log(`Source: ${source_path}`);
console.log(`Dest: ${dest_path}`);
try {
// 2. Ensure temp directory exists
if (!fs.existsSync(clean_temp_root)) {
fs.mkdirSync(clean_temp_root, { recursive: true });
}
// 3. Verify Source
if (!fs.existsSync(source_path)) {
throw new Error(`Source file not found in cache: ${source_path}`);
}
// 4. Perform atomic copy
fs.copyFileSync(source_path, dest_path);
console.log('File copied to temp successfully.');
// 5. Trigger Specialized Launcher (if presentation)
const ext = path.extname(filename).toLowerCase().replace('.', '');
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'
});
}
// 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 };
}
};
/**
* Specialized Presentation Launcher (Phase 5)
* Handles platform-specific application selection (LibreOffice on Linux,
* PowerPoint/Keynote on macOS).
* Updated 2026-01-26
*/
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}`);
// 1. Detect OS
let platform = os_platform;
if (platform === 'auto') {
platform = os.platform();
}
// 2. Handle Linux (LibreOffice Testing)
if (platform === 'linux') {
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) {
console.error('LibreOffice Launch Error:', err);
resolve({ success: false, error: err.message });
} else {
resolve({ success: true, stdout, stderr });
}
});
});
}
// 3. Handle macOS (Production)
if (platform === 'darwin') {
if (app === 'keynote') {
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);
}
// 4. Default Fallback (Windows/Others)
return ipcRenderer.invoke('open_local_file', '', cleaned_path);
};
// For loading JS file
function loadJS() {
// Gives -1 when the given input is not in the string
// i.e this file has not been added
if (filesAdded.indexOf('script.js') !== -1) return;
// Head tag
var head = document.getElementsByTagName('head')[0];
// Creating script element
var script = document.createElement('script');
script.src = 'script.js';
script.type = 'text/javascript';
// Adding script element
head.append(script);
// Adding the name of the file to keep record
filesAdded += ' script.js';
}
// To load CSS file
function loadCSS() {
if (filesAdded.indexOf('styles.css') !== -1) return;
var head = document.getElementsByTagName('head')[0];
// Creating link element
var style = document.createElement('link');
style.href = 'styles.css';
style.type = 'text/css';
style.rel = 'stylesheet';
head.append(style);
// Adding the name of the file to keep record
filesAdded += ' styles.css';
}
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() ***');
if (os.platform == 'darwin') {
let default_osit_sync_app_config_path = path.join(
default_osit_sync_app_root_path,
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);
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);
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');
console.log('Linux config directory: ' + app_root_path);
return false;
} else {
console.log('Unknown OS... Is this Windows?');
return false;
}
return true;
};