const blessed = require('neo-blessed'); // Require the needed libs const Hyperswarm = require('hyperswarm') const crypto = require('hypercore-crypto') const b4a = require('b4a') const readline = require('readline') const fs = require("fs"); // Import our command const { login } = require('./commands/login'); const { execute } = require('./commands/exec'); const { stop } = require('./commands/stop'); const { start } = require('./commands/start'); const { restart } = require('./commands/restart'); const { stats } = require('./commands/stats'); const { changeDir } = require('./commands/cd'); const { AIRequest } = require('./commands/AI'); let rand = Math.floor(Math.random() * 99999).toString(); let USERPWD = "/" let DAPI_KEY let LOGGEDIN = false let MYKEY = [] let conns = [] let connectedUsers = []; let USERNAME = ["annon" + rand] function sleep(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } function addUser(user, peerId) { connectedUsers.push({ name: user, peerId: peerId }); sidebarBox.setContent(connectedUsers.map(user => `${user.name} - ${user.peerId}`).join("\n")); screen.render(); } function removeUser(peerId) { connectedUsers = connectedUsers.filter(user => user.peerId !== peerId); sidebarBox.setContent("Connected Peers: \n" + connectedUsers.map(user => `${user.name} - ${user.peerId}`).join("\n")); screen.render(); } // Create the screen const screen = blessed.screen({ smartCSR: true, fastCSR: true }); let mainBox = blessed.box({ parent: screen, top: 0, left: 0, width: '80%', height: '80%', border: { type: 'line' }, style: { fg: 'white', bg: 'black' }, keys: true, vi: true, alwaysScroll: true, scrollable: true, scrollbar: { style: { bg: 'yellow' } } }); async function updateScroll() { mainBox.scrollTo(mainBox.getScrollHeight()); } // Create the STDIN box for chat input and command input const stdinBox = blessed.textbox({ bottom: '0', left: '0', width: '80%', height: '21%', border: { type: 'line' }, style: { fg: 'white', bg: 'black', border: { fg: '#f0f0f0' }, }, inputOnFocus: true, input: true }); // Create the sidebar box for connected peers const sidebarBox = blessed.box({ top: '0', right: '0', width: '20%', height: '100%', content: '', border: { type: 'line' }, style: { fg: 'white', bg: 'black', border: { fg: '#f0f0f0' }, } }); sidebarBox.setLabel("Peers since connection: 0") const originalLog = console.log; console.log = (...args) => { mainBox.setContent(mainBox.getContent() + `\n${args.join(' ')}`); updateScroll() stdinBox.clearValue(); screen.render() } // Generate a random public key const publicKey = crypto.randomBytes(32) // Create the swarm and pass in the public key const swarm = new Hyperswarm() const commandDir = './commands/'; const commandFiles = fs.readdirSync(commandDir); const commands = {} for (const file of commandFiles) { const commandName = file.split(".")[0] require(`${commandDir}/${file}`) const command = require(`${commandDir}/${file}`); commands[commandName] = command; } async function handleCommand(input) { if (input.startsWith("!") || input.startsWith(">")) { const command = input.split(" ") if (!command) return consoile.log("Please either send a message or enter a command.") switch (command[0]) { case "!": AIRequest(command.slice(1).join(" ")) break; case ">cd": USERPWD = await changeDir(command[1], USERPWD); console.log(USERPWD) break; case ">stats": stats(MYKEY[0]) break; case ">": execute(MYKEY[0], command.slice(1).join(" "), USERPWD, conns); break; case ">restart": restart(MYKEY[0]) break; case ">stop": stop(MYKEY[0]) break; case ">start": start(MYKEY[0]) break; case ">login": login(command[1], conns, MYKEY, USERNAME) break; case ">exit": console.log("Sending close message...") for (let conn of conns) { conn.write(`CLOSED: ${publicKey.toString('hex')}`) } await sleep(2000) process.exit() break default: console.log("Command not found.") } } else { for (const conn of conns) conn.write(`${USERNAME[0]}: ${input}`) } console.log(`${USERNAME[0]}: ${input}`) } swarm.on('connection', conn => { process.on('SIGINT', async () => { console.log("Sending close message...") for (let conn of conns) { conn.write(`CLOSED: ${publicKey.toString('hex')}`) } await sleep(2000) process.exit() }) const name = b4a.toString(conn.remotePublicKey, 'hex') console.log(`* got a connection from ${name} (${USERNAME[0]}) *`) addUser(USERNAME[0], name) sidebarBox.setLabel("Connected Peers: " + connectedUsers.length) screen.render() conns.push(conn) conn.once('close', () => conns.splice(conns.indexOf(conn), 1)) conn.on('data', data => { 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 () => { await sleep(5000) conns = conns.filter(c => c !== conn); conn.destroy(); })(); } else { console.log(`${data}`) } // Use the USERNAME if it has been set, otherwise use the public key }) }) swarm.on('error', (err) => { console.log('Error connecting to peer:', err); }); // Join a common topic const topic = process.argv[2] ? b4a.from(process.argv[2], 'hex') : crypto.randomBytes(32) setTimeout(() => { const discovery = swarm.join(topic, { lookup: true, announce: true, timeout: 300000 }); // The flushed promise will resolve when the topic has been fully announced to the DHT discovery.flushed().then(() => { mainBox.setLabel("Topic: " + b4a.toString(topic, 'hex') + " (Share to connect)") stdinBox.setLabel("To login: >login [TOKEN] | To quit: >exit") screen.render() }) }, 1000); // Append the boxes to the screen screen.append(mainBox); screen.append(stdinBox); screen.append(sidebarBox); // Handle input in the stdinBox stdinBox.on('submit', (input) => { // handle the input here // for example : handleCommand(input); // clear the input field stdinBox.focus(); // screen.render(); }); // setInterval(() => { // mainBox.scrollTo(mainBox.getScrollHeight()); // }, 1000); stdinBox.focus(); // Render the screen screen.render() // Quit on Escape, q, or Control-C. screen.key(['escape', 'q', 'C-c'], function(ch, key) { return process.exit(0); });