From bd08aae1da2dafe7020aff9c4b7871ec256ff78a Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Wed, 10 Jul 2019 14:11:46 +0100
Subject: [PATCH] Asyncify everything so that we can do dependency injection

---
 .gitignore                         |  1 +
 server/bootstrap/cli.mjs           | 72 ++++++++++++++++++++++++++++
 server/bootstrap/container.mjs     | 63 ++++++++++++++++++-------
 server/bootstrap/database_init.mjs |  4 +-
 server/help.mjs                    |  6 +--
 server/index.mjs                   | 76 ++++--------------------------
 6 files changed, 131 insertions(+), 91 deletions(-)
 create mode 100644 server/bootstrap/cli.mjs

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();
