diff --git a/.gitignore b/.gitignore index 100635e..f2cfbac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ example-message.json +*.sqlite *.pcapng *.png *.stl diff --git a/server/bootstrap/cli.mjs b/server/bootstrap/cli.mjs new file mode 100644 index 0000000..6072a0d --- /dev/null +++ b/server/bootstrap/cli.mjs @@ -0,0 +1,72 @@ +"use strict"; + +import show_help from '../help.mjs'; +import { decode_payload } from '../ttn-app-server/DecodePayload.mjs'; + +export default async function(c) { + let { ansi: a, log: l, settings } = c.cradle; + + // 2: CLI Argument Parsing + let args = process.argv.slice(2); // Slice out the node binary name and the filename + let extras = []; + for(let i = 0; i < args.length; i++) { + if(!args[i].startsWith("-")) { + extras.push(args[i]); + continue; + } + + switch(args[i]) { + case "--help": + case "-h": + show_help(c.cradle); + process.exit(); + break; + + case "--version": + case "-v": + console.log(program.version); + break; + + // Add more arguments here + } + } + + // 3: Environment Variable Parsing + + // process.env.XYZ + + // 4: Run + if(extras.length < 1) { + console.error(`${a.fred}${a.hicol}Error: No subcommand specified.${a.reset}`); + show_help(c.cradle); + process.exit(); + } + + l.log(`${a.fgreen}${a.hicol}*** LoRaWAN Signal Mapper ***${a.reset}`); + + switch(extras[0]) { + case "ttn-app-server": + l.log(`${a.fgreen}${a.hicol}Starting The Things Network application server${a.reset}`); + + let app_server = c.resolve("TTNAppServer"); + await app_server.run(); + break; + + case "decode-test": + l.log(`${a.fgreen}${a.hicol}Decoding message${a.reset}`); + if(process.argv.length < 4) { + l.error("No message specified. Specify the message to decode in single quotes directly after 'decode-test'."); + process.exit(1); + } + l.log("Input: ", process.argv[3]); + l.log("Output: ", decode_payload(process.argv[3])); + break; + + default: + console.error(`${a.fred}${a.hicol}Error: Subcommand '${extras[0]}' not recognised.${a.reset}`); + console.error( `${a.fred}Perhaps you mistyped it, or it hasn't been implemented yet?`); + process.exit(1); + break; + } + +} diff --git a/server/bootstrap/container.mjs b/server/bootstrap/container.mjs index 9e3aa03..e5483a5 100644 --- a/server/bootstrap/container.mjs +++ b/server/bootstrap/container.mjs @@ -1,5 +1,9 @@ "use strict"; +import { promises as fs } from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + import a from 'awilix'; import Ansi from '../Helpers/Ansi.mjs'; @@ -10,22 +14,47 @@ import MessageHandler from '../ttn-app-server/MessageHandler.mjs'; import settings from './settings.mjs'; import database_init from '../bootstrap/database_init.mjs'; -const c = a.createContainer({ - injectionMode: a.InjectionMode.PROXY -}); +const root_dir = path.dirname(path.dirname(fileURLToPath(import.meta.url))); -c.register({ - settings: a.asValue(settings), - ansi: a.asClass(Ansi).singleton(), - log: a.asClass(Log).singleton(), - database: a.asFunction(database_init).singleton(), - TTNAppServer: a.asClass(TTNAppServer), - MessageHandler: a.asClass(MessageHandler) -}); +export default async function setup() { + const c = a.createContainer({ + injectionMode: a.InjectionMode.PROXY + }); -c.loadModules("../Repos.SQLite/*.mjs", { - register: a.asClass, - lifetime: a.Lifetime.SINGLETON -}); - -export default c; + c.register({ + root_dir: a.asValue(root_dir), + settings: a.asValue(settings), + ansi: a.asClass(Ansi).singleton(), + log: a.asClass(Log).singleton(), + database: a.asFunction(database_init).singleton(), + TTNAppServer: a.asClass(TTNAppServer), + MessageHandler: a.asClass(MessageHandler) + }); + + let repo_filenames = await fs.readdir(path.join(root_dir, "./Repos.SQLite")); + + for(let repo_filename of repo_filenames) { + let class_root = await import(path.join(root_dir, `./Repos.SQLite/${repo_filename}`)), + class_name = class_root.default.prototype.constructor.name; + + c.register( + class_name, + a.asClass(class_root.default).singleton(), + ); + } + + // console.log(c.registrations); + + // c.loadModules([ + // "./Repos.SQLite/*.mjs" + // // "./Repos.SQLite/ReadingRepo.mjs" + // ], { + // cwd: root_dir, + // resolverOptions: { + // register: a.asClass, + // lifetime: a.Lifetime.SINGLETON + // } + // }); + + return c; +} diff --git a/server/bootstrap/database_init.mjs b/server/bootstrap/database_init.mjs index 2d14c14..ddffb1f 100644 --- a/server/bootstrap/database_init.mjs +++ b/server/bootstrap/database_init.mjs @@ -5,9 +5,9 @@ import Database from 'better-sqlite3'; var db = null; -async function init({ settings: { database: { filename, options } } }) { +function init({ settings: { database: { filename, options } } }) { db = new Database(filename, options); - db.exec(await fs.promises.readFile("../db_template.sql", "utf8")); + db.exec(fs.readFileSync("../db_template.sql", "utf8")); return db; } diff --git a/server/help.mjs b/server/help.mjs index 11be188..9026940 100644 --- a/server/help.mjs +++ b/server/help.mjs @@ -1,10 +1,6 @@ import path from 'path'; -import c from './bootstrap/container.mjs'; - -const a = c.resolve("ansi"); - -export default function(settings) { +export default function({ settings, ansi : a }) { console.log(`${settings.program_name}, ${settings.version} ${a.locol}By Starbeamrainbowlabs${a.reset} diff --git a/server/index.mjs b/server/index.mjs index 8bfd742..201118b 100755 --- a/server/index.mjs +++ b/server/index.mjs @@ -2,74 +2,16 @@ "use strict"; // 1: Setup & Imports -import c from './bootstrap/container.mjs'; +import setup from './bootstrap/container.mjs'; +import cli from './bootstrap/cli.mjs'; -import show_help from './help.mjs'; -import { decode_payload } from './ttn-app-server/DecodePayload.mjs'; - -const settings = c.resolve("settings"); -const a = c.resolve("ansi"); -const l = c.resolve("log"); - -// 2: CLI Argument Parsing -let args = process.argv.slice(2); // Slice out the node binary name and the filename -let extras = []; -for(let i = 0; i < args.length; i++) { - if(!args[i].startsWith("-")) { - extras.push(args[i]); - continue; - } - - switch(args[i]) { - case "--help": - case "-h": - show_help(settings); - process.exit(); - break; - - case "--version": - case "-v": - console.log(program.version); - break; - - // Add more arguments here +async function run() { + try { + let c = await setup(); + await cli(c); + } catch(error) { + console.error(error); } } -// 3: Environment Variable Parsing - -// process.env.XYZ - -// 4: Run -if(extras.length < 1) { - console.error(`${a.fred}${a.hicol}Error: No subcommand specified.${a.reset}`); - show_help(settings); - process.exit(); -} - -l.log(`${a.fgreen}${a.hicol}*** LoRaWAN Signal Mapper ***${a.reset}`); - -switch(extras[0]) { - case "ttn-app-server": - l.log(`${a.fgreen}${a.hicol}Starting The Things Network application server${a.reset}`); - - let app_server = c.resolve("TTNAppServer"); - app_server.run(); - break; - - case "decode-test": - l.log(`${a.fgreen}${a.hicol}Decoding message${a.reset}`); - if(process.argv.length < 4) { - l.error("No message specified. Specify the message to decode in single quotes directly after 'decode-test'."); - process.exit(1); - } - l.log("Input: ", process.argv[3]); - l.log("Output: ", decode_payload(process.argv[3])); - break; - - default: - console.error(`${a.fred}${a.hicol}Error: Subcommand '${extras[0]}' not recognised.${a.reset}`); - console.error( `${a.fred}Perhaps you mistyped it, or it hasn't been implemented yet?`); - process.exit(1); - break; -} +run();