UNPKG

@trap_stevo/filetide-cli

Version:

Seamless, real-time file transfers between devices with effortless connectivity. A powerful command-line tool built for instant, secure, and cross-platform file sharing, enabling efficient and reliable data transfers in any network environment.

543 lines (542 loc) 19.4 kB
#!/usr/bin/env node "use strict"; function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); } function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); } function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); } const { HUDUtilityManager } = require("@trap_stevo/legendarybuilderpronodejs-utilities"); const FileTideClient = require("@trap_stevo/filetide-client"); const FileTide = require("@trap_stevo/filetide"); const readline = require("readline"); const chalk = require("chalk"); const path = require("path"); const fs = require("fs"); const os = require("os"); const CLIHistoryManager = require("./HUDManagers/CLIHistoryManager"); const ConsoleTable = require("./HUDComponents/ConsoleTable"); let fileMessagerInstance; let typingTimer; const shortcuts = { ">Downloads": { description: "The downloads folder of the user's system.", shortCut: ">Downloads" }, ">Documents": { description: "The documents folder of the user's system.", shortCut: ">Documents" }, ">Desktop": { description: "The desktop of the user's system.", shortCut: ">Desktop" }, ">AppData": { description: "The roaming application data folder of the user's system.", shortCut: ">AppData" }, ">LocalAppData": { description: "The local application data folder of the user's system.", shortCut: ">LocalAppData" }, ">Music": { description: "The music folder of the user's system.", shortCut: ">Music" }, ">Photos": { description: "The photos folder of the user's system.", shortCut: ">Photos" }, ">Videos": { description: "The videos folder of the user's system.", shortCut: ">Videos" }, ">Public": { description: "The public folder of the user's system.", shortCut: ">Public" }, ">Templates": { description: "The templates folder of the user's system.", shortCut: ">Templates" }, ">Temp": { description: "The temporary files folder of the user's system.", shortCut: ">Temp" }, ">LogFiles": { description: "The log files folder of the user's system.", shortCut: ">LogFiles" }, ">SystemRoot": { description: "The system root folder of the user's system.", shortCut: ">SystemRoot" }, ">Cache": { description: "The cache folder of the user's system.", shortCut: ">Cache" }, ">Config": { description: "The configuration folder of the user's system.", shortCut: ">Config" }, ">CurrentDirectory": { description: "The current instance folder of the user's system.", shortCut: ">CurrentDirectory" }, ">CurrentUser": { description: "The current user folder of the connected user's system.", shortCut: ">CurrentUser" }, ">Home": { description: "The home folder of the user's system.", shortCut: ">Home" } }; const commands = { "request": { description: "Request files / directories from the desired client!", command: "request <clientName> \"/path/to/file\" \"/destination/path\"" }, "send": { description: "Sends files / directories to the desired client!", command: "send <clientName> \"/path/to/file\" \"/destination/path\"" }, "channel-": { description: "Updates the tide domain (room) of the connection!", command: "channel- <channel-name>" }, "tide-": { description: "Updates the tide (connection URL)!", command: "tide- <https://domain.com>" }, "cmd-": { description: "List the current available commands!", command: "cmd-" }, "id-": { description: "Updates your display name!", command: "id- <client-name>" }, "online-": { description: "See all the connected clients!", command: "online-" }, "shrtcs-": { description: "Lists the available path shortcuts for seamless transfers!", command: "shrtcs-" }, "CTRL + L": { description: "Clears the current console.", command: "CTRL + L" }, "CTRL + Q": { description: "Exits the current session.", command: "CTRL + Q" } }; var _FileTideCLI_brand = /*#__PURE__*/new WeakSet(); class FileTideCLI { constructor(inputDeviceName, inputTideURL, inputCurrentRoom, displayTitle = true, cli = true, enableCLI = true, allowCLIBeforeConnection = false, clientOptions = {}, connectionOptions = {}, transportOptions = {}, messagerSettings = {}, enableTransferBarrier = true, options = {}, debugMode = true) { _classPrivateMethodInitSpec(this, _FileTideCLI_brand); const fileTide = new FileTideClient(inputDeviceName, inputTideURL, inputCurrentRoom, displayTitle, cli, debugMode); this.fileMessagerInstance = fileTide.fileMessagerInstance; this.commandHistoryManager = new CLIHistoryManager(569); this.fileTideClient = fileTide; this.typingTimer = null; this.rl = null; this.currentInput = ""; this.pastedInput = ""; this.allowCLIBeforeConnection = allowCLIBeforeConnection; this.transferBarrier = enableTransferBarrier; this.enableCLI = enableCLI; if (this.enableCLI) { this.startClient(clientOptions, connectionOptions, transportOptions, messagerSettings, this.transferBarrier, () => {}, (transferData, forwardResponse) => { _assertClassBrand(_FileTideCLI_brand, this, _promptTransferBarrier).call(this, transferData).then(acceptTransfer => { if (acceptTransfer) { console.log(transferData.transferType === "send" ? "Transfer accepted!" : "Request accepted!"); forwardResponse(true, transferData); return; } console.log(transferData.transferType === "send" ? "Transfer declined." : "Request declined."); forwardResponse(false, transferData); }); }, () => {}, () => {}, options); } if (this.allowCLIBeforeConnection) { _assertClassBrand(_FileTideCLI_brand, this, _startListeningForInput).call(this); } } startClient(clientOptions = {}, connectionOptions = {}, transportOptions = {}, messagerSettings = {}, enableTransferBarrier = true, onIncomingFile, onIncomingTransfer, onTransferBarrier, onTransferProgress, options = {}) { this.fileTideClient.startClient(clientOptions, connectionOptions, transportOptions, messagerSettings, fileMessager => { this.fileMessagerInstance = fileMessager; _assertClassBrand(_FileTideCLI_brand, this, _startListeningForInput).call(this); }, () => {}, onIncomingFile, onIncomingTransfer, onTransferBarrier, onTransferProgress, enableTransferBarrier, { onTransferComplete: (data, activeTransfers, success) => { _assertClassBrand(_FileTideCLI_brand, this, _displayCLIHUD).call(this); }, onCurrentClientIDAlreadyOnline: updatedClientID => { this.fileTideClient.changeClientID(updatedClientID); }, onCurrentOnlineClients: currentClients => { _assertClassBrand(_FileTideCLI_brand, this, _displayCLIHUD).call(this); }, ...options }); } clear() { console.clear(); this.fileTideClient.displayTitle(true); setTimeout(() => { _assertClassBrand(_FileTideCLI_brand, this, _displayCLIHUD).call(this); this.currentInput = ""; _assertClassBrand(_FileTideCLI_brand, this, _clearPromptInput).call(this); this.rl.prompt(); }, 269); } exitFileTideCLI() { if (this.fileMessagerInstance && this.fileMessagerInstance.clientTide) { this.fileTideClient.displayMessage("info", "\n\n"); this.fileTideClient.broadcastClientOffline(this.fileMessagerInstance); this.fileMessagerInstance.clientTide.closeSocket(this.fileTideClient.currentDeviceName); } this.fileTideClient.displayMessage("info", "\nExiting FileTide..."); process.exit(); } async processCommand(input) { if (!input) { return; } const trimmedInput = input.trim(); if (_assertClassBrand(_FileTideCLI_brand, this, _handleDetailsCommand).call(this, trimmedInput)) { return; } if (trimmedInput.startsWith("send")) { const args = this.parseArguments(trimmedInput, true); const [command, recipientId, filePath, destinationPath, filterContent] = args; if (command === "send" && recipientId && filePath && destinationPath) { this.commandHistoryManager.add(trimmedInput); await this.fileTideClient.transferFiles(recipientId, filePath, destinationPath, filterContent || []); return; } FileTide.outputGradient(`[${this.fileTideClient.deviceName}] Invalid send command. Usage: ${commands["send"].command}`, ["#F94144", "#F3722C"]); return; } else if (trimmedInput.startsWith("request")) { const args = this.parseArguments(trimmedInput, true); const [command, clientID, filePath, destinationPath, filterContent] = args; if (command === "request" && clientID && filePath && destinationPath) { this.commandHistoryManager.add(trimmedInput); this.fileTideClient.requestFileTransfer(clientID, filePath, destinationPath, filterContent || []); return; } FileTide.outputGradient(`[${this.fileTideClient.deviceName}] Invalid send command. Usage: ${commands["request"].command}`, ["#F94144", "#F3722C"]); return; } else if (trimmedInput.startsWith("channel-")) { const [command, channel] = trimmedInput.split(" "); if (command === "channel-" && channel) { this.commandHistoryManager.add(trimmedInput); this.fileTideClient.changeRoom(channel); return; } FileTide.outputGradient(`[${this.fileTideClient.deviceName}] Invalid channel command. Usage: ${commands["channel-"].command}`, ["#F94144", "#F3722C"]); return; } else if (trimmedInput.startsWith("tide-")) { const [command, url] = trimmedInput.split(" "); if (command === "tide-" && url) { this.commandHistoryManager.add(trimmedInput); this.fileTideClient.changeTideUrl(url); return; } FileTide.outputGradient(`[${this.fileTideClient.deviceName}] Invalid tide command. Usage: ${commands["tide-"].command}`, ["#F94144", "#F3722C"]); return; } else if (trimmedInput.startsWith("id-")) { const [command, clientID, ...args] = trimmedInput.split(" "); const trailingName = args.join(" "); if (command === "id-" && `${clientID} ${trailingName}`) { this.commandHistoryManager.add(trimmedInput); this.fileTideClient.changeClientID(`${clientID} ${trailingName}`, () => { _assertClassBrand(_FileTideCLI_brand, this, _displayCLIHUD).call(this); }); return; } FileTide.outputGradient(`[${this.fileTideClient.deviceName}] Invalid id command. Usage: ${commands["id-"].command}`, ["#F94144", "#F3722C"]); return; } FileTide.outputGradient(`[${this.fileTideClient.deviceName}] Invalid channel command. Enter: "cmd-" for the list of commands.`, ["#F94144", "#F3722C"]); return; } parseArguments(input, includesFilter = false) { const regex = /[^\s"]+|"([^"]*)"/g; const args = []; let match; while ((match = regex.exec(input)) !== null) { args.push(match[1] ? match[1] : match[0]); } if (!includesFilter) { return args; } const mainArgs = args.slice(0, 4); const filterContentRaw = args.slice(4).join(" "); let filterContent; if (filterContentRaw.includes(",")) { filterContent = filterContentRaw.split(",").map(item => item.trim()); } else { filterContent = filterContentRaw.split(/\s+/).filter(item => item.trim() !== ""); } return [...mainArgs, filterContent]; } static getShortcuts() { const cliTable = new ConsoleTable({ padding: 2, headerAlign: "center", cellAlign: "left", borderStyle: "bold", columnOrder: ["shortCut", "description"], columnNames: { shortCut: "Shortcut", description: "Description" }, title: "✨ Shortcuts ✨", tableNumber: 1, gradient: { title: ["#00FFFF", "#1E90FF"], header: ["#FFD700", "#FF8C00"], border: ["#2e2f30", "#788e9e"], cell: ["#00BFFF", "#1E90FF"] }, cellColor: (content, column) => { if (column === "shortCut") { return chalk.blue(content); } return content; } }); cliTable.setData(shortcuts); console.log(cliTable.render(), "\n"); return; } static listCommands() { const cliTable = new ConsoleTable({ padding: 2, headerAlign: "center", cellAlign: "left", borderStyle: "bold", columnOrder: ["command", "description"], columnNames: { command: "Command", description: "Description" }, title: "✨ Commands ✨", tableNumber: 1, gradient: { title: ["#00FFFF", "#1E90FF"], header: ["#FFD700", "#FF8C00"], border: ["#2e2f30", "#788e9e"], cell: ["#00BFFF", "#1E90FF"] }, cellColor: (content, column) => { if (column === "command") { return chalk.blue(content); } return content; } }); cliTable.setData(commands); console.log(cliTable.render(), "\n"); return; } getOnlineClients(displayCLIHUD = true) { this.fileTideClient.getOnlineClients(() => { if (!displayCLIHUD) { return; } setTimeout(() => { _assertClassBrand(_FileTideCLI_brand, this, _displayCLIHUD).call(this); }, 269); }); return; } } function _clearTypingTimer(handleTypingTimeout, typingTimeout = 5000) { if (this.typingTimer) { clearTimeout(this.typingTimer); } this.typingTimer = setTimeout(handleTypingTimeout, typingTimeout); return; } function _displayCLIHUD(redrawPrompt = true, includeDescription = true) { if (!this.rl) { return; } if (includeDescription) { this.fileTideClient.displayMessage("info", `\n[${this.fileTideClient.deviceName}] Enter "cmd-" for the list of commands.)\n`); } this.fileTideClient.displayMessage("info", `<${this.fileTideClient.tideUrl}>`); const promptText = this.fileTideClient.applyGradient(` ${HUDUtilityManager.convertUTCDateToDateDisplay(HUDUtilityManager.generateUTCDateDouble(), true, 1)} :: FileTide >> `, "indicator"); if (!redrawPrompt) { process.stdout.write(promptText); process.stdout.write(this.currentInput); } if (redrawPrompt) { this.rl.setPrompt(promptText); this.rl.prompt(); } return; } function _startListeningForInput() { if (this.rl) { this.rl.close(); process.stdin.removeListener('keypress', this.keypressHandler); } this.rl = readline.createInterface({ output: process.stdout, input: process.stdin, historySize: 1000 }); setTimeout(() => { _assertClassBrand(_FileTideCLI_brand, this, _displayCLIHUD).call(this); }, 269); this.keypressHandler = (char, key) => { if (key && key.ctrl && key.name === "q") { this.exitFileTideCLI(); return; } if (key && key.ctrl && key.name === "l") { this.clear(); return; } if (key.name === "up" || key.name === "down") { const previousCommand = this.commandHistoryManager.get(key.name); if (previousCommand) { this.currentInput = previousCommand; } return; } if (key.name === "right" || key.name === "left" || key.ctrl && key.name === "v") { return; } if (key.name === "return") { this.currentInput = ""; this.pastedInput = ""; this.rl.prompt(); } else if (key.name === "backspace") { if (this.currentInput.length > 0) { this.currentInput = this.currentInput.slice(0, -1) || ""; } } else { this.currentInput += char; } _assertClassBrand(_FileTideCLI_brand, this, _clearTypingTimer).call(this, () => { _assertClassBrand(_FileTideCLI_brand, this, _displayCLIHUD).call(this, false); }, 69000); }; this.rl.input.on("keypress", this.keypressHandler); this.rl.on("line", async input => { this.pastedInput += input.trim(); await this.processCommand(this.pastedInput); this.pastedInput = ""; this.rl.prompt(); }); } function _clearPromptInput() { readline.clearLine(process.stdout, 0); readline.cursorTo(process.stdout, 0); this.currentInput = ""; return; } function _handleDetailsCommand(trimmedInput) { const [command] = trimmedInput.split(" "); const detailsCommands = { "online-": () => this.getOnlineClients(), "shrtcs-": () => _assertClassBrand(_FileTideCLI_brand, this, _getShortcuts).call(this), "cmd-": () => _assertClassBrand(_FileTideCLI_brand, this, _listCommands).call(this) }; if (detailsCommands[command]) { this.commandHistoryManager.add(command); detailsCommands[command](); return true; } return false; } function _promptTransferBarrier(transferData) { return new Promise(resolve => { const question = `${transferData.clientID} wants ${transferData.transferType === "requestSend" ? "you to send:" : "to transfer you:"}\n\n\t${transferData.path}.\n\nDo you accept (Y/n)? `; FileTide.outputGradient(question, ["#3c97b0", "#7addeb"]); this.rl.question("", answer => { const normalizedAnswer = answer.trim().toLowerCase(); if (normalizedAnswer === "" || normalizedAnswer === "y") { resolve(true); } else { resolve(false); } }); }); } function _getShortcuts() { const cliTable = new ConsoleTable({ padding: 2, headerAlign: "center", cellAlign: "left", borderStyle: "bold", columnOrder: ["shortCut", "description"], columnNames: { shortCut: "Shortcut", description: "Description" }, title: "✨ Shortcuts ✨", tableNumber: 1, gradient: { title: ["#00FFFF", "#1E90FF"], header: ["#FFD700", "#FF8C00"], border: ["#2e2f30", "#788e9e"], cell: ["#00BFFF", "#1E90FF"] }, cellColor: (content, column) => { if (column === "shortCut") { return chalk.blue(content); } return content; } }); cliTable.setData(shortcuts); this.fileTideClient.displayMessage("info", `\n[${this.fileTideClient.deviceName}]\n\n`); console.log(cliTable.render(), "\n"); setTimeout(() => { _assertClassBrand(_FileTideCLI_brand, this, _displayCLIHUD).call(this); }, 269); return; } function _listCommands() { const cliTable = new ConsoleTable({ padding: 2, headerAlign: "center", cellAlign: "left", borderStyle: "bold", columnOrder: ["command", "description"], columnNames: { command: "Command", description: "Description" }, title: "✨ Commands ✨", tableNumber: 1, gradient: { title: ["#00FFFF", "#1E90FF"], header: ["#FFD700", "#FF8C00"], border: ["#2e2f30", "#788e9e"], cell: ["#00BFFF", "#1E90FF"] }, cellColor: (content, column) => { if (column === "command") { return chalk.blue(content); } return content; } }); cliTable.setData(commands); this.fileTideClient.displayMessage("info", `\n[${this.fileTideClient.deviceName}]\n\n`); console.log(cliTable.render(), "\n"); setTimeout(() => { _assertClassBrand(_FileTideCLI_brand, this, _displayCLIHUD).call(this); }, 269); return; } ; module.exports = FileTideCLI;