w-ftp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/.editorconfig +9 -0
  2. package/.eslintignore +3 -0
  3. package/.eslintrc.js +54 -0
  4. package/.jsdoc +25 -0
  5. package/LICENSE +21 -0
  6. package/README.md +163 -0
  7. package/SECURITY.md +5 -0
  8. package/babel.config.js +14 -0
  9. package/docs/WFtp.mjs.html +665 -0
  10. package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  11. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  12. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  13. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  14. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  15. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  16. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  17. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  18. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  19. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  20. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  21. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  22. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  23. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  24. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  25. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  26. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  27. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  28. package/docs/global.html +439 -0
  29. package/docs/index.html +81 -0
  30. package/docs/jsftp.js.html +925 -0
  31. package/docs/scripts/collapse.js +20 -0
  32. package/docs/scripts/linenumber.js +25 -0
  33. package/docs/scripts/nav.js +12 -0
  34. package/docs/scripts/polyfill.js +4 -0
  35. package/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  36. package/docs/scripts/prettify/lang-css.js +2 -0
  37. package/docs/scripts/prettify/prettify.js +28 -0
  38. package/docs/scripts/search.js +83 -0
  39. package/docs/styles/jsdoc.css +765 -0
  40. package/docs/styles/prettify.css +79 -0
  41. package/g-download.mjs +84 -0
  42. package/g-upload.mjs +65 -0
  43. package/package.json +30 -0
  44. package/src/WFtp.mjs +596 -0
  45. package/src/jsftp.js +856 -0
  46. package/test/all.test.mjs +10 -0
  47. package/toolg/addVersion.mjs +4 -0
  48. package/toolg/cleanFolder.mjs +4 -0
  49. package/toolg/gDistRollup.mjs +27 -0
  50. package/toolg/modifyReadme.mjs +4 -0
