/*
Unofficial brainlet command-line interface
Copyright (C) 2020 hiimgoodpack
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
const brainlet = require("./brainlet-lib/index.js");
const readline = require("readline").createInterface({
input: process.stdin,
output: process.stdout
});
const ask = (question) => {
return new Promise((res, rej) => {
readline.question(question, res);
});
};
const catchErrors = (promise) => {
return new Promise((res, rej) => {
promise.then(res).catch((...errors) => {
console.error(...errors);
res(undefined);
});
});
};
const promiseSucceeded = async (promise) => {
return await new Promise((res, rej) => {
promise.then(() => {
res(true);
}).catch((...errors) => {
console.error(...errors);
res(false);
});
});
};
const getColorCode = ([r, g, b]) => {
return `\x1b[38;2;${r};${g};${b}m`;
};
const resetColorCode = "\x1b[0m";
const clearLine = "\x1b[2K";
const hexToRGB = (hex) => {
let decimal = parseInt(hex.substr(1), 16);
return [(decimal & 0xFF0000) >> 16, (decimal & 0xFF00) >> 8, decimal & 0xFF];
};
let user = {};
console.log(`Unofficial brainlet command-line interface
Copyright (C) 2020 hiimgoodpack
License GPLv3+: GNU GPL version 3 or later
Warning: You should not connect to an untrusted server,
or a server with untrusted clients, as there may be some risks
with outputting arbritrary text ot the console.
`);
// Put in async function
(async() => {
const server = process.argv[2];
let prompt = 1;
let developerMode = 0;
let socket;
const useDeveloperMode = () => {
return new Promise((res, rej) => {
if (!developerMode) {
ask(`Warning: This command requires developer mode to be enabled.
Enabling developer mode may enable commands which can reveal private information or information
which can be used to log into your account.
Note: Every time the client is started, developer mode is disabled, even if you have enabled it previously in another session.
Are you sure you want to enable developer mode? [y/n] `).then((response) => {
if (response === "y") {
developerMode = true;
console.log("Developer mode has been enabled")
}
res();
});
} else
res();
});
}
while (prompt) {
const input = await ask("> ");
switch (input) {
case "q":
case "quit": {
prompt = 0;
break;
}
case "signup": {
let newUser = {};
// Get username, email, and password
while (1) {
newUser.name = await ask("Username: ");
let error = brainlet.valid.username(newUser.name);
if (error)
console.error(error);
else
break;
}
while (1) {
newUser.email = await ask("Email: ");
let error = brainlet.valid.email(newUser.email);
if (error)
console.error(error);
else
break;
}
while (1) {
newUser.password = await ask("Password: ");
let error = brainlet.valid.password(newUser.password);
if (error)
console.error(error);
else
break;
}
while (1) {
let confirmationPassword = await ask("Enter same password again: ");
if (confirmationPassword === newUser.password)
break;
else
console.error("Passwords do not match");
}
if (await promiseSucceeded(brainlet.users.create(server, newUser))) {
console.log("Account successfully created. To log in, use the \"login\" command");
}
break;
}
case "login": {
// Get username and password
while (1) {
user.name = await ask("Username: ");
let error = brainlet.valid.username(user.name);
if (error)
console.error(error);
else
break;
}
while (1) {
user.password = await ask("Password: ");
let error = brainlet.valid.password(user.password);
if (error)
console.error(error);
else
break;
}
let newUser = await catchErrors(brainlet.users.login(server, user));
if (newUser) {
newUser.password = undefined;
newUser.email = undefined;
user = newUser;
console.log("Successfully logged in, starting connection");
socket = await brainlet.categories.client(server, user.token);
console.log("Connection started");
}
break;
}
case "ls": {
if (!socket) {
console.error("You must log in before listing categories");
break;
}
const limit = 5;
let categories = await catchErrors(brainlet.categories.list(server, user.token, limit));
if (categories) {
if (categories === limit) {
console.error(`Warning: This may be an incomplete list of categories`);
}
console.log("CATEGORY ID | CATEGORY TITLE");
for (let category of categories) {
console.log(`${category._id} | ${category.title}`);
}
}
break;
}
case "join": {
if (!socket) {
console.error("You must log in before joining a category");
break;
}
let categoryID = await ask("Category ID: ");
await catchErrors(socket.connect([categoryID]));
console.log(`Successfully joined category ${categoryID}.
Anything typed will be sent to other users, unless it is prefixed with '/'.
To leave this category, use '/quit'`);
const PS1 = `${getColorCode(hexToRGB(user.color))}${user.name}${resetColorCode} [message currently not sent]: `;
socket.onMessage((message) => {
if (message.category._id === categoryID) {
process.stdout.write(`\r${clearLine}${getColorCode(hexToRGB(message.author.color))}${message.author.username}${resetColorCode}: ${message.content}\n${PS1}`);
}
});
let sendMessages = true;
while (sendMessages) {
const message = await ask(PS1);
switch (message) {
case "/leave": {
sendMessages = false;
break;
}
default: {
if (message[0] === "/") {
console.error(`${getColorCode([0xdd, 0, 0])}Invalid command ${message}`);
break;
}
socket.send(categoryID, message);
}
}
}
break;
}
case "dump": {
await useDeveloperMode();
if (developerMode) {
console.log(user);
}
break;
}
}
}
readline.close();
})();