folder-upload-webpack-plugin
Version:
Upload your folder to ssh sftp server after build, add support to 'webpack --watch'
142 lines (121 loc) • 4.23 kB
text/typescript
import * as console from "console";
import {Client as Ssh2Client, ConnectConfig, Client} from "ssh2";
import SftpClient from "ssh2-sftp-client";
import chalk, {Chalk} from "chalk";
import path from "path";
import ProgressBar from "./ProgressBar";
import {clearTimeout} from "timers";
const fs = require('fs')
const promiseRepeat = function(promise: () => Promise<any>, ms = 3000, attempt = 0) {
return new Promise((resolve, reject) => {
promiseTimeout(promise, ms).then(result => {
resolve(result);
}).catch(async (err) => {
attempt++;
if(attempt < 3) return await promiseRepeat(promise, ms, attempt);
reject(err);
});
})
}
const promiseTimeout = function(promise: () => Promise<any>, ms = 3000){
let timeout = new Promise((resolve, reject) => {
let id = setTimeout(() => {
clearTimeout(id);
reject('Timed out in '+ ms + 'ms.')
}, ms)
})
return Promise.race([
promise,
timeout
])
}
export default class SshClient {
private readonly logging: boolean|undefined;
private progress: boolean;
private options: ConnectConfig;
private sftp: SftpClient;
private streams: number = 10;
constructor(log:boolean|undefined = false, progress = true, streams = 10) {
this.logging = log;
this.progress = progress;
this.streams = streams
}
async connect(options: ConnectConfig = {}) {
this.options = options;
this.sftp = new SftpClient();
await this.sftp.connect({...this.options});
}
async ssh2connect(config: ConnectConfig): Promise<Client> {
return await new Promise((resolve, reject) => {
let conn = new Ssh2Client();
conn.on('ready', () => resolve(conn)).on('error', reject).connect(config)
return conn;
})
}
async exists(remotePath:string) {
let exits = await this.sftp.exists(remotePath);
return !!exits;
}
async mkdir(remotePath:string, recursive?: boolean) {
return await this.sftp.mkdir(remotePath, recursive);
}
async rmdir(remotePath:string) {
return await this.sftp.rmdir(remotePath);
}
async sendFile(files: Array<{ remotePath:string,name:string,fillPath:string }>) {
let self = this;
let uploaded = 0;
const pb = new ProgressBar('Sending...', 20);
if (files.length > 0) {
let sliced_array: Array<Array<{ remotePath:string,name:string,fillPath:string }>> = [];
let i = 0;
files.map((item) => {
if(!sliced_array[i]) sliced_array[i] = []
sliced_array[i].push(item);
if(sliced_array[i].length > this.streams) i++;
});
for (let i in sliced_array) {
await Promise.all(sliced_array[i].map(file => {
if (!fs.existsSync(file.fillPath)) {
throw new Error(`File: ${file.fillPath} not exist!`)
}
let remoteFile = path.resolve(file.remotePath + file.name);
this.log('Put: ' + file.fillPath + ' to server ' + remoteFile, chalk.yellow);
return this.sftp.fastPut(file.fillPath, remoteFile, {mode: 0o777}).then(result => {
uploaded++;
self.progress && pb.render({
percent: parseFloat((uploaded / files.length).toFixed(4)),
completed: uploaded,
total: files.length,
})
}).catch(err => {
this.log(err, chalk.red.bold)
return async function retry() {
return await self.sftp.fastPut(file.fillPath, remoteFile, {mode: 0o777});
}();
});
})).catch(err => {
this.log(err, chalk.red.bold)
});
}
}
}
async symlink(remotePath: string) {
return await this.sftp.mkdir(remotePath, true);
}
async delete(path: string) {
return await this.sftp.delete(path);
}
async chmod(path: string, chmod: number|string) {
return await this.sftp.chmod(path, chmod);
}
async end() {
await this.sftp.end();
}
log(text: string, formatter:Chalk = chalk) {
if(!this.logging) {
return;
}
console.log(formatter(text));
}
}