w-converhp 2.0.26 → 2.0.28

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.
@@ -3,7 +3,8 @@ import get from 'lodash-es/get.js'
3
3
  import isWindow from 'wsemi/src/isWindow.mjs'
4
4
  import evem from 'wsemi/src/evem.mjs'
5
5
  import genPm from 'wsemi/src/genPm.mjs'
6
- import genID from 'wsemi/src/genID.mjs'
6
+ // import genID from 'wsemi/src/genID.mjs'
7
+ // import now2strp from 'wsemi/src/now2strp.mjs'
7
8
  import haskey from 'wsemi/src/haskey.mjs'
8
9
  import isfun from 'wsemi/src/isfun.mjs'
9
10
  import ispint from 'wsemi/src/ispint.mjs'
@@ -19,7 +20,7 @@ import blob2u8arr from 'wsemi/src/blob2u8arr.mjs'
19
20
  import obj2u8arr from 'wsemi/src/obj2u8arr.mjs'
20
21
  import u8arr2obj from 'wsemi/src/u8arr2obj.mjs'
21
22
  import pmConvertResolve from 'wsemi/src/pmConvertResolve.mjs'
22
- import now2strp from 'wsemi/src/now2strp.mjs'
23
+ // import getFileHash from 'wsemi/src/getFileHash.mjs'
23
24
 
24
25
 
