diff --git a/app/index.bootstrap.html b/app/index.bootstrap.html new file mode 100644 index 0000000..5e2a482 --- /dev/null +++ b/app/index.bootstrap.html @@ -0,0 +1,47 @@ + + + + + + + One Sky IT's Aether App - External XXX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Loaded HTML + + + diff --git a/app/index.current.html b/app/index.current.html new file mode 100644 index 0000000..db2e2f8 --- /dev/null +++ b/app/index.current.html @@ -0,0 +1,316 @@ + + + + + + + One Sky IT's Aether App - External + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Site-Nav-Menu
+ +
+ + + + + +
+
System-Notifications (and Site-Notifications)
+ +
+ +
+ +
+
+ + + +
+ +
+ + + +
System-Debug
+ + + + + + + + + + diff --git a/app/script.current.js b/app/script.current.js new file mode 100644 index 0000000..d604e27 --- /dev/null +++ b/app/script.current.js @@ -0,0 +1,1265 @@ +'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 cmsc 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}`); + } + + if (!config.account_id) { + config.account_id = '_XY7DXtc9MY'; // Not ideal...? + } + + 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 2022-10-12 +exports.download_hash_file_to_cache_v2 = async function ({api_base_url, 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}; 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; + } + } + } + } + + let download_file_result = await ipcRenderer.invoke('download_file', api_base_url, endpoint, full_cached_hash_path, hash, verify_hash, overwrite_existing).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; + } + }); + + 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) { +// // 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) { + // 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 2022-05-07 +exports.run_cmd = async function ({cmd=null, return_stdout=null, return_stdin=null, sync=null}) { + console.log('*** Electron framework export: run_cmd() ***'); + + console.log(`Command String: ${cmd}`); + + let result; + + if (!sync) { + result = child_process.exec(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(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 2022-05-07 +exports.run_cmd_sync = function ({cmd=null, return_stdout=null, return_stdin=null}) { + console.log('*** Electron framework export: run_cmd() ***'); + + console.log(`Command String: ${cmd}`); + + let stdout; + + try { + stdout = child_process.execSync(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; + } + + // let result; + // let stdout; + // let stderr; + // try { + // let { stdout, stderr } = child_process.execSync(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; + // } + // }); + // } catch (err) { + // console.error(err); + // return false; + // } + + // console.log('Result:', result); + // return result; +} + + +// Run raw command +// Updated 2022-05-25 +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(); + + console.log(data); + return data; +} + + + +// 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; +} \ No newline at end of file diff --git a/app/script.js b/app/script.js new file mode 100644 index 0000000..e69de29 diff --git a/app/style.css b/app/style.css new file mode 100644 index 0000000..e69de29 diff --git a/app/style.current.css b/app/style.current.css new file mode 100644 index 0000000..cbebafa --- /dev/null +++ b/app/style.current.css @@ -0,0 +1,28 @@ +body { + /* min-height: 100%; + height: 100%; + max-height: 100%; */ + + /* margin: .1em; + padding: .1em; */ +} + +section#Main-Body { + /* outline: solid thin red; */ + + /* min-height: 100%; + height: 100%; + max-height: 100%; */ +} + +section#Main-Nav-Menu { + /* min-height: 100%; + height: 100%; + max-height: 100%; */ +} + +section#Main-Content { + /* min-height: 100%; + height: 100%; + max-height: 100%; */ +} \ No newline at end of file diff --git a/app/test.html b/app/test.html new file mode 100644 index 0000000..a0ee9ca --- /dev/null +++ b/app/test.html @@ -0,0 +1,279 @@ + + + + + + + One Sky IT's Aether App + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Site-Nav-Menu
+ +
+ + + + + +
+
System-Notifications (and Site-Notifications)
+ +
+ +
+ +
+
+ + + +
+ +
+ + + +
System-Debug
+ + + + + + + + + + diff --git a/index.js b/index.js index 6319404..6dff36c 100644 --- a/index.js +++ b/index.js @@ -145,7 +145,8 @@ function createWindow () { webPreferences: { contextIsolation: false, nodeIntegration: true, - nodeIntegrationInWorker: true + nodeIntegrationInWorker: true, + enableRemoteModule: true } }) @@ -179,7 +180,7 @@ function createWindow () { let index_url = 'http://localhost/index.html'; if (config.native_app_index_url) { - index_url = native_app_index_url; + index_url = config.native_app_index_url; } else { index_url = 'https://app.oneskyit.com/native/index.html'; } diff --git a/package-lock.json b/package-lock.json index e618b0c..e0b1a6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "aether_app_native", - "version": "3.6.1", + "version": "2023.5.14.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "aether_app_native", - "version": "3.6.1", + "version": "2023.5.14.2", "license": "ISC", "dependencies": { "axios": "^1.1.2", @@ -595,9 +595,9 @@ } }, "node_modules/electron": { - "version": "22.3.6", - "resolved": "https://registry.npmjs.org/electron/-/electron-22.3.6.tgz", - "integrity": "sha512-/1/DivFHH5AWa/uOuqpkeg12/jjicjkBU8kYv70oeqRFwXzoyuJhgwlzER4jZXnbGjF5Nxz9900oXq/QzAViAw==", + "version": "22.3.10", + "resolved": "https://registry.npmjs.org/electron/-/electron-22.3.10.tgz", + "integrity": "sha512-gh7PtSh+rfxHfM4dzPiEO+k1NRo07FvaK/jXG3HzuODrpTTEhC9rsE+AJGrTKQU6Nz7GorseMvnvs8PnUQPPTw==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -2527,9 +2527,9 @@ } }, "electron": { - "version": "22.3.6", - "resolved": "https://registry.npmjs.org/electron/-/electron-22.3.6.tgz", - "integrity": "sha512-/1/DivFHH5AWa/uOuqpkeg12/jjicjkBU8kYv70oeqRFwXzoyuJhgwlzER4jZXnbGjF5Nxz9900oXq/QzAViAw==", + "version": "22.3.10", + "resolved": "https://registry.npmjs.org/electron/-/electron-22.3.10.tgz", + "integrity": "sha512-gh7PtSh+rfxHfM4dzPiEO+k1NRo07FvaK/jXG3HzuODrpTTEhC9rsE+AJGrTKQU6Nz7GorseMvnvs8PnUQPPTw==", "dev": true, "requires": { "@electron/get": "^2.0.0",