package/src/WFtp.mjs ADDED
@@ -0,0 +1,596 @@
1
+ import path from 'path'
2
+ import fs from 'fs'
3
+ import get from 'lodash/get'
4
+ import size from 'lodash/size'
5
+ import filter from 'lodash/filter'
6
+ import find from 'lodash/find'
7
+ import map from 'lodash/map'
8
+ import genPm from 'wsemi/src/genPm.mjs'
9
+ import cint from 'wsemi/src/cint.mjs'
10
+ import cstr from 'wsemi/src/cstr.mjs'
11
+ import ispint from 'wsemi/src/ispint.mjs'
12
+ import isestr from 'wsemi/src/isestr.mjs'
13
+ import iseobj from 'wsemi/src/iseobj.mjs'
14
+ import isfun from 'wsemi/src/isfun.mjs'
15
+ import isnum from 'wsemi/src/isnum.mjs'
16
+ import strleft from 'wsemi/src/strleft.mjs'
17
+ import pmSeries from 'wsemi/src/pmSeries.mjs'
18
+ import getFileName from 'wsemi/src/getFileName.mjs'
19
+ import fsTreeFolder from 'wsemi/src/fsTreeFolder.mjs'
20
+ import fsIsFolder from 'wsemi/src/fsIsFolder.mjs'
21
+ import fsIsFile from 'wsemi/src/fsIsFile.mjs'
22
+ import fsCreateFolder from 'wsemi/src/fsCreateFolder.mjs'
23
+ // import Jsftp from 'jsftp'
24
+ import Jsftp from './jsftp.js'
25
+ console.log('Jsftp', Jsftp)
26
+
27
+
28
+ /**
29
+ * 指定FTP伺服器資料夾內檔案並自動同步至本機,只能用於Windows作業系統
30
+ *
31
+ * @param {String} fp 輸入檔案路徑字串
32
+ * @param {Object} [opt={}] 輸入設定物件,預設{}
33
+ * @param {String} [opt.ver='4.8'] 輸入調用windows程序之Net Framework版本字串,可有'4.5'、'4.6'、'4.7.2'與'4.8',預設'4.8'
34
+ * @returns {Promise} 回傳Promise,resolve回傳成功訊息,reject回傳錯誤訊息
35
+ * @example
36
+ * import WFtp from './src/WFtp.mjs'
37
+ *
38
+ * async function test() {
39
+ *
40
+ * //fp
41
+ * let fp = './g.mseed'
42
+ *
43
+ * //WFtp
44
+ * let r = await WFtp(fp)
45
+ * console.log(r)
46
+ * // [
47
+ * // {
48
+ * // name: 'SE.RST01.00.HNE.D.2020-09-17T013552.000000.csv',
49
+ * // path: null,
50
+ * // data: { heads: [Object], records: [Array] }
51
+ * // },
52
+ * // {
53
+ * // name: 'SE.RST01.00.HNN.D.2020-09-17T013552.000000.csv',
54
+ * // path: null,
55
+ * // data: { heads: [Object], records: [Array] }
56
+ * // },
57
+ * // {
58
+ * // name: 'SE.RST01.00.HNZ.D.2020-09-17T013552.000000.csv',
59
+ * // path: null,
60
+ * // data: { heads: [Object], records: [Array] }
61
+ * // }
62
+ * // ]
63
+ *
64
+ * }
65
+ * test()
66
+ * .catch((err) => {
67
+ * console.log('catch', err)
68
+ * })
69
+ *
70
+ */
71
+ function WFtp() {
72
+
73
+ function WFtpCore() {
74
+ let Ftp = null
75
+
76
+
77
+ async function ftpConn(opt = {}) {
78
+
79
+ //pm
80
+ let pm = genPm()
81
+
82
+ //hostname
83
+ let hostname = get(opt, 'hostname')
84
+ if (!isestr(hostname)) {
85
+ pm.reject(`hostname[${hostname}] is not a effective string`)
86
+ return pm
87
+ }
88
+
89
+ //port
90
+ let port = get(opt, 'port')
91
+ if (!ispint(port)) {
92
+ pm.reject(`port[${port}] is not a positive integer`)
93
+ return pm
94
+ }
95
+ port = cint(port)
96
+
97
+ //username
98
+ let username = get(opt, 'username')
99
+ if (!isestr(username)) {
100
+ pm.reject(`username[${username}] is not a effective string`)
101
+ return pm
102
+ }
103
+
104
+ //password
105
+ let password = get(opt, 'password')
106
+ if (!isestr(password)) {
107
+ pm.reject(`password[${password}] is not a effective string`)
108
+ return pm
109
+ }
110
+
111
+ try {
112
+ Ftp = new Jsftp({
113
+ host: hostname,
114
+ port, // defaults to 21
115
+ user: username, // defaults to "anonymous"
116
+ pass: password, // defaults to "@anonymous"
117
+ })
118
+ pm.resolve('ok')
119
+ }
120
+ catch (err) {
121
+ pm.reject(err)
122
+ }
123
+
124
+ return pm
125
+ }
126
+
127
+
128
+ async function ftpLs(remoteFd = '.') {
129
+
130
+ //pm
131
+ let pm = genPm()
132
+
133
+ //check
134
+ if (Ftp === null) {
135
+ pm.reject(`FTP has not been initialized. please use 'conn' to construct FTP`)
136
+ return pm
137
+ }
138
+
139
+ Ftp.ls(remoteFd, (err, res) => {
140
+ if (err) {
141
+ pm.reject(err)
142
+ }
143
+ else {
144
+ pm.resolve(res)
145
+ }
146
+ })
147
+
148
+ return pm
149
+ }
150
+
151
+
152
+ async function ftpQuit() {
153
+
154
+ //pm
155
+ let pm = genPm()
156
+
157
+ //check
158
+ if (Ftp === null) {
159
+ pm.reject(`FTP has not been initialized. please use 'conn' to construct FTP`)
160
+ return pm
161
+ }
162
+
163
+ Ftp.raw('quit', (err, res) => {
164
+ if (err) {
165
+ pm.reject(err)
166
+ }
167
+ else {
168
+ pm.resolve(res)
169
+ }
170
+ })
171
+
172
+ return pm
173
+ }
174
+
175
+
176
+ async function ftpStateFile(fpRemote) {
177
+
178
+ //ftpLs
179
+ let file = null
180
+ await ftpLs(fpRemote)
181
+ .then((res) => {
182
+ file = res
183
+ })
184
+ .catch(() => {
185
+ file = null
186
+ })
187
+
188
+ //get
189
+ file = get(file, 0, null)
190
+ // console.log('file', file)
191
+
192
+ return file
193
+ }
194
+
195
+
196
+ async function ftpCheckFile(fpRemote) {
197
+
198
+ //ftpStateFile
199
+ let file = await ftpStateFile(fpRemote)
200
+
201
+ //b
202
+ let b = iseobj(file)
203
+
204
+ return b
205
+ }
206
+
207
+
208
+ async function ftpDownload(fpRemote, fpLocal, cbProcess) {
209
+
210
+ //pm
211
+ let pm = genPm()
212
+
213
+ //check
214
+ if (Ftp === null) {
215
+ pm.reject(`FTP has not been initialized. please use 'conn' to construct FTP`)
216
+ return pm
217
+ }
218
+
219
+ //fpRemote
220
+ if (!isestr(fpRemote)) {
221
+ pm.reject(`fpRemote[${fpRemote}] is not a effective string`)
222
+ return pm
223
+ }
224
+
225
+ //fpLocal
226
+ if (!isestr(fpLocal)) {
227
+ pm.reject(`fpLocal[${fpLocal}] is not a effective string`)
228
+ return pm
229
+ }
230
+
231
+ //fdLocal
232
+ let fdLocal = path.basename(path.dirname(fpLocal))
233
+
234
+ //check fdLocal
235
+ if (!fsIsFolder(fdLocal)) {
236
+ fsCreateFolder(fdLocal)
237
+ }
238
+
239
+ //ftpStateFile
240
+ let file = await ftpStateFile(fpRemote)
241
+ // console.log('file', file)
242
+
243
+ //fileSize
244
+ let fileSize = get(file, 'size')
245
+
246
+ //check
247
+ if (!isnum(fileSize)) {
248
+ pm.reject(`can not get the size of file[${fpRemote}]`)
249
+ return pm
250
+ }
251
+ fileSize = cint(fileSize)
252
+ // console.log('fileSize', fileSize)
253
+
254
+ Ftp.get(fpRemote, (err, socket) => {
255
+
256
+ //check
257
+ if (err) {
258
+ pm.reject(err)
259
+ }
260
+
261
+ //check
262
+ if (fsIsFile(fpLocal)) {
263
+ fs.unlinkSync(fpLocal)
264
+ }
265
+
266
+ //createWriteStream
267
+ let writer = fs.createWriteStream(fpLocal)
268
+
269
+ //on data
270
+ let dss = 0
271
+ socket.on('data', (d) => {
272
+ // console.log('socket.on data', d)
273
+
274
+ //cbProcess
275
+ if (isfun(cbProcess)) {
276
+ let ds = size(d)
277
+ dss += ds
278
+ let r = dss / fileSize * 100
279
+ // console.log(`receving... ${dig((r), 1)}%`)
280
+ cbProcess({
281
+ progress: r,
282
+ name: getFileName(fpLocal),
283
+ fpRemote,
284
+ fpLocal,
285
+ })
286
+ }
287
+
288
+ //write
289
+ writer.write(d)
290
+
291
+ })
292
+
293
+ //on close
294
+ socket.on('close', (err) => {
295
+ if (err) {
296
+ pm.reject(err)
297
+ }
298
+ else {
299
+ pm.resolve('ok')
300
+ }
301
+ })
302
+
303
+ //resume
304
+ socket.resume()
305
+
306
+ })
307
+
308
+ return pm
309
+ }
310
+
311
+
312
+ async function ftpUpload(fpLocal, fpRemote, cbProcess) {
313
+
314
+ //pm
315
+ let pm = genPm()
316
+
317
+ //check
318
+ if (Ftp === null) {
319
+ pm.reject(`FTP has not been initialized. please use 'conn' to construct FTP`)
320
+ return pm
321
+ }
322
+
323
+ //fpRemote
324
+ if (!isestr(fpRemote)) {
325
+ pm.reject(`fpRemote[${fpRemote}] is not a effective string`)
326
+ return pm
327
+ }
328
+
329
+ //fpLocal
330
+ if (!isestr(fpLocal)) {
331
+ pm.reject(`fpLocal[${fpLocal}] is not a effective string`)
332
+ return pm
333
+ }
334
+
335
+ //check
336
+ if (!fsIsFile(fpLocal)) {
337
+ pm.reject(`fpLocal[${fpLocal}] is not a file`)
338
+ return pm
339
+ }
340
+
341
+ //statSync
342
+ let stat = fs.statSync(fpLocal)
343
+
344
+ //fileSize
345
+ let fileSize = get(stat, 'size')
346
+
347
+ //check
348
+ if (!isnum(fileSize)) {
349
+ pm.reject(`can not get the size of file[${fpLocal}]`)
350
+ return pm
351
+ }
352
+ fileSize = cint(fileSize)
353
+ // console.log('fileSize', fileSize)
354
+
355
+ //bufferLocal
356
+ let bufferLocal = fs.readFileSync(fpLocal)
357
+
358
+ // //createReadStream
359
+ // let reader = fs.createReadStream(fpLocal)
360
+
361
+ let dss = 0
362
+ Ftp.put(bufferLocal, fpRemote, (err, buffer) => {
363
+ // console.log('Ftp.put', err, buffer)
364
+
365
+ //check
366
+ if (err) {
367
+ pm.reject(err)
368
+ return
369
+ }
370
+
371
+ //check
372
+ if (size(buffer) === 0) {
373
+ pm.resolve('ok')
374
+ return
375
+ }
376
+
377
+ //cbProcess
378
+ if (isfun(cbProcess)) {
379
+ let ds = size(buffer)
380
+ dss += ds
381
+ let r = dss / fileSize * 100
382
+ // console.log(`receving... ${dig((r), 1)}%`)
383
+ cbProcess({
384
+ progress: r,
385
+ name: getFileName(fpLocal),
386
+ fpRemote,
387
+ fpLocal,
388
+ })
389
+ }
390
+
391
+ })
392
+
393
+ return pm
394
+ }
395
+
396
+
397
+ async function ftpSyncToLocal(fdRemote, fdLocal, cbProcess) {
398
+
399
+ //check
400
+ if (Ftp === null) {
401
+ return Promise.reject(`FTP has not been initialized. please use 'conn' to construct FTP`)
402
+ }
403
+
404
+ //ftpLs
405
+ let fsRemote = await ftpLs(fdRemote)
406
+ // fsRemote = map(fsRemote, (v) => {
407
+ // let d = dayjs(v.time)
408
+ // v.stat = d.format('YYYY-MM-DDTHH:mm:ss')
409
+ // return v
410
+ // })
411
+ // console.log('fsRemote', fsRemote)
412
+
413
+ //check fdLocal
414
+ if (!fsIsFolder(fdLocal)) {
415
+ fsCreateFolder(fdLocal)
416
+ }
417
+
418
+ //fsTreeFolder
419
+ let fsLocal = fsTreeFolder(fdLocal)
420
+ fsLocal = filter(fsLocal, (v) => {
421
+ return !v.isFolder
422
+ })
423
+ fsLocal = map(fsLocal, (v) => {
424
+ let stat = fs.statSync(v.path)
425
+ v.size = cstr(get(stat, 'size', ''))
426
+ return v
427
+ })
428
+ // console.log('fsLocal', fsLocal)
429
+
430
+ //pmSeries
431
+ let n = 0
432
+ let ss = []
433
+ await pmSeries(fsRemote, async (fileRemote) => {
434
+
435
+ //fileLocal
436
+ let fileLocal = find(fsLocal, { name: fileRemote.name })
437
+ // console.log('fileLocal', fileLocal)
438
+
439
+ //fpRemote
440
+ // let fpRemote = path.resolve(fdRemote, v.name)
441
+ let fpRemote = fdRemote
442
+ if (!strleft(fpRemote, 1) !== '/') {
443
+ fpRemote += '/'
444
+ }
445
+ fpRemote += get(fileRemote, 'name', '')
446
+ // console.log('fpRemote', fpRemote)
447
+
448
+ //fpLocal
449
+ let fpLocal = path.resolve(fdLocal, get(fileRemote, 'name', ''))
450
+ // console.log('fpLocal', fpLocal)
451
+
452
+ //cb
453
+ let cb = (msg) => {
454
+ if (isfun(cbProcess)) {
455
+ cbProcess(msg)
456
+ }
457
+ }
458
+
459
+ //ftpDownload
460
+ if (!iseobj(fileLocal)) {
461
+ //本地檔案不存在
462
+ await ftpDownload(fpRemote, fpLocal, cb)
463
+ n++
464
+ ss.push({
465
+ name: fileRemote.name,
466
+ reason: 'no local file',
467
+ })
468
+ }
469
+ else if (fileRemote.size !== fileLocal.size) {
470
+ //本地檔案大小與遠端檔案大小不同
471
+ await ftpDownload(fpRemote, fpLocal, cb)
472
+ n++
473
+ ss.push({
474
+ name: fileRemote.name,
475
+ reason: `size[${fileLocal.size}] of local file != size[${fileRemote.size}] of remote file`,
476
+ })
477
+ }
478
+
479
+ })
480
+
481
+ return {
482
+ num: n,
483
+ files: ss,
484
+ }
485
+ }
486
+
487
+
488
+ async function ftpSyncToRemote(fdLocal, fdRemote, cbProcess) {
489
+
490
+ //check
491
+ if (Ftp === null) {
492
+ return Promise.reject(`FTP has not been initialized. please use 'conn' to construct FTP`)
493
+ }
494
+
495
+ //ftpLs
496
+ let fsRemote = await ftpLs(fdRemote)
497
+ // fsRemote = map(fsRemote, (v) => {
498
+ // let d = dayjs(v.time)
499
+ // v.stat = d.format('YYYY-MM-DDTHH:mm:ss')
500
+ // return v
501
+ // })
502
+ // console.log('fsRemote', fsRemote)
503
+
504
+ //check fdLocal
505
+ if (!fsIsFolder(fdLocal)) {
506
+ return Promise.reject(`fdLocal[${fdLocal}] is not a folder`)
507
+ }
508
+
509
+ //fsTreeFolder
510
+ let fsLocal = fsTreeFolder(fdLocal)
511
+ fsLocal = filter(fsLocal, (v) => {
512
+ return !v.isFolder
513
+ })
514
+ fsLocal = map(fsLocal, (v) => {
515
+ let stat = fs.statSync(v.path)
516
+ v.size = cstr(get(stat, 'size', ''))
517
+ return v
518
+ })
519
+ // console.log('fsLocal', fsLocal)
520
+
521
+ //pmSeries
522
+ let n = 0
523
+ let ss = []
524
+ await pmSeries(fsLocal, async (fileLocal) => {
525
+
526
+ //fileRemote
527
+ let fileRemote = find(fsRemote, { name: fileLocal.name })
528
+ // console.log('fileRemote', fileRemote)
529
+
530
+ //fpRemote
531
+ // let fpRemote = path.resolve(fdRemote, v.name)
532
+ let fpRemote = fdRemote
533
+ if (!strleft(fpRemote, 1) !== '/') {
534
+ fpRemote += '/'
535
+ }
536
+ fpRemote += get(fileLocal, 'name', '')
537
+ // console.log('fpRemote', fpRemote)
538
+
539
+ //fpLocal
540
+ let fpLocal = path.resolve(fdLocal, get(fileLocal, 'name', ''))
541
+ // console.log('fpLocal', fpLocal)
542
+
543
+ //cb
544
+ let cb = (msg) => {
545
+ if (isfun(cbProcess)) {
546
+ cbProcess(msg)
547
+ }
548
+ }
549
+
550
+ //ftpUpload
551
+ if (!iseobj(fileRemote)) {
552
+ //遠端檔案不存在
553
+ await ftpUpload(fpLocal, fpRemote, cb)
554
+ n++
555
+ ss.push({
556
+ name: fileLocal.name,
557
+ reason: 'no Remote file',
558
+ })
559
+ }
560
+ else if (fileLocal.size !== fileRemote.size) {
561
+ //遠端檔案大小與本機檔案大小不同
562
+ await ftpUpload(fpLocal, fpRemote, cb)
563
+ n++
564
+ ss.push({
565
+ name: fileLocal.name,
566
+ reason: `size[${fileRemote.size}] of remote file != size[${fileLocal.size}] of local file`,
567
+ })
568
+ }
569
+
570
+ })
571
+
572
+ return {
573
+ num: n,
574
+ files: ss,
575
+ }
576
+ }
577
+
578
+
579
+ return {
580
+ conn: ftpConn,
581
+ ls: ftpLs,
582
+ stateFile: ftpStateFile,
583
+ checkFile: ftpCheckFile,
584
+ download: ftpDownload,
585
+ syncToLocal: ftpSyncToLocal,
586
+ syncToRemote: ftpSyncToRemote,
587
+ upload: ftpUpload,
588
+ quit: ftpQuit,
589
+ }
590
+ }
591
+
592
+ return new WFtpCore()
593
+ }
594
+
595
+
596
+ export default WFtp