import { createWriteStream } from 'fs'; import * as path from 'path'; import { extname } from 'path'; import { FileEntry } from "ssh2-streams"; import * as vscode from 'vscode'; import { TreeItemCollapsibleState } from "vscode"; import { Command, NodeType } from '../common/constant'; import { ClientManager } from '../manager/clientManager'; import { FileManager, FileModel } from '../manager/fileManager'; import ServiceManager from '../manager/serviceManager'; import AbstractNode from "./abstracNode"; import ConnectionProvider from './connectionProvider'; import { SSHConfig } from "./sshConfig"; var progressStream = require('progress-stream'); const prettyBytes = require('pretty-bytes'); export class FileNode extends AbstractNode { contextValue = NodeType.FILE; fullPath: string; constructor(readonly sshConfig: SSHConfig, readonly file: FileEntry, readonly parentName: string) { super(file.filename, TreeItemCollapsibleState.None) this.description = prettyBytes(file.attrs.size) this.iconPath = this.getIcon(this.file.filename) this.fullPath = this.parentName + this.file.filename; this.command = { command: "ssh.file.open", arguments: [this], title: "Open File" } } public async getChildren(): Promise<AbstractNode[]> { return []; } delete(): any { vscode.window.showQuickPick(["YES", "NO"], { canPickMany: false }).then(async str => { if (str == "YES") { const { sftp } = await ClientManager.getSSH(this.sshConfig) sftp.unlink(this.fullPath, (err) => { if (err) { vscode.window.showErrorMessage(err.message) } else { vscode.commands.executeCommand(Command.REFRESH) } }) } }) } async open() { if (this.file.attrs.size > 10485760) { vscode.window.showErrorMessage("File size except 10 MB, not support open!") return; } const extName = path.extname(this.file.filename).toLowerCase(); if (extName == ".gz" || extName == ".exe" || extName == ".7z" || extName == ".jar" || extName == ".bin" || extName == ".tar") { vscode.window.showErrorMessage(`Not support open ${extName} file!`) return; } const { sftp } = await ClientManager.getSSH(this.sshConfig) const tempPath = await FileManager.record(`temp/${this.file.filename}`, null, FileModel.WRITE); sftp.fastGet(this.fullPath, tempPath, async (err) => { if (err) { vscode.window.showErrorMessage(err.message) } else { ConnectionProvider.tempRemoteMap.set(path.resolve(tempPath), { remote: this.fullPath, sshConfig: this.sshConfig }) vscode.commands.executeCommand('vscode.open', vscode.Uri.file(tempPath)) } }) } download(): any { const extName = extname(this.file.filename)?.replace(".", ""); vscode.window.showSaveDialog({ defaultUri: vscode.Uri.file(this.file.filename), filters: { "Type": [extName] }, saveLabel: "Select Download Path" }) .then(async uri => { if (uri) { const { sftp } = await ClientManager.getSSH(this.sshConfig) vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, title: `Start downloading ${this.fullPath}`, cancellable:true }, (progress, token) => { return new Promise((resolve) => { const fileReadStream = sftp.createReadStream(this.fullPath) var str = progressStream({ length: this.file.attrs.size, time: 100 }); let before=0; str.on("progress", (progressData: any) => { if (progressData.percentage == 100) { resolve(null) vscode.window.showInformationMessage(`Download ${this.fullPath} success, cost time: ${progressData.runtime}s`) return; } progress.report({ increment: progressData.percentage-before,message:`remaining : ${prettyBytes(progressData.remaining)}` }); before=progressData.percentage }) str.on("error",err=>{ vscode.window.showErrorMessage(err.message) }) const outStream = createWriteStream(uri.fsPath); fileReadStream.pipe(str).pipe(outStream); token.onCancellationRequested(() => { fileReadStream.destroy() outStream.destroy() }); }) }) } }) } getIcon(fileName: string): string { const extPath = ServiceManager.context.extensionPath; const ext = path.extname(fileName).replace(".", "").toLowerCase() let fileIcon; switch (ext) { case 'pub': case 'pem': fileIcon = "key.svg"; break; case 'ts': fileIcon = "typescript.svg"; break; case 'log': fileIcon = "log.svg"; break; case 'sql': fileIcon = "sql.svg"; break; case 'xml': fileIcon = "xml.svg"; break; case 'html': fileIcon = "html.svg"; break; case 'java': case 'class': fileIcon = "java.svg"; break; case 'js': case 'map': fileIcon = "javascript.svg"; break; case 'yml': case 'yaml': fileIcon = "yaml.svg"; break; case 'json': fileIcon = "json.svg"; break; case 'sh': fileIcon = "console.svg"; break; case 'cfg': case 'conf': fileIcon = "settings.svg"; break; case 'rar': case 'zip': case '7z': case 'gz': case 'tar': fileIcon = "zip.svg"; break; default: fileIcon = "file.svg"; break; } return `${extPath}/resources/image/icon/${fileIcon}` } }