@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
JavaScript
"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;