diff --git a/sshChat.js b/sshChat.js index 1acb52c..196803e 100644 --- a/sshChat.js +++ b/sshChat.js @@ -1,12 +1,13 @@ -const blessed = require('neo-blessed'); // Require the needed libs +const blessed = require('neo-blessed'); const Hyperswarm = require('hyperswarm') const crypto = require('hypercore-crypto') const b4a = require('b4a') const readline = require('readline') const fs = require("fs"); -// Import our command +// Import our commands - You must add this line. +// Otherwise there is no access to the command functions const { login } = require('./commands/login'); const { execute } = require('./commands/exec'); const { stop } = require('./commands/stop'); @@ -16,37 +17,38 @@ const { stats } = require('./commands/stats'); const { changeDir } = require('./commands/cd'); const { AIRequest } = require('./commands/AI'); +// Generate a random number, this is used when generating a anon name let rand = Math.floor(Math.random() * 99999).toString(); - +// Storage for our clients information let USERPWD = "/" let DAPI_KEY let LOGGEDIN = false let MYKEY = [] let conns = [] let connectedUsers = []; -let USERNAME = ["annon" + rand] +let USERNAME = ["anon" + rand] let DISCORD_USERID = [] - +// Sleep function used when closing connections. function sleep(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } - - +// Adding a user to a peer and user MAP to keep track of peers. function addUser(user, peerId) { connectedUsers.push({ name: user, peerId: peerId }); sidebarBox.setContent(connectedUsers.map(user => `${user.peerId}`).join("\n")); screen.render(); } - +// Removing a user to a peer and user MAP to keep track of peers. +// TODO: Get this to work properly function removeUser(peerId) { connectedUsers = connectedUsers.filter(user => user.peerId !== peerId); sidebarBox.setContent("Peers since connection: \n" + connectedUsers.map(user => `${user.peerId}`).join("\n")); screen.render(); } -// Create the screen +// Create the screen for blessed const screen = blessed.screen({ smartCSR: true, fastCSR: true @@ -67,22 +69,24 @@ screen.key(['escape', 'q', 'C-c'], function (ch, key) { }); -// Return to chat +// When users press ESC, you may press t or enter to go back +// to the chat input box screen.key(['t', 'enter'], function (ch, key) { stdinBox.focus(); }); -// Return to chat -screen.key(['p', 'enter'], function (ch, key) { +// When users press ESC, you may press p to go to the mainbox +// This lets users scroll the chat feed. +screen.key(['p'], function (ch, key) { sidebarBox.focus(); }); - -// Debug ONLY +// Debug ONLY - Use this to capture keypress events // screen.on('keypress', function(ch, key){ // console.log(JSON.stringify(key)); // }); +// Creating the mainbox let mainBox = blessed.box({ parent: screen, top: 0, @@ -107,6 +111,7 @@ let mainBox = blessed.box({ } }); +// A function to update the mainbox scroll per message. async function updateScroll() { mainBox.scrollTo(mainBox.getScrollHeight()); @@ -133,7 +138,7 @@ const stdinBox = blessed.textbox({ }); - +// Sidebar to display all peers that have been seen let sidebarBox = blessed.box({ parent: screen, top: '0', @@ -158,9 +163,11 @@ let sidebarBox = blessed.box({ } }); +// Setting the sidebar label. sidebarBox.setLabel("Peers since connection: 0") - +// Replacing the console.log function with our own +// This sends all console.log events to the main window. const originalLog = console.log; console.log = (...args) => { mainBox.setContent(mainBox.getContent() + `\n${args.join(' ')}`); @@ -170,18 +177,19 @@ console.log = (...args) => { } - // Generate a random public key const publicKey = crypto.randomBytes(32) // Create the swarm and pass in the public key const swarm = new Hyperswarm() +// Set up our commands const commandDir = __dirname + '/commands/'; const commandFiles = fs.readdirSync(commandDir); const commands = {} +// For each command lets add it to a var for (const file of commandFiles) { const commandName = file.split(".")[0] require(`${commandDir}/${file}`) @@ -190,6 +198,7 @@ for (const file of commandFiles) { } +// The command handler async function handleCommand(input) { if (input.startsWith("!") || input.startsWith(">")) { const command = input.split(" ") @@ -265,28 +274,39 @@ swarm.on('connection', conn => { process.exit() }) - + + // Remote Connection Name const name = b4a.toString(conn.remotePublicKey, 'hex') console.log(`* got a connection from ${name} (${USERNAME[0]}) *`) + // Add the user to the MAP addUser(USERNAME[0], name) + // Update the sidebar sidebarBox.setLabel("Peers since connection: " + connectedUsers.length) + // Render the changes screen.render() + // Add the connection to the conn list conns.push(conn) + // IF the connection is closed, remove a connection conn.once('close', () => conns.splice(conns.indexOf(conn), 1)) + + // Handle data as it comes in from the peer stream conn.on('data', data => { + // If data shows that a peer has left, lets handle it and remove their key if (data.toString().startsWith('CLOSED:')) { // Extract the key from the message string const key = data.toString().split(':')[1].trim(); removeUser(key) console.log(`Removing peer ${key}`); - (async () => { + // Wait 5 seconds, remove the peer from the connections + // This stops timeouts which crashes all peers. + (async () => { await sleep(5000) conns = conns.filter(c => c !== conn); conn.destroy(); })(); - } else { + // If there is no actions detected, update chat. console.log(`${data}`) } // Use the USERNAME if it has been set, otherwise use the public key @@ -301,7 +321,7 @@ swarm.on('error', (err) => { // Join a common topic const topic = process.argv[2] ? b4a.from(process.argv[2], 'hex') : crypto.randomBytes(32) - +// Join the topic with a timeout setTimeout(() => { const discovery = swarm.join(topic, { lookup: true, @@ -343,5 +363,4 @@ stdinBox.on('submit', (input) => { // }, 1000); stdinBox.focus(); // Render the screen - screen.render() \ No newline at end of file