UNPKG

@trap_stevo/filetide-client

Version:

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

422 lines (409 loc) 16.3 kB
"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 FileTide = require("@trap_stevo/filetide"); const chalk = require("chalk"); const path = require("path"); const fs = require("fs"); const os = require("os"); let currentRoom = "file-room"; let tideUrl = "http://localhost:9269"; const deviceName = os.hostname(); let fileTide; let fileMessagerInstance; const gradients = { success: ["\x1b[38;5;48m", "\x1b[38;5;49m", "\x1b[38;5;50m"], "indicator": ["\x1b[38;5;30m", "\x1b[38;5;37m", "\x1b[38;5;44m", "\x1b[38;5;51m", "\x1b[38;5;147m"], error: ["\x1b[38;5;203m", "\x1b[38;5;202m", "\x1b[38;5;208m"], info: ["\x1b[38;5;74m", "\x1b[38;5;75m"], critical: ["\x1b[38;5;203m", "\x1b[38;5;214m"], neutral: ["\x1b[38;5;74m", "\x1b[38;5;81m", "\x1b[38;5;117m", "\x1b[38;5;153m"] }; const shortcuts = { ">Downloads": { description: "User's downloads folder.", shortCut: ">Downloads" }, ">Documents": { description: "User's documents folder.", shortCut: ">Documents" }, ">Desktop": { description: "User's desktop folder.", shortCut: ">Desktop" }, ">AppData": { description: "User's roaming application data folder.", shortCut: ">AppData" }, ">LocalAppData": { description: "User's local application data folder.", shortCut: ">LocalAppData" }, ">Music": { description: "User's music folder.", shortCut: ">Music" }, ">Photos": { description: "User's photos folder.", shortCut: ">Photos" }, ">Videos": { description: "User's videos folder.", shortCut: ">Videos" }, ">Public": { description: "User's public folder.", shortCut: ">Public" }, ">Templates": { description: "User's templates folder", shortCut: ">Templates" }, ">Temp": { description: "System's temp folder.", shortCut: ">Temp" }, ">LogFiles": { description: "System's logs folder.", shortCut: ">LogFiles" }, ">SystemRoot": { description: "System's root folder.", shortCut: ">SystemRoot" }, ">Cache": { description: "User's application cache folder.", shortCut: ">Cache" }, ">Config": { description: "User's application config folder.", shortCut: ">Config" }, ">CurrentDirectory": { description: "User's current folder.", shortCut: ">CurrentDirectory" }, ">Home": { description: "System's home folder.", shortCut: ">Home" } }; const colorReset = "\x1b[0m"; var _FileTideClient_brand = /*#__PURE__*/new WeakSet(); class FileTideClient { constructor(inputDeviceName, inputTideURL, inputCurrentRoom, displayTitle = true, showCLITitle = false, debugMode = false) { // --- FileTide Client Cleanup Management --- _classPrivateMethodInitSpec(this, _FileTideClient_brand); fileTide = new FileTide(debugMode); this.currentDeviceName = inputDeviceName || deviceName; this.originDeviceName = inputDeviceName || deviceName; this.deviceName = inputDeviceName || deviceName; this.tideUrl = inputTideURL || tideUrl; this.currentRoom = inputCurrentRoom || currentRoom; this.fileMessagerInstance = fileMessagerInstance; this.clientDisconnected = false; this.shortcuts = shortcuts; this.connectionID = null; _assertClassBrand(_FileTideClient_brand, this, _setupProcessEvents).call(this); this.messagerSettings = { maxReconnectionAttempts: 15, reconnectionAttempts: 15, maxReconnectionDelay: 10000 }; this.transportOptions = { parallelChunks: 3, maxRetries: 3 }; this.connectionOptions = {}; this.clientOptions = {}; if (displayTitle) { this.displayTitle(showCLITitle); } return; } // --- FileTide Client TideToken Enforcement Management --- updateTideTokenEnforcementCallbackConfigurations(updatedConfigurations = {}) { fileTide.updateTideTokenEnforcementCallbackConfigurations(updatedConfigurations); } async registerTideToken(tideToken, meta = {}) { return await fileTide.registerTideToken(tideToken, meta); } async inspectTideToken(tideToken) { return await fileTide.inspectTideToken(tideToken); } getTideTokenEnforcerOverviewMetrics() { return fileTide.getTideTokenEnforcerOverviewMetrics(); } getTideToken(scope = "default") { return fileTide.getTideToken(scope); } broadcastClientOffline(fileMessager, forceBroadcast = false) { if (fileMessager && !this.clientDisconnected) { this.clientDisconnected = true; const transferStates = fileTide.getTidingTransferStates(); fileMessager.clientTide.emitEvent(this.deviceName, "client-offline", { clientID: this.deviceName, connectionID: this.connectionID, disconnectedDuringTransfer: transferStates.size > 0 ? true : false }); FileTide.outputGradient(`[${this.deviceName}] Disconnected from the file net.`, ["#00C897", "#00E0FF"]); return; } if (!fileMessager || !forceBroadcast) { return; } this.clientDisconnected = true; const transferStates = fileTide.getTidingTransferStates(); fileMessager.clientTide.emitEvent(this.deviceName, "client-offline", { clientID: this.deviceName, connectionID: this.connectionID, disconnectedDuringTransfer: transferStates.size > 0 ? true : false }); FileTide.outputGradient(`[${this.deviceName}] Disconnected from the file net.`, ["#00C897", "#00E0FF"]); } async closeAllClients(onBeforeClientDisconnect, onClientDisconnect, onCompletion) { await fileTide.stopAllMessagers(async (...data) => { this.broadcastClientOffline(this.fileMessagerInstance); if (typeof onBeforeClientDisconnect === "function") { await onBeforeClientDisconnect(...data); } }, onClientDisconnect, onCompletion); } async closeClient(userID, onBeforeDisconnect, onDisconnect, onCompletion) { await fileTide.stopMessager(userID, async (...data) => { this.broadcastClientOffline(this.fileMessagerInstance); if (typeof onBeforeDisconnect === "function") { await onBeforeDisconnect(...data); } }, onDisconnect, onCompletion); } // --- FileTide Client Client Management --- startClient(clientOptions = {}, connectionOptions = {}, transportOptions = { parallelChunks: 3, maxRetries: 3 }, messagerSettings = { maxReconnectionAttempts: 15, reconnectionAttempts: 15, maxReconnectionDelay: 10000 }, onConnect = null, onDisconnect = null, ...clientConfigurations) { const launchClient = () => { if (this.fileMessagerInstance && this.fileMessagerInstance.clientTide && this.fileMessagerInstance.clientTide.tideExists(this.deviceName)) { this.broadcastClientOffline(this.fileMessagerInstance); this.fileMessagerInstance.clientTide.closeSocket(this.deviceName); } fileTide.launchMessager({ serverUrl: this.tideUrl, ...clientOptions }, { maxHttpBufferSize: 5e9, pingTimeout: 3600000, pingInterval: 60000, ...connectionOptions }, transportOptions, messagerSettings, this.currentRoom, this.deviceName, (fileMessager, enterRoom) => { this.fileMessagerInstance = fileMessager; this.connectionID = null; fileMessager.clientTide.onEvent(this.deviceName, "connect", async () => { this.clientDisconnected = false; this.connectionID = fileMessager.clientTide.sockets[this.deviceName].id; FileTide.outputGradient(`[${this.deviceName}] Connected to FileTide ~ ${this.tideUrl} in ${this.currentRoom}!`, ["#00C897", "#00E0FF"]); fileMessager.clientTide.emitEvent(this.deviceName, "client-online", this.deviceName, fileMessager.clientTide.sockets[this.deviceName].tideID, this.pDeviceName, fileMessager.clientTide.sockets[this.deviceName].id, fileTide.transferBarrier, this.originDeviceName, this.currentRoom); const clientOnline = await fileMessager.clientTide.emitEventWithResponse(this.deviceName, "check-client-online", "retrieved-client-online", { clientID: this.deviceName }, 5000); if (clientOnline && clientOnline.online && clientOnline.client.id !== this.connectionID) { launchClient(); return; } enterRoom(); FileTide.outputGradient(`[${this.deviceName}] Getting connected clients...`, ["#00C897", "#00E0FF"]); if (onConnect) { onConnect(fileMessager); } }); fileMessager.clientTide.onEvent(this.deviceName, "disconnect", () => { if (this.fileMessagerInstance.clientTide.tideExists(this.deviceName)) { this.broadcastClientOffline(fileMessager); } if (onDisconnect) { onDisconnect(this.deviceName, this.connectionID, this.tideUrl); } }); }, ...clientConfigurations); }; this.connectionOptions = connectionOptions; this.transportOptions = transportOptions; this.messagerSettings = messagerSettings; this.clientOptions = clientOptions; launchClient(); } getOnlineClients(completion) { this.fileMessagerInstance.clientTide.emitEvent(this.deviceName, "clients-online", this.deviceName); if (completion) { completion(); } return; } refreshConnection(reconnectClient = true, onReconnect, onDisconnect, ...clientConfigurations) { if (!reconnectClient) { return; } this.startClient(this.clientOptions, this.connectionOptions, this.transportOptions, this.messagerSettings, onReconnect, onDisconnect, ...clientConfigurations); return; } // --- FileTide Client Transfer Management --- requestFileTransfer(senderID, filePath, destinationPath, filterContent = [], transferRequestExpirationTime = 30000) { FileTide.outputGradient(`[${this.deviceName}] Requesting ${path.basename(filePath)} from client ~ ${senderID}...`, ["#00C897", "#00E0FF"]); this.fileMessagerInstance.requestTransfer(this.deviceName, senderID, filePath, destinationPath, filterContent, transferRequestExpirationTime); return; } async transferFiles(recipientID, filePath, destinationPath, filterContent = [], tideSize = 200, tidalSize = 500, minTideSize = 10, maxTideSize = 2000, transferRequestExpirationTime = 30000, metadata = {}) { await fileTide.sendToDevice(recipientID, filePath, destinationPath, filterContent, tideSize, tidalSize, minTideSize, maxTideSize, transferRequestExpirationTime, metadata); return; } listFiles(recipientID, depth = 1) { fileTide.listFilesFromClient(recipientID, depth); return; } // --- FileTide Client Shore Policy Management --- clearShorePolicies(clientID, shores = []) { return fileTide.clearShorePolicies(clientID, shores); } addShorePolicies(clientID, shores = []) { return fileTide.addShorePolicies(clientID, shores); } getShorePolicies(clientID) { return fileTide.getShorePolicies(clientID); } addShortcuts(inputShortcuts) { for (const [key, value] of Object.entries(inputShortcuts)) { if (!shortcuts[key]) { this.shortcuts[key] = { description: value.description || "No description provided.", shortCut: key }; } } return shortcuts; } clearShortcuts(inputShortcuts) { for (const key of inputShortcuts) { if (shortcuts[key]) { delete this.shortcuts[key]; } } return shortcuts; } getShortcuts() { return shortcuts; } // --- FileTide Client Client Settings Management --- changeRoom(room, completion, reconnectClient = true, onReconnect, onDisconnect, ...clientConfigurations) { this.currentRoom = room; FileTide.outputGradient(`[${this.deviceName}] Updated room to ${this.currentRoom}`, ["#4D96FF", "#89CFF0"]); this.refreshConnection(reconnectClient, onReconnect, onDisconnect, ...clientConfigurations); if (completion) { completion(room, true); } return; } async changeClientID(clientID, completion, reconnectClient = true, onReconnect, onDisconnect, ...clientConfigurations) { const clientOnline = await this.fileMessagerInstance.clientTide.emitEventWithResponse(clientID, "check-client-online", "retrieved-client-online", { clientID }, 5000); let updatedClientID = false; if (clientOnline && clientOnline.online && clientOnline.client.id !== this.connectionID) { FileTide.outputGradient(`[${this.deviceName}] Client name taken ~ ${this.deviceName}`, ["#4D96FF", "#89CFF0"]); } else if (!clientOnline || !clientOnline.online || clientOnline.client.id === this.connectionID) { const pDeviceName = this.deviceName; this.currentDeviceName = pDeviceName; this.clientDisconnected = true; const transferStates = fileTide.getTidingTransferStates(); this.fileMessagerInstance.clientTide.emitEvent(pDeviceName, "client-offline", { clientID: pDeviceName, connectionID: this.connectionID, disconnectedDuringTransfer: transferStates.size > 0 ? true : false }); this.fileMessagerInstance.clientTide.closeSocket(this.deviceName); this.deviceName = clientID; FileTide.outputGradient(`[${pDeviceName}] Updated client name to ${this.deviceName}`, ["#4D96FF", "#89CFF0"]); this.refreshConnection(reconnectClient, onReconnect, onDisconnect, ...clientConfigurations); updatedClientID = true; } if (completion) { completion(clientID, updatedClientID); } return; } changeTideUrl(url, completion, reconnectClient = true, onReconnect, onDisconnect, ...clientConfigurations) { this.tideUrl = url; FileTide.outputGradient(`[${this.deviceName}] Updated tide URL to ${this.tideUrl}`, ["#4D96FF", "#89CFF0"]); this.refreshConnection(reconnectClient, onReconnect, onDisconnect, ...clientConfigurations); if (completion) { completion(url, true); } return; } // --- FileTide Client Display Management --- applyGradient(text, gradientType) { const colors = gradients[gradientType]; let gradientText = ""; if (text.length === 0) return colorReset + text; const totalSteps = Math.max(text.length - 1, 1); for (let i = 0; i < text.length; i++) { const progress = i / totalSteps; const colorIndex = Math.floor(progress * (colors.length - 1)); gradientText += colors[colorIndex] + text[i]; } return gradientText + colorReset; } displayMessage(type, message) { switch (type) { case "success": console.log(this.applyGradient(message, "success")); break; case "indicator": console.log(this.applyGradient(message, "indicator")); break; case "error": console.log(this.applyGradient(message, "error")); break; case "info": console.log(this.applyGradient(message, "info")); break; case "critical": console.log(this.applyGradient(message, "critical")); break; case "neutral": console.log(this.applyGradient(message, "neutral")); break; default: console.log(this.applyGradient(message, "neutral")); } } displayTitle(cli = false) { FileTide.displayFileTideLogo(); FileTide.displayFileTideTitle(cli); FileTide.displayFileTideAuthor(); } } function _setupProcessEvents() { process.on("exit", code => { FileTide.outputGradient(`Exited FileTide: ${code}`, ["#00C897", "#00E0FF"]); this.broadcastClientOffline(this.fileMessagerInstance); }); process.on("SIGINT", () => { FileTide.outputGradient("Exiting FileTide (Ctrl+C).", ["#00C897", "#00E0FF"]); process.exit(); }); process.on("uncaughtException", error => { FileTide.outputGradient(`Uncaught exception: ${error}`, ["#F94144", "#F3722C"]); process.exit(1); }); } ; module.exports = FileTideClient;