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 , readonly file , readonly parentName ) { 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 ( ) { return [ ] ; } delete ( ) { 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 ( ) { 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 ) => { 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 ) { 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 }` ; } }