Source: secure_connection.js

const aes = require("./aes");

const net = require("net");

/**
 * Creates an easy to use connection instance
 * @param {net.Socket} _socket The socket of said connection
 * @param {string} _aesKey The already established aes key
 * 
 * @class
 */
function SecureConnection (_socket, _aesKey) {

	var socket = _socket;
	var aesKey = _aesKey;

	function execute (event, args) {

		for (e of events[event]) {
			e.apply(undefined, args);
		}

	}

	var offloading = false;
	var ofb = "";

	var ofl = 0;

	/**
	 * Process data that has been received
	 * @private
	 */
	this.process = function process (data) {

		if (offloading) {
			ofb += data.toString().trim();
			if (ofb.length === ofl) {

				offloading = false;
				this.process(ofb);

			}
			return;
		}

		var e = aes.decryptString(data.toString().trim(), aesKey);

		var j = JSON.parse(e);

		if (j.type === "start_load") {
			offloading = true;
			ofl = j.data;
		}

		if (j.type === "json") {

			execute(j.type, [j.data]);

		} else if (j.type === "file") {

			execute(j.type, [j.data.name, Buffer.from(j.data.content)]);

		}

	}

	var events = {

		json: [],
		file: []

	}

	/**
	 * Listen to an event
	 * @param {string} event
	 * @param {Function} listener 
	 * @returns {SecureConnection}
	 */

	this.on = function on (event, listener) {

		if (!events[event]) throw new Error(`Invalid event: ${event}`);

		events[event].push(listener);

		return this;

	}

	this.write = function write (data) {

		var e = aes.encryptString(data, aesKey);

		if (e.length >= 65536) {

			var s = e.match(/.{1,65535}/g);

			// console.log(s.length);
			
			this.sendData("start_load", e.length);

			setTimeout(() => {

				var i = 0;

				var ii = setInterval(() => {

					if (s[i] === undefined) {clearInterval(ii); return;}

					socket.write(s[i] + "\n");

					i++;

				}, 50);

			}, 100);

		} else {

			socket.write(e + "\n");

		}

	}

	
	/**
	 * Sends data. I wouldn't recommend using this function directly.
	 * @param {string} type The type of data to send
	 * @param {Object} data The data to send
	 * @returns {SecureConnection}
	 * 
	 * @see sendJson
	 */

	this.sendData = function sendData (type, data) {

		this.write(JSON.stringify({

			type,
			data

		}));

		return this;

	}
	
	/**
	 * Sends JSON data
	 * @param {Object} json The JSON to send
	 * @returns {SecureConnection}
	 */

	this.sendJson = function sendJson (json) {

		this.sendData("json", json);

		return this;

	}
	
	/**
	 * Sends file data
	 * @param {string} name The name of the file to send
	 * @param {Buffer} content The file data to send
	 * @returns {SecureConnection}
	 */

	this.sendFile = function sendFile (name, content) {

		this.sendData("file", {
			name,
			content: [...content]
		});	
	
		return this;

	}

}

module.exports = SecureConnection;