25
26
  /**
@@ -72,7 +73,7 @@ import now2strp from 'wsemi/src/now2strp.mjs'
72
73
  * }
73
74
  * },
74
75
  * {
75
- * fdDownload: './', //於後端nodejs環境才能提供
76
+ * fdDownload: './', //於nodejs環境才能提供
76
77
  * })
77
78
  * .then(function(res) {
78
79
  * console.log('client web: download: then', res)
@@ -165,6 +166,9 @@ function WConverhpClient(opt) {
165
166
  else if (type === 'slice') {
166
167
  urlUse = `${url}slc`
167
168
  }
169
+ else if (type === 'upload-check-slice-hash') {
170
+ urlUse = `${url}ulckh`
171
+ }
168
172
  else if (type === 'slice-merge') {
169
173
  urlUse = `${url}slcm`
170
174
  }
@@ -436,11 +440,11 @@ function WConverhpClient(opt) {
436
440
  //nodejs通過fs與stream接收檔案, stream出錯只會觸發error事件, 此處try catch為攔截其他非stream程式碼錯誤
437
441
  try {
438
442
 
439
- //path, fs
443
+ //path, fs, 使用動態import供nodejs使用, 否則會被webpack偵測報錯
440
444
  let path = await import('path')
441
445
  let fs = await import('fs')
442
446
 
443
- //fdDownload, 只有後端下載才使用fdDownload
447
+ //fdDownload, 只有nodejs下載才使用fdDownload
444
448
  let fdDownload = get(opt, 'fdDownload', '')
445
449
  fs.mkdirSync(fdDownload, { recursive: true }) //須使用mkdirSync, 不要用fsIsFolder與fsCreateFolder避免編譯
446
450
  // console.log('fdDownload', fdDownload)
@@ -623,8 +627,36 @@ function WConverhpClient(opt) {
623
627
  }
624
628
  }
625
629
 
630
+ //calcHash
631
+ async function calcHash(inp) {
632
+ let pm = genPm()
633
+ if (env === 'browser') {
634
+ //於browser時, 因是給予blob或file上傳, 且使用非同步async版計算hash, 可支援大檔
635
+
636
+ let ab = await inp.arrayBuffer()
637
+ let hashBuffer = await crypto.subtle.digest('SHA-256', ab)
638
+ let hashArray = Array.from(new Uint8Array(hashBuffer))
639
+ let hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
640
+
641
+ pm.resolve(hashHex)
642
+ }
643
+ else {
644
+ //於nodejs時, 因尚無法提供檔名上傳, 故會是readFileSync讀入的buffer, 同步sync版無法支援大檔
645
+
646
+ //crypto, 使用動態import供nodejs使用, 否則會被webpack偵測報錯
647
+ let crypto = await import('crypto')
648
+
649
+ let hash = crypto.createHash('sha256')
650
+ hash.update(inp, 'utf8')
651
+ let hashHex = hash.digest('hex')
652
+
653
+ pm.resolve(hashHex)
654
+ }
655
+ return pm
656
+ }
657
+
626
658
  //sendDataSlice
627
- async function sendDataSlice(tempId, bb, cbProgress) {
659
+ async function sendDataSlice(fileTotalName, bb, cbProgress) {
628
660
 
629
661
  //n
630
662
  let n = 0
@@ -637,7 +669,7 @@ function WConverhpClient(opt) {
637
669
  }
638
670
  if (n === 0) {
639
671
  try {
640
- n = bb.length //for Uint8Array //後端用fs讀有檔案大小上限, 除非改傳入檔名用stream讀, 否則無法支援超大檔
672
+ n = bb.length //for Uint8Array //nodejs用fs讀有檔案大小上限, 除非改傳入檔名用stream讀, 否則無法支援超大檔
641
673
  n = cint(n)
642
674
  }
643
675
  catch (err) {}
@@ -649,12 +681,40 @@ function WConverhpClient(opt) {
649
681
  }
650
682
  // console.log('n', n)
651
683
 
684
+ //getFileHash
685
+ let fileTotalHash = await calcHash(bb)
686
+ // console.log('fileTotalHash', fileTotalHash)
687
+
688
+ //ckh
689
+ let ckh = async({ filename, fileHash }) => {
690
+
691
+ //send upload-check-slice-hash
692
+ let resCk = await send('upload-check-slice-hash', { filename, fileHash }, { dataType: 'json' })
693
+ // console.log('resCk', resCk)
694
+
695
+ return resCk
696
+ }
697
+
698
+ //rAll
699
+ let rAll = await ckh({ filename: fileTotalHash, fileHash: fileTotalHash })
700
+ // console.log('rAll', rAll)
701
+
702
+ //check
703
+ if (rAll.existed) {
704
+ //已有上傳大檔
705
+ let resMg = {
706
+ filename: fileTotalName,
707
+ path: rAll.path,
708
+ }
709
+ return resMg
710
+ }
711
+
652
712
  //chunkTotal
653
713
  let chunkTotal = Math.ceil(n / sizeSlice)
654
714
  // console.log('chunkTotal', chunkTotal)
655
715
 
656
716
  //packageId
657
- let packageId = `${now2strp()}-${genID()}`
717
+ let packageId = fileTotalHash
658
718
  // console.log('packageId', packageId)
659
719
 
660
720
  //progCount, progWeightSlice
@@ -687,6 +747,10 @@ function WConverhpClient(opt) {
687
747
  //upload slice
688
748
  for (let i = 0; i < chunkTotal; i++) {
689
749
 
750
+ //fileSliceName
751
+ let fileSliceName = `${fileTotalHash}_${i}`
752
+ // console.log('fileSliceName', fileSliceName)
753
+
690
754
  //start
691
755
  let start = i * sizeSlice
692
756
 
@@ -696,6 +760,23 @@ function WConverhpClient(opt) {
696
760
  //chunk
697
761
  let chunk = bb.slice(start, end)
698
762
 
763
+ //fileSliceHash
764
+ let fileSliceHash = await calcHash(chunk)
765
+ // console.log('fileSliceHash', fileSliceHash)
766
+
767
+ //rChunk
768
+ let rChunk = await ckh({ filename: fileSliceName, fileHash: fileSliceHash })
769
+ // console.log('fileSliceName', fileSliceName)
770
+ // console.log('fileSliceHash', fileSliceHash)
771
+ // console.log('rChunk', rChunk)
772
+ // console.log('')
773
+
774
+ //check
775
+ if (rChunk.existed) {
776
+ //已有上傳切片檔
777
+ continue
778
+ }
779
+
699
780
  //send slice
700
781
  let hd = {
701
782
  'chunk-index': i,
@@ -703,12 +784,13 @@ function WConverhpClient(opt) {
703
784
  'package-id': packageId,
704
785
  }
705
786
  await send('slice', chunk, { headers: hd, dataType: 'blob', cbProgress: cbProgressSlice })
787
+ // console.log('resSl', resSl)
706
788
 
707
789
  }
708
790
 
709
791
  //send slice-merge
710
792
  let msg = {
711
- 'filename': tempId,
793
+ 'filename': fileTotalName,
712
794
  'chunk-total': chunkTotal,
713
795
  'package-id': packageId,
714
796
  }
@@ -784,12 +866,12 @@ function WConverhpClient(opt) {
784
866
  }
785
867
 
786
868
  //upload
787
- async function upload(tempId, input, cbProgress) {
869
+ async function upload(filename, input, cbProgress) {
788
870
 
789
871
  //bb
790
872
  let bb = input
791
873
 
792
- return sendDataSlice(tempId, bb, cbProgress)
874
+ return sendDataSlice(filename, bb, cbProgress)
793
875
  }
794
876
 
795
877
  //downloadNodejs
@@ -1,3 +1,4 @@
1
+ import path from 'path'
1
2
  import fs from 'fs'
2
3
  import stream from 'stream'
3
4
  import Hapi from '@hapi/hapi'
@@ -20,8 +21,10 @@ import str2b64 from 'wsemi/src/str2b64.mjs'
20
21
  import haskey from 'wsemi/src/haskey.mjs'
21
22
  import obj2u8arr from 'wsemi/src/obj2u8arr.mjs'
22
23
  import u8arr2obj from 'wsemi/src/u8arr2obj.mjs'
24
+ import fsIsFile from 'wsemi/src/fsIsFile.mjs'
23
25
  import fsIsFolder from 'wsemi/src/fsIsFolder.mjs'
24
26
  import fsCreateFolder from 'wsemi/src/fsCreateFolder.mjs'
27
+ import fsGetFileHash from 'wsemi/src/fsGetFileHash.mjs'
25
28
  import mergeFiles from './mergeFiles.wk.umd.js'
26
29
  // import mergeFiles from './mergeFiles.mjs'
27
30
 
@@ -406,12 +409,25 @@ function WConverhpServer(opt = {}) {
406
409
  //returnMsg
407
410
  let returnMsg = get(opt, 'returnMsg', '')
408
411
 
409
- return res.response(smr)
410
- .header('Return-Type', returnType)
411
- .header('Return-Msg', returnMsg)
412
+ //r
413
+ let r = res.response(smr)
412
414
  .header('Cache-Control', 'no-cache, no-store, must-revalidate')
413
415
  .header('Content-Type', 'application/octet-stream')
414
416
  .header('Content-Length', smr.readableLength)
417
+ if (isestr(returnType)) {
418
+ r.header('Return-Type', returnType)
419
+ }
420
+ if (isestr(returnMsg)) {
421
+ r.header('Return-Msg', returnMsg)
422
+ }
423
+
424
+ return r
425
+ // return res.response(smr)
426
+ // .header('Return-Type', returnType)
427
+ // .header('Return-Msg', returnMsg)
428
+ // .header('Cache-Control', 'no-cache, no-store, must-revalidate')
429
+ // .header('Content-Type', 'application/octet-stream')
430
+ // .header('Content-Length', smr.readableLength)
415
431
  }
416
432
 
417
433
  //responseU8aStreamWithError
@@ -584,6 +600,132 @@ function WConverhpServer(opt = {}) {
584
600
  },
585
601
  }
586
602
 
603
+ //apiUploadCheckHash
604
+ let apiUploadCheckHash = {
605
+ path: `/${apiName}ulckh`,
606
+ method: 'POST',
607
+ options: {
608
+ payload: {
609
+ maxBytes: 1024 * 1024 * 1024 * 1024, //預設為1mb, 調整至1tb, 也就是給予3次方
610
+ maxParts: 1000 * 1000 * 1000, //預設為1000, 給予3次方
611
+ timeout: false, //避免請求未完成時中斷
612
+ // output: 'stream',
613
+ parse: true, //前端送obj過來須自動解析
614
+ },
615
+ timeout: {
616
+ server: false, //關閉伺服器超時
617
+ socket: false, //關閉socket超時
618
+ },
619
+ },
620
+ handler: async function (req, res) {
621
+ // console.log(req, res)
622
+ // console.log('payload', req.payload)
623
+
624
+ //headers
625
+ let headers = get(req, 'headers')
626
+ headers = iseobj(headers) ? headers : ''
627
+ // console.log('headers', headers)
628
+
629
+ //query
630
+ let query = get(req, 'query')
631
+ query = iseobj(query) ? query : ''
632
+ // console.log('query', query)
633
+
634
+ //authorization
635
+ let authorization = get(headers, 'authorization', '')
636
+ authorization = isestr(authorization) ? authorization : ''
637
+
638
+ //check
639
+ if (true) {
640
+
641
+ //verifyConn
642
+ let m = verifyConn({ apiType: 'upload-check-slice-hash', authorization, headers, query })
643
+ if (ispm(m)) {
644
+ m = await m
645
+ }
646
+
647
+ //check
648
+ if (m !== true) {
649
+ return responseU8aStreamWithError(res, 'permission denied')
650
+ }
651
+
652
+ }
653
+
654
+ //eeEmit
655
+ eeEmit('handler', {
656
+ api: 'apiUploadCheckHash',
657
+ headers,
658
+ query,
659
+ })
660
+
661
+ //filename, fileHash, 從payload接收
662
+ let filename = get(req, 'payload.filename', '')
663
+ let fileHash = get(req, 'payload.fileHash', '')
664
+ // console.log('filename', filename)
665
+ // console.log('fileHash', fileHash)
666
+
667
+ //check
668
+ if (!isestr(filename)) {
669
+ // console.log('invalid filename in payload')
670
+ return responseU8aStreamWithError(res, 'invalid filename in payload')
671
+ }
672
+
673
+ //check
674
+ if (!isestr(fileHash)) {
675
+ // console.log('invalid fileHash in payload')
676
+ return responseU8aStreamWithError(res, 'invalid fileHash in payload')
677
+ }
678
+
679
+ //pathFile
680
+ let pathFile = path.join(pathUploadTemp, filename)
681
+ // console.log('pathFile', pathFile)
682
+
683
+ //check
684
+ if (!fsIsFile(pathFile)) {
685
+ let out = {
686
+ success: {
687
+ existed: false,
688
+ msg: 'not exist',
689
+ },
690
+ }
691
+ let u8aOut = obj2u8arr(out)
692
+ return responseU8aStream(res, u8aOut, { returnType: 'success', returnMsg: 'need to parse' })
693
+ }
694
+
695
+ //hash, fsGetFileHash要用非同步stream模式才能支援大檔
696
+ let hash = await fsGetFileHash(pathFile, { useSync: false, type: 'sha256' })
697
+ // console.log('path', pathFile)
698
+ // console.log('hash(front)', fileHash)
699
+ // console.log('hash(backend)', hash)
700
+ // console.log('')
701
+
702
+ //check
703
+ if (fileHash !== hash) {
704
+ let out = {
705
+ success: {
706
+ existed: false,
707
+ msg: 'not equal',
708
+ },
709
+ }
710
+ let u8aOut = obj2u8arr(out)
711
+ return responseU8aStream(res, u8aOut, { returnType: 'success', returnMsg: 'need to parse' })
712
+ }
713
+
714
+ if (true) {
715
+ let out = {
716
+ success: {
717
+ existed: true,
718
+ msg: 'equal',
719
+ path: pathFile,
720
+ },
721
+ }
722
+ let u8aOut = obj2u8arr(out)
723
+ return responseU8aStream(res, u8aOut, { returnType: 'success', returnMsg: 'need to parse' })
724
+ }
725
+
726
+ },
727
+ }
728
+
587
729
  //apiUploadSlice
588
730
  let apiUploadSlice = {
589
731
  path: `/${apiName}slc`,
@@ -664,7 +806,7 @@ function WConverhpServer(opt = {}) {
664
806
  }
665
807
 
666
808
  //pathFileChunk
667
- let pathFileChunk = `${pathUploadTemp}/${packageId}_${chunkIndex}` //path.join(pathUploadTemp, `${packageId}_${chunkIndex}`)
809
+ let pathFileChunk = path.join(pathUploadTemp, `${packageId}_${chunkIndex}`)
668
810
  // console.log('pathFileChunk', pathFileChunk)
669
811
 
670
812
  //streamWrite
@@ -1264,6 +1406,7 @@ function WConverhpServer(opt = {}) {
1264
1406
  apiRoutes = [
1265
1407
  ...apiRoutes,
1266
1408
  apiMain,
1409
+ apiUploadCheckHash,
1267
1410
  apiUploadSlice,
1268
1411
  apiUploadSliceMerge,
1269
1412
  apiDownloadGetFilename,
@@ -1284,7 +1427,7 @@ function WConverhpServer(opt = {}) {
1284
1427
 
1285
1428
  //start
1286
1429
  if (get(opt, 'serverHapi')) {
1287
- server.route([apiMain, apiUploadSlice, apiUploadSliceMerge, apiDownloadGetFilename, apiDownloadGetFile, apiDownload])
1430
+ server.route([apiMain, apiUploadCheckHash, apiUploadSlice, apiUploadSliceMerge, apiDownloadGetFilename, apiDownloadGetFile, apiDownload])
1288
1431
  }
1289
1432
  else {
1290
1433
  startServer()
package/srv.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import path from 'path'
1
2
  import fs from 'fs'
2
3
  import _ from 'lodash-es'
3
4
  import w from 'wsemi'
@@ -134,7 +135,7 @@ setTimeout(() => {
134
135
  console.log('ms', ms)
135
136
  // console.log('ms', JSON.stringify(ms))
136
137
  wo.stop()
137
- }, 3000)
138
+ }, 3000) //bbb
138
139
 
139
140
 
140
141
  //node --experimental-modules srv.mjs
@@ -21,10 +21,12 @@ async function core() {
21
21
  globals: {
22
22
  'path': 'path',
23
23
  'fs': 'fs',
24
+ 'crypto': 'crypto',
24
25
  },
25
26
  external: [
26
27
  'path',
27
28
  'fs',
29
+ 'crypto',
28
30
  ],
29
31
  })
30
32
  .catch((err) => {