UNPKG

universal-file-client

Version:

Universal file transfer client with unified interface for FTP, SFTP, and HTTP protocols

234 lines 8.54 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.UniversalFileClient = void 0; const ftp_adapter_1 = require("./adapters/ftp-adapter"); const sftp_adapter_1 = require("./adapters/sftp-adapter"); const http_adapter_1 = require("./adapters/http-adapter"); const protocol_detector_1 = require("./utils/protocol-detector"); const file_matcher_1 = require("./utils/file-matcher"); const path = __importStar(require("path")); class UniversalFileClient { constructor() { this.adapter = null; this.protocol = null; this.connectionConfig = null; } async connect(config) { if (!config.host) { throw new Error('Host is required for connection'); } const protocol = protocol_detector_1.ProtocolDetector.detect(config.host); this.protocol = protocol; this.connectionConfig = config; // Create appropriate adapter switch (protocol) { case 'ftp': case 'ftps': this.adapter = new ftp_adapter_1.FtpAdapter(); break; case 'sftp': this.adapter = new sftp_adapter_1.SftpAdapter(); break; case 'http': case 'https': this.adapter = new http_adapter_1.HttpAdapter(); break; default: throw new Error(`Unsupported protocol: ${protocol}`); } await this.adapter.connect(config); } async disconnect() { if (this.adapter) { await this.adapter.disconnect(); this.adapter = null; this.protocol = null; this.connectionConfig = null; } } async list(pathArg = '.', options = {}) { if (!this.adapter) { throw new Error('Not connected to any server'); } try { const files = await this.adapter.list(pathArg); if (!options.includeDirectories) { return files.filter(file => !file.isDirectory); } return files; } catch (error) { throw new Error(`Failed to list directory: ${error.message}`); } } async download(remotePath, options = {}) { if (!this.adapter) { throw new Error('Not connected to any server'); } const retries = options.retries || 3; const retryDelay = options.retryDelay || 1000; for (let attempt = 0; attempt <= retries; attempt++) { try { return await this.adapter.download(remotePath); } catch (error) { if (attempt === retries) { throw error; } await this.sleep(retryDelay * Math.pow(2, attempt)); } } throw new Error('Download failed after all retries'); } async upload(localPath, remotePath) { if (!this.adapter) { throw new Error('Not connected to any server'); } if (!localPath || !remotePath) { throw new Error('Both local and remote paths are required for upload'); } try { return await this.adapter.upload(localPath, remotePath); } catch (error) { throw new Error(`Failed to upload file: ${error.message}`); } } async stat(filePath) { if (!this.adapter) { throw new Error('Not connected to any server'); } if (!filePath) { throw new Error('File path is required for stat operation'); } try { return await this.adapter.stat(filePath); } catch (error) { throw new Error(`Failed to get file stats: ${error.message}`); } } async exists(filePath) { if (!this.adapter) { throw new Error('Not connected to any server'); } if (!filePath) { throw new Error('File path is required for exists check'); } try { return await this.adapter.exists(filePath); } catch (error) { // Return false for exists check instead of throwing return false; } } async lastModified(filePath) { if (!this.adapter) { throw new Error('Not connected to any server'); } return this.adapter.lastModified(filePath); } async findFile(targetPath, fileNameType = 'smart') { if (!this.adapter) { throw new Error('Not connected to any server'); } const dirPath = path.dirname(targetPath); const parsedPath = path.parse(targetPath); const { name: basename, ext: extname } = parsedPath; try { // First try exact path const exactFile = await this.stat(targetPath); if (exactFile) { return { file: exactFile, actualPath: targetPath }; } // List directory and find matching files const files = await this.list(dirPath); const matchOptions = { basename, filepath: targetPath, extname, }; const matchedFile = file_matcher_1.FileMatcher.findBestMatch(files, matchOptions, fileNameType); if (matchedFile) { const actualPath = path.join(dirPath, matchedFile.name); return { file: matchedFile, actualPath }; } return null; } catch (error) { throw new Error(`Failed to find file: ${error.message}`); } } async checkForUpdates(filePath, lastKnownDate, fileNameType = 'smart') { const result = await this.findFile(filePath, fileNameType); if (!result) { return { hasUpdate: false }; } const { file, actualPath } = result; // For HTTP/JSON files, always consider as updated (API exception) if (this.protocol === 'http' || this.protocol === 'https') { const httpAdapter = this.adapter; const fileInfo = await httpAdapter.getFileInfo(actualPath); if (fileInfo.isJson) { return { hasUpdate: true, file, actualPath }; } // For non-JSON HTTP files, check last modified if (!fileInfo.lastModified) { return { hasUpdate: false, file, actualPath }; } const hasUpdate = fileInfo.lastModified.getTime() > lastKnownDate.getTime(); return { hasUpdate, file, actualPath }; } // For FTP/SFTP, check modification time const hasUpdate = file.date.getTime() > lastKnownDate.getTime(); return { hasUpdate, file, actualPath }; } getProtocol() { return this.protocol; } getConnectionConfig() { return this.connectionConfig; } isConnected() { return this.adapter !== null; } sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } exports.UniversalFileClient = UniversalFileClient; //# sourceMappingURL=universal-ftp-client.js.map