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