w-converhp 2.0.26 → 2.0.27
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 +2 -2
- package/docs/WConverhpClient.mjs.html +85 -9
- 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 +83 -7
- package/src/WConverhpServer.mjs +148 -5
- package/srv.mjs +2 -1
- package/toolg/gDistRollup.mjs +2 -0
|
@@ -45,7 +45,8 @@
|
|
|
45
45
|
|
|
46
46
|
<section>
|
|
47
47
|
<article>
|
|
48
|
-
<pre class="prettyprint source linenums"><code>import
|
|
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
|
-
|
|
457
|
-
|
|
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 =
|
|
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
|
|
1510
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Thu Apr 10 2025 22:27:22 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
|
|
74
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Thu Apr 10 2025 22:27:22 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.
|
|
3
|
+
"version": "2.0.27",
|
|
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.
|
|
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 = '
|
|
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
package/src/WConverhpClient.mjs
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import crypto from 'crypto'
|
|
1
2
|
import axios from 'axios'
|
|
2
3
|
import get from 'lodash-es/get.js'
|
|
3
4
|
import isWindow from 'wsemi/src/isWindow.mjs'
|
|
4
5
|
import evem from 'wsemi/src/evem.mjs'
|
|
5
6
|
import genPm from 'wsemi/src/genPm.mjs'
|
|
6
|
-
import genID from 'wsemi/src/genID.mjs'
|
|
7
|
+
// import genID from 'wsemi/src/genID.mjs'
|
|
8
|
+
// import now2strp from 'wsemi/src/now2strp.mjs'
|
|
7
9
|
import haskey from 'wsemi/src/haskey.mjs'
|
|
8
10
|
import isfun from 'wsemi/src/isfun.mjs'
|
|
9
11
|
import ispint from 'wsemi/src/ispint.mjs'
|
|
@@ -19,7 +21,7 @@ import blob2u8arr from 'wsemi/src/blob2u8arr.mjs'
|
|
|
19
21
|
import obj2u8arr from 'wsemi/src/obj2u8arr.mjs'
|
|
20
22
|
import u8arr2obj from 'wsemi/src/u8arr2obj.mjs'
|
|
21
23
|
import pmConvertResolve from 'wsemi/src/pmConvertResolve.mjs'
|
|
22
|
-
import
|
|
24
|
+
// import getFileHash from 'wsemi/src/getFileHash.mjs'
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
/**
|
|
@@ -165,6 +167,9 @@ function WConverhpClient(opt) {
|
|
|
165
167
|
else if (type === 'slice') {
|
|
166
168
|
urlUse = `${url}slc`
|
|
167
169
|
}
|
|
170
|
+
else if (type === 'upload-check-slice-hash') {
|
|
171
|
+
urlUse = `${url}ulckh`
|
|
172
|
+
}
|
|
168
173
|
else if (type === 'slice-merge') {
|
|
169
174
|
urlUse = `${url}slcm`
|
|
170
175
|
}
|
|
@@ -623,8 +628,29 @@ function WConverhpClient(opt) {
|
|
|
623
628
|
}
|
|
624
629
|
}
|
|
625
630
|
|
|
631
|
+
//calcHash
|
|
632
|
+
async function calcHash(inp) {
|
|
633
|
+
let pm = genPm()
|
|
634
|
+
if (env === 'browser') {
|
|
635
|
+
//前端browser時, 因是給予blob或file上傳, 且使用非同步async版計算hash, 可支援大檔
|
|
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
|
+
pm.resolve(hashHex)
|
|
641
|
+
}
|
|
642
|
+
else {
|
|
643
|
+
//前端nodejs時, 因尚無法提供檔名上傳, 故會是readFileSync讀入的buffer, 同步sync版無法支援大檔
|
|
644
|
+
let hash = crypto.createHash('sha256')
|
|
645
|
+
hash.update(inp, 'utf8')
|
|
646
|
+
let hashHex = hash.digest('hex')
|
|
647
|
+
pm.resolve(hashHex)
|
|
648
|
+
}
|
|
649
|
+
return pm
|
|
650
|
+
}
|
|
651
|
+
|
|
626
652
|
//sendDataSlice
|
|
627
|
-
async function sendDataSlice(
|
|
653
|
+
async function sendDataSlice(fileTotalName, bb, cbProgress) {
|
|
628
654
|
|
|
629
655
|
//n
|
|
630
656
|
let n = 0
|
|
@@ -649,12 +675,40 @@ function WConverhpClient(opt) {
|
|
|
649
675
|
}
|
|
650
676
|
// console.log('n', n)
|
|
651
677
|
|
|
678
|
+
//getFileHash
|
|
679
|
+
let fileTotalHash = await calcHash(bb)
|
|
680
|
+
// console.log('fileTotalHash', fileTotalHash)
|
|
681
|
+
|
|
682
|
+
//ckh
|
|
683
|
+
let ckh = async({ filename, fileHash }) => {
|
|
684
|
+
|
|
685
|
+
//send upload-check-slice-hash
|
|
686
|
+
let resCk = await send('upload-check-slice-hash', { filename, fileHash }, { dataType: 'json' })
|
|
687
|
+
// console.log('resCk', resCk)
|
|
688
|
+
|
|
689
|
+
return resCk
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
//rAll
|
|
693
|
+
let rAll = await ckh({ filename: fileTotalHash, fileHash: fileTotalHash })
|
|
694
|
+
// console.log('rAll', rAll)
|
|
695
|
+
|
|
696
|
+
//check
|
|
697
|
+
if (rAll.existed) {
|
|
698
|
+
//已有上傳大檔
|
|
699
|
+
let resMg = {
|
|
700
|
+
filename: fileTotalName,
|
|
701
|
+
path: rAll.path,
|
|
702
|
+
}
|
|
703
|
+
return resMg
|
|
704
|
+
}
|
|
705
|
+
|
|
652
706
|
//chunkTotal
|
|
653
707
|
let chunkTotal = Math.ceil(n / sizeSlice)
|
|
654
708
|
// console.log('chunkTotal', chunkTotal)
|
|
655
709
|
|
|
656
710
|
//packageId
|
|
657
|
-
let packageId =
|
|
711
|
+
let packageId = fileTotalHash
|
|
658
712
|
// console.log('packageId', packageId)
|
|
659
713
|
|
|
660
714
|
//progCount, progWeightSlice
|
|
@@ -687,6 +741,10 @@ function WConverhpClient(opt) {
|
|
|
687
741
|
//upload slice
|
|
688
742
|
for (let i = 0; i < chunkTotal; i++) {
|
|
689
743
|
|
|
744
|
+
//fileSliceName
|
|
745
|
+
let fileSliceName = `${fileTotalHash}_${i}`
|
|
746
|
+
// console.log('fileSliceName', fileSliceName)
|
|
747
|
+
|
|
690
748
|
//start
|
|
691
749
|
let start = i * sizeSlice
|
|
692
750
|
|
|
@@ -696,6 +754,23 @@ function WConverhpClient(opt) {
|
|
|
696
754
|
//chunk
|
|
697
755
|
let chunk = bb.slice(start, end)
|
|
698
756
|
|
|
757
|
+
//fileSliceHash
|
|
758
|
+
let fileSliceHash = await calcHash(chunk)
|
|
759
|
+
// console.log('fileSliceHash', fileSliceHash)
|
|
760
|
+
|
|
761
|
+
//rChunk
|
|
762
|
+
let rChunk = await ckh({ filename: fileSliceName, fileHash: fileSliceHash })
|
|
763
|
+
// console.log('fileSliceName', fileSliceName)
|
|
764
|
+
// console.log('fileSliceHash', fileSliceHash)
|
|
765
|
+
// console.log('rChunk', rChunk)
|
|
766
|
+
// console.log('')
|
|
767
|
+
|
|
768
|
+
//check
|
|
769
|
+
if (rChunk.existed) {
|
|
770
|
+
//已有上傳切片檔
|
|
771
|
+
continue
|
|
772
|
+
}
|
|
773
|
+
|
|
699
774
|
//send slice
|
|
700
775
|
let hd = {
|
|
701
776
|
'chunk-index': i,
|
|
@@ -703,12 +778,13 @@ function WConverhpClient(opt) {
|
|
|
703
778
|
'package-id': packageId,
|
|
704
779
|
}
|
|
705
780
|
await send('slice', chunk, { headers: hd, dataType: 'blob', cbProgress: cbProgressSlice })
|
|
781
|
+
// console.log('resSl', resSl)
|
|
706
782
|
|
|
707
783
|
}
|
|
708
784
|
|
|
709
785
|
//send slice-merge
|
|
710
786
|
let msg = {
|
|
711
|
-
'filename':
|
|
787
|
+
'filename': fileTotalName,
|
|
712
788
|
'chunk-total': chunkTotal,
|
|
713
789
|
'package-id': packageId,
|
|
714
790
|
}
|
|
@@ -784,12 +860,12 @@ function WConverhpClient(opt) {
|
|
|
784
860
|
}
|
|
785
861
|
|
|
786
862
|
//upload
|
|
787
|
-
async function upload(
|
|
863
|
+
async function upload(filename, input, cbProgress) {
|
|
788
864
|
|
|
789
865
|
//bb
|
|
790
866
|
let bb = input
|
|
791
867
|
|
|
792
|
-
return sendDataSlice(
|
|
868
|
+
return sendDataSlice(filename, bb, cbProgress)
|
|
793
869
|
}
|
|
794
870
|
|
|
795
871
|
//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
|
-
},
|
|
138
|
+
}, 1113000) //bbb
|
|
138
139
|
|
|
139
140
|
|
|
140
141
|
//node --experimental-modules srv.mjs
|