1 |
|
2 |
|
3 |
|
4 | const SSH2 = require('ssh2').Client,
|
5 | EventEmitter = require('events').EventEmitter,
|
6 | T = require('../tools');
|
7 |
|
8 | class Downloader extends EventEmitter {
|
9 | constructor(fromPath, toPath, auths, filters) {
|
10 | super();
|
11 |
|
12 | this.fromPath = fromPath;
|
13 | this.toPath = toPath;
|
14 | this.auths = auths;
|
15 | this.ssh2 = null;
|
16 | this.sftp = null;
|
17 | this.filters = filters || [];
|
18 | this.count = 0;
|
19 | }
|
20 |
|
21 | start() {
|
22 | this.initSSH();
|
23 | }
|
24 |
|
25 | initSSH() {
|
26 | if (!this.ssh2) {
|
27 | this.ssh2 = new SSH2();
|
28 | }
|
29 | let message;
|
30 | if (this.auths.password) {
|
31 | message = `→ [${this.auths.host}] Authenticating with password.`;
|
32 | } else if (this.auths.key) {
|
33 | message = `→ [${this.auths.host}] Authenticating with private key.`;
|
34 | }
|
35 |
|
36 | this.emit('start', {
|
37 | message,
|
38 | backup: this
|
39 | });
|
40 | this.ssh2.on('ready', this._onReady.bind(this));
|
41 | this.ssh2.connect(this.auths);
|
42 | }
|
43 |
|
44 | download() {
|
45 |
|
46 | this.ssh2.sftp((err, sftp) => {
|
47 | if (err) throw err;
|
48 | this.sftp = sftp;
|
49 | this.emit('before_download', {
|
50 | message: '→ Download start ...... ',
|
51 | backup: this
|
52 | });
|
53 | this._readdir(this.fromPath, null, sftp);
|
54 | });
|
55 | }
|
56 |
|
57 | |
58 |
|
59 |
|
60 |
|
61 |
|
62 | _readdir(dir, out) {
|
63 | this.count++;
|
64 | this.sftp.readdir(dir, (err, list) => {
|
65 | if (err) {
|
66 | if (err.message !== 'No such file') {
|
67 | this._error(err.message, 500, dir);
|
68 | } else {
|
69 | this._error(`⚠ No such '${dir}'`, 404, dir);
|
70 | }
|
71 | return false;
|
72 | }
|
73 |
|
74 | if (list && list.length > 0) {
|
75 | for (let i = 0; i < list.length; ++i) {
|
76 | const item = list[i];
|
77 | const input = T.Path.posix.join(dir, item.filename);
|
78 | const output = T.Path.resolve(out || this.toPath, item.filename);
|
79 | const stat = item.attrs;
|
80 |
|
81 | if (this.filters.indexOf(input) > -1) continue;
|
82 |
|
83 | if (stat.isDirectory()) {
|
84 |
|
85 | !T.fs.existsSync(output) && T.fs.mkdirSync(output);
|
86 |
|
87 | this._readdir(input, output);
|
88 | } else if (stat.isFile(input)) {
|
89 | this._getFile(input, output, stat);
|
90 | }
|
91 | }
|
92 | } else {
|
93 | this._error(`⚠ '${dir}' is empty directory`, 400, dir);
|
94 | }
|
95 | this.count--;
|
96 | });
|
97 | }
|
98 |
|
99 | |
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 | _getFile(input, output, stat) {
|
106 | this.count++;
|
107 | let readStream = this.sftp.createReadStream(input, {
|
108 | flags: 'r',
|
109 | encoding: null,
|
110 | handle: null,
|
111 | mode: 0o666,
|
112 | autoClose: true
|
113 | });
|
114 | let writeStream = T.fs.createWriteStream(output);
|
115 | readStream.pipe(writeStream).on('finish', () => {
|
116 | const message = `√ [${T.getTime()}] download to '${output}', after ${T.msg.yellow(stat.size / 1000 + ' kb')}`;
|
117 | this.emit('file_downloaded', {
|
118 | output,
|
119 | size: stat.size,
|
120 | message
|
121 | });
|
122 | this._finishEnd(--this.count);
|
123 | });
|
124 | readStream.on('err', err => {
|
125 | T.log.error(err.message);
|
126 | });
|
127 | }
|
128 |
|
129 |
|
130 | _finishEnd(count) {
|
131 | count === 0 && this._done('√ Download finish');
|
132 | }
|
133 |
|
134 | _done(message, state, directory) {
|
135 | this.emit('done', {
|
136 | message: message,
|
137 | state: state || 200,
|
138 | directory,
|
139 | backup: this
|
140 | });
|
141 | }
|
142 |
|
143 | _error(message, state, directory) {
|
144 | this.emit('error', {
|
145 | message,
|
146 | state,
|
147 | directory,
|
148 | backup: this
|
149 | });
|
150 | directory === this.fromPath && this._done(message, state, directory);
|
151 | }
|
152 |
|
153 | _onReady() {
|
154 | this.download();
|
155 | }
|
156 | }
|
157 |
|
158 | module.exports = Downloader; |
\ | No newline at end of file |