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.
@@ -50,7 +50,8 @@ import get from 'lodash-es/get.js'
50
50
  import isWindow from 'wsemi/src/isWindow.mjs'
51
51
  import evem from 'wsemi/src/evem.mjs'
52
52
  import genPm from 'wsemi/src/genPm.mjs'
53
- import genID from 'wsemi/src/genID.mjs'
53
+ // import genID from 'wsemi/src/genID.mjs'
54
+ // import now2strp from 'wsemi/src/now2strp.mjs'
54
55
  import haskey from 'wsemi/src/haskey.mjs'
55
56
  import isfun from 'wsemi/src/isfun.mjs'
56
57
  import ispint from 'wsemi/src/ispint.mjs'
@@ -66,7 +67,7 @@ import blob2u8arr from 'wsemi/src/blob2u8arr.mjs'
66
67
  import obj2u8arr from 'wsemi/src/obj2u8arr.mjs'
67
68
  import u8arr2obj from 'wsemi/src/u8arr2obj.mjs'
68
69
  import pmConvertResolve from 'wsemi/src/pmConvertResolve.mjs'
69
- import now2strp from 'wsemi/src/now2strp.mjs'
70
+ // import getFileHash from 'wsemi/src/getFileHash.mjs'
70
71
 
71
72
 
