diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index c8b12e6a..ec42c880 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -44,7 +44,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -55,7 +55,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # ℹī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -69,4 +69,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/package.json b/package.json index ab6b63e3..15817163 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,8 @@ "node_modules/fsevents/fsevents.node", "../docs/api_doc/butler-api.yaml", "node_modules/@fastify/swagger", - "static/**/*" + "static/**/*", + "package.json" ], "scripts": [ "node_modules/enigma.js/**/*.json", diff --git a/src/app.js b/src/app.js index 814beb09..61b8a4d0 100644 --- a/src/app.js +++ b/src/app.js @@ -41,12 +41,20 @@ async function build(opts = {}) { } // Load certificates to use when connecting to healthcheck API + // When running in packaged app (using pkg): import.meta.url = /snapshot/butler/build.cjs + // When running as Node.js: import.meta.url = /home/goran/code/butler/src/app.js const filename = fileURLToPath(import.meta.url); const dirname = path.dirname(filename); const certFile = path.resolve(dirname, globals.config.get('Butler.cert.clientCert')); const keyFile = path.resolve(dirname, globals.config.get('Butler.cert.clientCertKey')); const caFile = path.resolve(dirname, globals.config.get('Butler.cert.clientCertCA')); + globals.logger.verbose(`MAIN: Executing JS filename: ${filename}`); + globals.logger.verbose(`MAIN: Executing JS dirname: ${dirname}`); + globals.logger.verbose(`MAIN: Using client cert file: ${certFile}`); + globals.logger.verbose(`MAIN: Using client cert key file: ${keyFile}`); + globals.logger.verbose(`MAIN: Using client cert CA file: ${caFile}`); + // Set up heartbeats, if enabled in the config file if ( (globals.config.has('Butler.heartbeat.enabled') && globals.config.get('Butler.heartbeat.enabled') === true) || diff --git a/src/globals.js b/src/globals.js index a8ce8376..84d9993c 100644 --- a/src/globals.js +++ b/src/globals.js @@ -24,17 +24,33 @@ class Settings { } // Get app version from package.json file - const filename = `./package.json`; - // const a = upath.resolve(filename) - const b = readFileSync(filename); - // const b = readFileSync(a); - const { version } = JSON.parse(b); - - // const loadJSON = (path) => JSON.parse(fs.readFileSync(new URL(path, import.meta.url))); - // const { version } = loadJSON('../package.json'); - this.appVersion = version; + const filenamePackage = `./package.json`; + let a; + let b; + let c; + // Are we running as a packaged app? + if (process.pkg) { + // Get path to JS file + a = process.pkg.defaultEntrypoint; + + // Strip off the filename + b = upath.dirname(a); + + // Add path to package.json file + c = upath.join(b, filenamePackage); + } else { + // Get path to JS file + a = fileURLToPath(import.meta.url); + + // Strip off the filename + b = upath.dirname(a); - console.log(`appVersion: ${this.appVersion}`); + // Add path to package.json file + c = upath.join(b, '..', filenamePackage); + } + + const { version } = JSON.parse(readFileSync(c)); + this.appVersion = version; // Command line parameters const program = new Command(); @@ -653,7 +669,7 @@ class Settings { const enableInfluxdb = this.config.get('Butler.influxDb.enable'); // Ensure that InfluxDB has been created - if(this.influx === undefined) { + if (this.influx === undefined) { this.logger.error('CONFIG: InfluxDB not initialized! Possible race condition during startup of Butler. Exiting.'); process.exit(1); } diff --git a/src/routes/sense_app.js b/src/routes/sense_app.js index 9d8753b5..140db6df 100644 --- a/src/routes/sense_app.js +++ b/src/routes/sense_app.js @@ -2,11 +2,10 @@ import httpErrors from 'http-errors'; import enigma from 'enigma.js'; import SenseUtilities from 'enigma.js/sense-utilities.js'; import WebSocket from 'ws'; -// import { createRequire } from "module"; -import { readFile } from 'fs/promises'; +import { readFileSync } from 'fs'; +import { fileURLToPath } from 'url'; import upath from 'upath'; - // Load global variables and functions import globals from '../globals.js'; @@ -14,31 +13,38 @@ import senseStartTask from '../qrs_util/sense_start_task.js'; import { logRESTCall } from '../lib/log_rest_call.js'; import apiPutAppReload from '../api/sense_app.js'; -// Set up enigma.js configuration - async function handlerPutAppReload(request, reply) { try { + // Set up enigma.js configuration const schemaFile = `./node_modules/enigma.js/schemas/${globals.configEngine.engineVersion}.json`; - // const require = createRequire(import.meta.url); - // // eslint-disable-next-line import/no-dynamic-require - // const qixSchema = require(schemaFile); - - // Convert schemaFile to absolute path using path - const a = upath.resolve(schemaFile) - const b = await readFile(schemaFile); - const qixSchema = JSON.parse(b); - + let a; + let b; + let c; + // Are we running as a packaged app? + if (process.pkg) { + // Yes, we are running as a packaged app + // Get path to JS file const + a = process.pkg.defaultEntrypoint; + + // Strip off the filename + b = upath.dirname(a); + + // Add path to package.json file + c = upath.join(b, schemaFile); + } else { + // No, we are running as native Node.js + // Get path to JS file + a = fileURLToPath(import.meta.url); - // const qixSchema = JSON.parse( - // await readFile( - // // new URL(schemaFile, import.meta.url); - // new URL(schemaFile, import.meta.url); - // ) - // ); + // Strip off the filename + b = upath.dirname(a); - // const { createRequire } = require('node:module'); - // const qixSchema = createRequire(schemaFile); + // Add path to package.json file + c = upath.join(b, '..', '..', schemaFile); + } + globals.logger.verbose(`APPDUMP: Using engine schema in file: ${c}`); + const qixSchema = JSON.parse(readFileSync(c)); logRESTCall(request); diff --git a/src/routes/sense_app_dump.js b/src/routes/sense_app_dump.js index 283b0505..5e7c1c7c 100644 --- a/src/routes/sense_app_dump.js +++ b/src/routes/sense_app_dump.js @@ -2,35 +2,46 @@ import serializeApp from 'serializeapp'; import httpErrors from 'http-errors'; import enigma from 'enigma.js'; import WebSocket from 'ws'; -// import { createRequire } from "module"; -import { readFile } from 'fs/promises'; +import { readFileSync } from 'fs'; +import { fileURLToPath } from 'url'; import upath from 'upath'; - import globals from '../globals.js'; import { logRESTCall } from '../lib/log_rest_call.js'; import { apiGetSenseAppDump, apiGetAppDump } from '../api/sense_app_dump.js'; -// Set up enigma.js configuration - async function handlerGetSenseAppDump(request, reply) { try { + // Set up enigma.js configuration const schemaFile = `./node_modules/enigma.js/schemas/${globals.configEngine.engineVersion}.json`; + let a; + let b; + let c; + // Are we running as a packaged app? + if (process.pkg) { + // Yes, we are running as a packaged app + // Get path to JS file const + a = process.pkg.defaultEntrypoint; + + // Strip off the filename + b = upath.dirname(a); + + // Add path to package.json file + c = upath.join(b, schemaFile); + } else { + // No, we are running as native Node.js + // Get path to JS file + a = fileURLToPath(import.meta.url); + // Strip off the filename + b = upath.dirname(a); - // const require = createRequire(import.meta.url); - // // eslint-disable-next-line import/no-dynamic-require - // const qixSchema = require(schemaFile); - - - // Convert schemaFile to absolute path using path - const a = upath.resolve(schemaFile) - const b = await readFile(a); - const qixSchema = JSON.parse(b); - + // Add path to package.json file + c = upath.join(b, '..', '..', schemaFile); + } - // const { createRequire } = require('node:module'); - // const qixSchema = createRequire(schemaFile); + globals.logger.verbose(`APPDUMP: Using engine schema in file: ${c}`); + const qixSchema = JSON.parse(readFileSync(c)); logRESTCall(request); @@ -58,10 +69,10 @@ async function handlerGetSenseAppDump(request, reply) { const session = enigma.create(configEnigma); const global = await session.open(); - + // We can now interact with the global object, for example get the document list. // Please refer to the Engine API documentation for available methods. - const app = await global.openDoc(request.params.appId, '', '', '', true); + const app = await global.openDoc(request.params.appId, '', '', '', true); const data = await serializeApp(app); reply.type('application/json; charset=utf-8').code(200).send(JSON.stringify(data)); diff --git a/src/routes/sense_list_apps.js b/src/routes/sense_list_apps.js index 041cc8eb..8cb7d1ef 100644 --- a/src/routes/sense_list_apps.js +++ b/src/routes/sense_list_apps.js @@ -1,36 +1,47 @@ import httpErrors from 'http-errors'; import enigma from 'enigma.js'; import WebSocket from 'ws'; -import { createRequire } from "module"; -import { readFile } from 'fs/promises'; +import { readFileSync } from 'fs'; +import { fileURLToPath } from 'url'; import upath from 'upath'; // Load global variables and functions import globals from '../globals.js'; - import { logRESTCall } from '../lib/log_rest_call.js'; import { apiGetSenseListApps, apiGetAppsList } from '../api/sense_list_apps.js'; -// Set up enigma.js configuration - async function handlerGetSenseListApps(request, reply) { try { + // Set up enigma.js configuration const schemaFile = `./node_modules/enigma.js/schemas/${globals.configEngine.engineVersion}.json`; - // const require = createRequire(import.meta.url); - // // eslint-disable-next-line import/no-dynamic-require - // const qixSchema = require(schemaFile); - - // Convert schemaFile to absolute path using path - const a = upath.resolve(schemaFile) - const b = await readFile(a); - const qixSchema = JSON.parse(b); - - - - // const { createRequire } = require('node:module'); - // const qixSchema = createRequire(schemaFile); - + let a; + let b; + let c; + // Are we running as a packaged app? + if (process.pkg) { + // Yes, we are running as a packaged app + // Get path to JS file const + a = process.pkg.defaultEntrypoint; + + // Strip off the filename + b = upath.dirname(a); + + // Add path to package.json file + c = upath.join(b, schemaFile); + } else { + // No, we are running as native Node.js + // Get path to JS file + a = fileURLToPath(import.meta.url); + + // Strip off the filename + b = upath.dirname(a); + + // Add path to package.json file + c = upath.join(b, '..', '..', schemaFile); + } + globals.logger.verbose(`APPDUMP: Using engine schema in file: ${c}`); + const qixSchema = JSON.parse(readFileSync(c)); logRESTCall(request); @@ -76,19 +87,19 @@ async function handlerGetSenseListApps(request, reply) { globals.logger.error(`LISTAPPS: Error closing connection to Sense engine: ${JSON.stringify(err, null, 2)}`); reply.send(httpErrors(500, 'Failed closing connection to Sense server')); } - // .catch((error) => { - // globals.logger.error( - // `LISTAPPS: Error while opening session to Sense engine during app listing: ${JSON.stringify(error, null, 2)}` - // ); - - // try { - // session.close(); - // } catch (err) { - // globals.logger.error(`LISTAPPS: Error closing connection to Sense engine: ${JSON.stringify(err, null, 2)}`); - // } - - // reply.send(httpErrors(422, 'Failed to open session to Sense engine')); - // }); + // .catch((error) => { + // globals.logger.error( + // `LISTAPPS: Error while opening session to Sense engine during app listing: ${JSON.stringify(error, null, 2)}` + // ); + + // try { + // session.close(); + // } catch (err) { + // globals.logger.error(`LISTAPPS: Error closing connection to Sense engine: ${JSON.stringify(err, null, 2)}`); + // } + + // reply.send(httpErrors(422, 'Failed to open session to Sense engine')); + // }); } catch (err) { globals.logger.error(`LISTAPPS: getting list of Sense apps, error is: ${JSON.stringify(err, null, 2)}`); reply.send(httpErrors(500, 'Failed getting list of Sense apps'));