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.
- package/.github/workflows/ci-test.yml +1 -1
- package/README.md +1 -1
- package/dist/w-converhp-client.umd.js +2 -2
- package/dist/w-converhp-client.umd.js.map +1 -1
- package/dist/w-converhp-server.umd.js +2 -2
- package/dist/w-converhp-server.umd.js.map +1 -1
- package/docs/WConverhpClient.html +3 -3
- package/docs/WConverhpClient.mjs.html +94 -12
- package/docs/WConverhpServer.html +2 -2
- package/docs/WConverhpServer.mjs.html +150 -7
- package/docs/index.html +1 -1
- package/package.json +2 -2
- package/sclc.mjs +1 -1
- package/script.txt +0 -2
- package/src/WConverhpClient.mjs +93 -11
- package/src/WConverhpServer.mjs +148 -5
- package/srv.mjs +2 -1
- package/toolg/gDistRollup.mjs +2 -0
package/src/WConverhpClient.mjs
CHANGED
|
@@ -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
|
|
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: './',
|
|
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,
|
|
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(
|
|
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
|
|
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 =
|
|
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':
|
|
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(
|
|
869
|
+
async function upload(filename, input, cbProgress) {
|
|
788
870
|
|
|
789
871
|
//bb
|
|
790
872
|
let bb = input
|
|
791
873
|
|
|
792
|
-
return sendDataSlice(
|
|
874
|
+
return sendDataSlice(filename, bb, cbProgress)
|
|
793
875
|
}
|
|
794
876
|
|
|
795
877
|
//downloadNodejs
|
package/src/WConverhpServer.mjs
CHANGED
|
@@ -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
|
-
|
|
410
|
-
|
|
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 =
|
|
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
|