72
73
  /**
@@ -119,7 +120,7 @@ import now2strp from 'wsemi/src/now2strp.mjs'
119
120
  * }
120
121
  * },
121
122
  * {
122
- * fdDownload: './', //於後端nodejs環境才能提供
123
+ * fdDownload: './', //於nodejs環境才能提供
123
124
  * })
124
125
  * .then(function(res) {
125
126
  * console.log('client web: download: then', res)
@@ -212,6 +213,9 @@ function WConverhpClient(opt) {
212
213
  else if (type === 'slice') {
213
214
  urlUse = `${url}slc`
214
215
  }
216
+ else if (type === 'upload-check-slice-hash') {
217
+ urlUse = `${url}ulckh`
218
+ }
215
219
  else if (type === 'slice-merge') {
216
220
  urlUse = `${url}slcm`
217
221
  }
@@ -483,11 +487,11 @@ function WConverhpClient(opt) {
483
487
  //nodejs通過fs與stream接收檔案, stream出錯只會觸發error事件, 此處try catch為攔截其他非stream程式碼錯誤
484
488
  try {
485
489
 
486
- //path, fs
490
+ //path, fs, 使用動態import供nodejs使用, 否則會被webpack偵測報錯
487
491
  let path = await import('path')
488
492
  let fs = await import('fs')
489
493
 
490
- //fdDownload, 只有後端下載才使用fdDownload
494
+ //fdDownload, 只有nodejs下載才使用fdDownload
491
495
  let fdDownload = get(opt, 'fdDownload', '')
492
496
  fs.mkdirSync(fdDownload, { recursive: true }) //須使用mkdirSync, 不要用fsIsFolder與fsCreateFolder避免編譯
493
497
  // console.log('fdDownload', fdDownload)
@@ -670,8 +674,36 @@ function WConverhpClient(opt) {
670
674
  }
671
675
  }
672
676
 
677
+ //calcHash
678
+ async function calcHash(inp) {
679
+ let pm = genPm()
680
+ if (env === 'browser') {
681
+ //於browser時, 因是給予blob或file上傳, 且使用非同步async版計算hash, 可支援大檔
682
+
683
+ let ab = await inp.arrayBuffer()
684
+ let hashBuffer = await crypto.subtle.digest('SHA-256', ab)
685
+ let hashArray = Array.from(new Uint8Array(hashBuffer))
686
+ let hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
687
+
688
+ pm.resolve(hashHex)
689
+ }
690
+ else {
691
+ //於nodejs時, 因尚無法提供檔名上傳, 故會是readFileSync讀入的buffer, 同步sync版無法支援大檔
692
+
693
+ //crypto, 使用動態import供nodejs使用, 否則會被webpack偵測報錯
694
+ let crypto = await import('crypto')
695
+
696
+ let hash = crypto.createHash('sha256')
697
+ hash.update(inp, 'utf8')
698
+ let hashHex = hash.digest('hex')
699
+
700
+ pm.resolve(hashHex)
701
+ }
702
+ return pm
703
+ }
704
+
673
705
  //sendDataSlice
674
- async function sendDataSlice(tempId, bb, cbProgress) {
706
+ async function sendDataSlice(fileTotalName, bb, cbProgress) {
675
707
 
676
708
  //n
677
709
  let n = 0
@@ -684,7 +716,7 @@ function WConverhpClient(opt) {
684
716
  }
685
717
  if (n === 0) {
686
718
  try {
687
- n = bb.length //for Uint8Array //後端用fs讀有檔案大小上限, 除非改傳入檔名用stream讀, 否則無法支援超大檔
719
+ n = bb.length //for Uint8Array //nodejs用fs讀有檔案大小上限, 除非改傳入檔名用stream讀, 否則無法支援超大檔
688
720
  n = cint(n)
689
721
  }
690
722
  catch (err) {}
@@ -696,12 +728,40 @@ function WConverhpClient(opt) {
696
728
  }
697
729
  // console.log('n', n)
698
730
 
731
+ //getFileHash
732
+ let fileTotalHash = await calcHash(bb)
733
+ // console.log('fileTotalHash', fileTotalHash)
734
+
735
+ //ckh
736
+ let ckh = async({ filename, fileHash }) => {
737
+
738
+ //send upload-check-slice-hash
739
+ let resCk = await send('upload-check-slice-hash', { filename, fileHash }, { dataType: 'json' })
740
+ // console.log('resCk', resCk)
741
+
742
+ return resCk
743
+ }
744
+
745
+ //rAll
746
+ let rAll = await ckh({ filename: fileTotalHash, fileHash: fileTotalHash })
747
+ // console.log('rAll', rAll)
748
+
749
+ //check
750
+ if (rAll.existed) {
751
+ //已有上傳大檔
752
+ let resMg = {
753
+ filename: fileTotalName,
754
+ path: rAll.path,
755
+ }
756
+ return resMg
757
+ }
758
+
699
759
  //chunkTotal
700
760
  let chunkTotal = Math.ceil(n / sizeSlice)
701
761
  // console.log('chunkTotal', chunkTotal)
702
762
 
703
763
  //packageId
704
- let packageId = `${now2strp()}-${genID()}`
764
+ let packageId = fileTotalHash
705
765
  // console.log('packageId', packageId)
706
766
 
707
767
  //progCount, progWeightSlice
@@ -734,6 +794,10 @@ function WConverhpClient(opt) {
734
794
  //upload slice
735
795
  for (let i = 0; i < chunkTotal; i++) {
736
796
 
797
+ //fileSliceName
798
+ let fileSliceName = `${fileTotalHash}_${i}`
799
+ // console.log('fileSliceName', fileSliceName)
800
+
737
801
  //start
738
802
  let start = i * sizeSlice
739
803
 
@@ -743,6 +807,23 @@ function WConverhpClient(opt) {
743
807
  //chunk
744
808
  let chunk = bb.slice(start, end)
745
809
 
810
+ //fileSliceHash
811
+ let fileSliceHash = await calcHash(chunk)
812
+ // console.log('fileSliceHash', fileSliceHash)
813
+
814
+ //rChunk
815
+ let rChunk = await ckh({ filename: fileSliceName, fileHash: fileSliceHash })
816
+ // console.log('fileSliceName', fileSliceName)
817
+ // console.log('fileSliceHash', fileSliceHash)
818
+ // console.log('rChunk', rChunk)
819
+ // console.log('')
820
+
821
+ //check
822
+ if (rChunk.existed) {
823
+ //已有上傳切片檔
824
+ continue
825
+ }
826
+
746
827
  //send slice
747
828
  let hd = {
748
829
  'chunk-index': i,
@@ -750,12 +831,13 @@ function WConverhpClient(opt) {
750
831
  'package-id': packageId,
751
832
  }
752
833
  await send('slice', chunk, { headers: hd, dataType: 'blob', cbProgress: cbProgressSlice })
834
+ // console.log('resSl', resSl)
753
835
 
754
836
  }
755
837
 
756
838
  //send slice-merge
757
839
  let msg = {
758
- 'filename': tempId,
840
+ 'filename': fileTotalName,
759
841
  'chunk-total': chunkTotal,
760
842
  'package-id': packageId,
761
843
  }
@@ -831,12 +913,12 @@ function WConverhpClient(opt) {
831
913
  }
832
914
 
833
915
  //upload
834
- async function upload(tempId, input, cbProgress) {
916
+ async function upload(filename, input, cbProgress) {
835
917
 
836
918
  //bb
837
919
  let bb = input
838
920
 
839
- return sendDataSlice(tempId, bb, cbProgress)
921
+ return sendDataSlice(filename, bb, cbProgress)
840
922
  }
841
923
 
842
924
  //downloadNodejs
@@ -921,7 +1003,7 @@ export default WConverhpClient
921
1003
  <br class="clear">
922
1004
 
923
1005
  <footer>
924
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Thu Apr 10 2025 15:40:07 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1006
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Thu Apr 10 2025 22:38:50 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
925
1007
  </footer>
926
1008
 
927
1009
  <script>prettyPrint();</script>
@@ -80,7 +80,7 @@
80
80
 
81
81
  <dt class="tag-source">Source:</dt>
82
82
  <dd class="tag-source"><ul class="dummy"><li>
83
- <a href="WConverhpServer.mjs.html">WConverhpServer.mjs</a>, <a href="WConverhpServer.mjs.html#line188">line 188</a>
83
+ <a href="WConverhpServer.mjs.html">WConverhpServer.mjs</a>, <a href="WConverhpServer.mjs.html#line191">line 191</a>
84
84
  </li></ul></dd>
85
85
 
86
86
 
@@ -749,7 +749,7 @@
749
749
  <br class="clear">
750
750
 
751
751
  <footer>
752
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Thu Apr 10 2025 15:40:07 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
752
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Thu Apr 10 2025 22:38:50 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
753
753
  </footer>
754
754
 
755
755
  <script>prettyPrint();</script>
@@ -45,7 +45,8 @@
45
45
 
46
46
  <section>
47
47
  <article>
48
- <pre class="prettyprint source linenums"><code>import fs from 'fs'
48
+ <pre class="prettyprint source linenums"><code>import path from 'path'
49
+ import fs from 'fs'
49
50
  import stream from 'stream'
50
51
  import Hapi from '@hapi/hapi'
51
52
  import Inert from '@hapi/inert' //提供靜態檔案
@@ -67,8 +68,10 @@ import str2b64 from 'wsemi/src/str2b64.mjs'
67
68
  import haskey from 'wsemi/src/haskey.mjs'
68
69
  import obj2u8arr from 'wsemi/src/obj2u8arr.mjs'
69
70
  import u8arr2obj from 'wsemi/src/u8arr2obj.mjs'
71
+ import fsIsFile from 'wsemi/src/fsIsFile.mjs'
70
72
  import fsIsFolder from 'wsemi/src/fsIsFolder.mjs'
71
73
  import fsCreateFolder from 'wsemi/src/fsCreateFolder.mjs'
74
+ import fsGetFileHash from 'wsemi/src/fsGetFileHash.mjs'
72
75
  import mergeFiles from './mergeFiles.wk.umd.js'
73
76
  // import mergeFiles from './mergeFiles.mjs'
74
77
 
@@ -453,12 +456,25 @@ function WConverhpServer(opt = {}) {
453
456
  //returnMsg
454
457
  let returnMsg = get(opt, 'returnMsg', '')
455
458
 
456
- return res.response(smr)
457
- .header('Return-Type', returnType)
458
- .header('Return-Msg', returnMsg)
459
+ //r
460
+ let r = res.response(smr)
459
461
  .header('Cache-Control', 'no-cache, no-store, must-revalidate')
460
462
  .header('Content-Type', 'application/octet-stream')
461
463
  .header('Content-Length', smr.readableLength)
464
+ if (isestr(returnType)) {
465
+ r.header('Return-Type', returnType)
466
+ }
467
+ if (isestr(returnMsg)) {
468
+ r.header('Return-Msg', returnMsg)
469
+ }
470
+
471
+ return r
472
+ // return res.response(smr)
473
+ // .header('Return-Type', returnType)
474
+ // .header('Return-Msg', returnMsg)
475
+ // .header('Cache-Control', 'no-cache, no-store, must-revalidate')
476
+ // .header('Content-Type', 'application/octet-stream')
477
+ // .header('Content-Length', smr.readableLength)
462
478
  }
463
479
 
464
480
  //responseU8aStreamWithError
@@ -631,6 +647,132 @@ function WConverhpServer(opt = {}) {
631
647
  },
632
648
  }
633
649
 
650
+ //apiUploadCheckHash
651
+ let apiUploadCheckHash = {
652
+ path: `/${apiName}ulckh`,
653
+ method: 'POST',
654
+ options: {
655
+ payload: {
656
+ maxBytes: 1024 * 1024 * 1024 * 1024, //預設為1mb, 調整至1tb, 也就是給予3次方
657
+ maxParts: 1000 * 1000 * 1000, //預設為1000, 給予3次方
658
+ timeout: false, //避免請求未完成時中斷
659
+ // output: 'stream',
660
+ parse: true, //前端送obj過來須自動解析
661
+ },
662
+ timeout: {
663
+ server: false, //關閉伺服器超時
664
+ socket: false, //關閉socket超時
665
+ },
666
+ },
667
+ handler: async function (req, res) {
668
+ // console.log(req, res)
669
+ // console.log('payload', req.payload)
670
+
671
+ //headers
672
+ let headers = get(req, 'headers')
673
+ headers = iseobj(headers) ? headers : ''
674
+ // console.log('headers', headers)
675
+
676
+ //query
677
+ let query = get(req, 'query')
678
+ query = iseobj(query) ? query : ''
679
+ // console.log('query', query)
680
+
681
+ //authorization
682
+ let authorization = get(headers, 'authorization', '')
683
+ authorization = isestr(authorization) ? authorization : ''
684
+
685
+ //check
686
+ if (true) {
687
+
688
+ //verifyConn
689
+ let m = verifyConn({ apiType: 'upload-check-slice-hash', authorization, headers, query })
690
+ if (ispm(m)) {
691
+ m = await m
692
+ }
693
+
694
+ //check
695
+ if (m !== true) {
696
+ return responseU8aStreamWithError(res, 'permission denied')
697
+ }
698
+
699
+ }
700
+
701
+ //eeEmit
702
+ eeEmit('handler', {
703
+ api: 'apiUploadCheckHash',
704
+ headers,
705
+ query,
706
+ })
707
+
708
+ //filename, fileHash, 從payload接收
709
+ let filename = get(req, 'payload.filename', '')
710
+ let fileHash = get(req, 'payload.fileHash', '')
711
+ // console.log('filename', filename)
712
+ // console.log('fileHash', fileHash)
713
+
714
+ //check
715
+ if (!isestr(filename)) {
716
+ // console.log('invalid filename in payload')
717
+ return responseU8aStreamWithError(res, 'invalid filename in payload')
718
+ }
719
+
720
+ //check
721
+ if (!isestr(fileHash)) {
722
+ // console.log('invalid fileHash in payload')
723
+ return responseU8aStreamWithError(res, 'invalid fileHash in payload')
724
+ }
725
+
726
+ //pathFile
727
+ let pathFile = path.join(pathUploadTemp, filename)
728
+ // console.log('pathFile', pathFile)
729
+
730
+ //check
731
+ if (!fsIsFile(pathFile)) {
732
+ let out = {
733
+ success: {
734
+ existed: false,
735
+ msg: 'not exist',
736
+ },
737
+ }
738
+ let u8aOut = obj2u8arr(out)
739
+ return responseU8aStream(res, u8aOut, { returnType: 'success', returnMsg: 'need to parse' })
740
+ }
741
+
742
+ //hash, fsGetFileHash要用非同步stream模式才能支援大檔
743
+ let hash = await fsGetFileHash(pathFile, { useSync: false, type: 'sha256' })
744
+ // console.log('path', pathFile)
745
+ // console.log('hash(front)', fileHash)
746
+ // console.log('hash(backend)', hash)
747
+ // console.log('')
748
+
749
+ //check
750
+ if (fileHash !== hash) {
751
+ let out = {
752
+ success: {
753
+ existed: false,
754
+ msg: 'not equal',
755
+ },
756
+ }
757
+ let u8aOut = obj2u8arr(out)
758
+ return responseU8aStream(res, u8aOut, { returnType: 'success', returnMsg: 'need to parse' })
759
+ }
760
+
761
+ if (true) {
762
+ let out = {
763
+ success: {
764
+ existed: true,
765
+ msg: 'equal',
766
+ path: pathFile,
767
+ },
768
+ }
769
+ let u8aOut = obj2u8arr(out)
770
+ return responseU8aStream(res, u8aOut, { returnType: 'success', returnMsg: 'need to parse' })
771
+ }
772
+
773
+ },
774
+ }
775
+
634
776
  //apiUploadSlice
635
777
  let apiUploadSlice = {
636
778
  path: `/${apiName}slc`,
@@ -711,7 +853,7 @@ function WConverhpServer(opt = {}) {
711
853
  }
712
854
 
713
855
  //pathFileChunk
714
- let pathFileChunk = `${pathUploadTemp}/${packageId}_${chunkIndex}` //path.join(pathUploadTemp, `${packageId}_${chunkIndex}`)
856
+ let pathFileChunk = path.join(pathUploadTemp, `${packageId}_${chunkIndex}`)
715
857
  // console.log('pathFileChunk', pathFileChunk)
716
858
 
717
859
  //streamWrite
@@ -1311,6 +1453,7 @@ function WConverhpServer(opt = {}) {
1311
1453
  apiRoutes = [
1312
1454
  ...apiRoutes,
1313
1455
  apiMain,
1456
+ apiUploadCheckHash,
1314
1457
  apiUploadSlice,
1315
1458
  apiUploadSliceMerge,
1316
1459
  apiDownloadGetFilename,
@@ -1331,7 +1474,7 @@ function WConverhpServer(opt = {}) {
1331
1474
 
1332
1475
  //start
1333
1476
  if (get(opt, 'serverHapi')) {
1334
- server.route([apiMain, apiUploadSlice, apiUploadSliceMerge, apiDownloadGetFilename, apiDownloadGetFile, apiDownload])
1477
+ server.route([apiMain, apiUploadCheckHash, apiUploadSlice, apiUploadSliceMerge, apiDownloadGetFilename, apiDownloadGetFile, apiDownload])
1335
1478
  }
1336
1479
  else {
1337
1480
  startServer()
@@ -1364,7 +1507,7 @@ export default WConverhpServer
1364
1507
  <br class="clear">
1365
1508
 
1366
1509
  <footer>
1367
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Thu Apr 10 2025 15:40:07 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1510
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Thu Apr 10 2025 22:38:50 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1368
1511
  </footer>
1369
1512
 
1370
1513
  <script>prettyPrint();</script>
package/docs/index.html CHANGED
@@ -71,7 +71,7 @@
71
71
  <br class="clear">
72
72
 
73
73
  <footer>
74
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Thu Apr 10 2025 15:40:07 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
74
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Thu Apr 10 2025 22:38:50 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
75
75
  </footer>
76
76
 
77
77
  <script>prettyPrint();</script>
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "w-converhp",
3
- "version": "2.0.26",
3
+ "version": "2.0.28",
4
4
  "main": "dist/w-converhp-server.umd.js",
5
5
  "dependencies": {
6
6
  "@hapi/hapi": "^21.4.0",
7
7
  "@hapi/inert": "^7.1.0",
8
8
  "axios": "^1.8.4",
9
9
  "lodash-es": "^4.17.21",
10
- "wsemi": "^1.7.79"
10
+ "wsemi": "^1.7.80"
11
11
  },
12
12
  "devDependencies": {
13
13
  "form-data": "^4.0.2",
package/sclc.mjs CHANGED
@@ -27,7 +27,7 @@ wo.on('error', (err) => {
27
27
  function uploadLargeFile() {
28
28
  let core = async() => {
29
29
 
30
- let fsz = '1000mb' //0mb 10mb 100mb 1000mb
30
+ let fsz = '10mb' //0mb 10mb 100mb 1000mb
31
31
 
32
32
  //u8a
33
33
  let u8a = new Uint8Array(fs.readFileSync(`../_data/${fsz}.7z`)) //後端並無blob格式, 用fs讀有檔案大小上限
package/script.txt CHANGED
@@ -16,5 +16,3 @@ npm run deploy
16
16
 
17
17
  #npm publish
18
18
 
19
- #npm test bbb
20
-