w-converhp 2.0.13 → 2.0.15
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/README.md +68 -99
- 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 +104 -120
- package/docs/WConverhpServer.html +43 -3
- package/docs/WConverhpServer.mjs.html +349 -32
- package/docs/index.html +1 -1
- package/package.json +1 -1
- package/scld.mjs +5 -5
- package/src/WConverhpClient.mjs +103 -119
- package/src/WConverhpServer.mjs +348 -31
- package/srv.mjs +25 -2
- package/test/downloadLargeFile.test.mjs +12 -13
- package/test/executeWithFile.test.mjs +10 -12
- package/test/executeWithU8a.test.mjs +11 -13
- package/test/uploadLargeFile.test.mjs +10 -14
package/src/WConverhpServer.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import stream from 'stream'
|
|
|
3
3
|
import Hapi from '@hapi/hapi'
|
|
4
4
|
import Inert from '@hapi/inert' //提供靜態檔案
|
|
5
5
|
import get from 'lodash-es/get.js'
|
|
6
|
+
import isNumber from 'lodash-es/isNumber.js'
|
|
6
7
|
import genPm from 'wsemi/src/genPm.mjs'
|
|
7
8
|
import evem from 'wsemi/src/evem.mjs'
|
|
8
9
|
import iseobj from 'wsemi/src/iseobj.mjs'
|
|
@@ -12,9 +13,10 @@ import ispint from 'wsemi/src/ispint.mjs'
|
|
|
12
13
|
import isearr from 'wsemi/src/isearr.mjs'
|
|
13
14
|
import isbol from 'wsemi/src/isbol.mjs'
|
|
14
15
|
import isfun from 'wsemi/src/isfun.mjs'
|
|
15
|
-
import isnum from 'wsemi/src/isnum.mjs'
|
|
16
16
|
import ispm from 'wsemi/src/ispm.mjs'
|
|
17
17
|
import cint from 'wsemi/src/cint.mjs'
|
|
18
|
+
import cstr from 'wsemi/src/cstr.mjs'
|
|
19
|
+
import str2b64 from 'wsemi/src/str2b64.mjs'
|
|
18
20
|
import haskey from 'wsemi/src/haskey.mjs'
|
|
19
21
|
import obj2u8arr from 'wsemi/src/obj2u8arr.mjs'
|
|
20
22
|
import u8arr2obj from 'wsemi/src/u8arr2obj.mjs'
|
|
@@ -24,6 +26,11 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
24
26
|
// import mergeFiles from './mergeFiles.mjs'
|
|
25
27
|
|
|
26
28
|
|
|
29
|
+
//回傳前端stream時(POST或GET皆可), 前端會須等stream傳完才能判斷是否為大檔或錯誤訊息, 此會導致若回傳超大檔, 會需要對超大檔進行解析會有記憶體上限問題, 故需要通過header提供基本成功或失敗訊息, 讓前端能進行解析判斷
|
|
30
|
+
//回傳前端(nodejs)時, 針對超大檔, 只能用POST並用stream回傳
|
|
31
|
+
//回傳前端(browser)時, 針對超大檔, 可用POST並用stream回傳但還要處理進度條, 若要交由瀏覽器下載器處理, 只能用GET並用stream回傳, 且前端只能用window.location.href或a.href+a.click()下載
|
|
32
|
+
|
|
33
|
+
|
|
27
34
|
/**
|
|
28
35
|
* 建立Hapi伺服器
|
|
29
36
|
*
|
|
@@ -34,6 +41,7 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
34
41
|
* @param {String} [opt.pathStaticFiles='dist'] 輸入當useInert=true時提供瀏覽資料夾字串,預設'dist'
|
|
35
42
|
* @param {String} [opt.apiName='api'] 輸入API名稱字串,預設'api'
|
|
36
43
|
* @param {String} [opt.pathUploadTemp='./uploadTemp'] 輸入暫時存放切片上傳檔案資料夾字串,預設'./uploadTemp'
|
|
44
|
+
* @param {String} [opt.tokenType='Bearer'] 輸入token類型字串,預設'Bearer'
|
|
37
45
|
* @param {Function} [opt.verifyConn=()=>{return true}] 輸入呼叫API時檢測函數,預設()=>{return true}
|
|
38
46
|
* @param {Array} [opt.corsOrigins=['*']] 輸入允許跨域網域陣列,若給予['*']代表允許全部,預設['*']
|
|
39
47
|
* @param {Integer} [opt.delayForBasic=0] 輸入基本API用延遲響應時間,單位ms,預設0
|
|
@@ -42,14 +50,24 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
42
50
|
* @returns {Object} 回傳事件物件,可監聽事件execute、upload、handler
|
|
43
51
|
* @example
|
|
44
52
|
*
|
|
53
|
+
* import fs from 'fs'
|
|
45
54
|
* import _ from 'lodash-es'
|
|
46
|
-
* import
|
|
55
|
+
* import w from 'wsemi'
|
|
56
|
+
* import WConverhpServer from './src/WConverhpServer.mjs'
|
|
57
|
+
*
|
|
58
|
+
* let ms = []
|
|
47
59
|
*
|
|
48
60
|
* let opt = {
|
|
49
61
|
* port: 8080,
|
|
50
62
|
* apiName: 'api',
|
|
51
63
|
* pathStaticFiles: '.', //要存取專案資料夾下web.html, 故不能給dist
|
|
52
|
-
* verifyConn: () => {
|
|
64
|
+
* verifyConn: async ({ apiType, authorization, headers, query }) => {
|
|
65
|
+
* console.log('verifyConn', `apiType[${apiType}]`, `authorization[${authorization}]`)
|
|
66
|
+
* let token = w.strdelleft(authorization, 7) //刪除Bearer
|
|
67
|
+
* if (!w.isestr(token)) {
|
|
68
|
+
* return false
|
|
69
|
+
* }
|
|
70
|
+
* // await w.delay(3000)
|
|
53
71
|
* return true
|
|
54
72
|
* },
|
|
55
73
|
* }
|
|
@@ -67,6 +85,7 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
67
85
|
*
|
|
68
86
|
* if (_.get(input, 'p.d.u8a', null)) {
|
|
69
87
|
* console.log('input.p.d.u8a', input.p.d.u8a)
|
|
88
|
+
* ms.push({ 'input.p.d.u8a': input.p.d.u8a })
|
|
70
89
|
* }
|
|
71
90
|
*
|
|
72
91
|
* let r = {
|
|
@@ -74,13 +93,7 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
74
93
|
* _data: [11, 22.22, 'abc', { x: '21', y: 65.43, z: 'test中文' }],
|
|
75
94
|
* _bin: {
|
|
76
95
|
* name: 'zdata.b2',
|
|
77
|
-
* u8a: new Uint8Array([66, 97, 115]),
|
|
78
|
-
* // name: '100mb.7z',
|
|
79
|
-
* // u8a: new Uint8Array(fs.readFileSync('D:\\開源-JS-006-2-w-converhp\\_temp\\100mb.7z')),
|
|
80
|
-
* // name: '500mb.7z',
|
|
81
|
-
* // u8a: new Uint8Array(fs.readFileSync('D:\\開源-JS-006-2-w-converhp\\_temp\\500mb.7z')),
|
|
82
|
-
* // name: '1000mb.7z',
|
|
83
|
-
* // u8a: new Uint8Array(fs.readFileSync('D:\\開源-JS-006-2-w-converhp\\_temp\\1000mb.7z')),
|
|
96
|
+
* u8a: new Uint8Array([52, 66, 97, 115]),
|
|
84
97
|
* },
|
|
85
98
|
* }
|
|
86
99
|
*
|
|
@@ -103,6 +116,7 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
103
116
|
* console.log(`Server[port:${opt.port}]: upload`, input)
|
|
104
117
|
*
|
|
105
118
|
* try {
|
|
119
|
+
* ms.push({ 'receive and return': input })
|
|
106
120
|
* let output = input
|
|
107
121
|
* pm.resolve(output)
|
|
108
122
|
* }
|
|
@@ -112,6 +126,28 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
112
126
|
* }
|
|
113
127
|
*
|
|
114
128
|
* })
|
|
129
|
+
* wo.on('download-get-filename', (input, pm) => {
|
|
130
|
+
* console.log(`Server[port:${opt.port}]: download-get-filename`, input)
|
|
131
|
+
*
|
|
132
|
+
* try {
|
|
133
|
+
* ms.push({ 'download': input })
|
|
134
|
+
*
|
|
135
|
+
* //filename
|
|
136
|
+
* let filename = `1mb中文.7z` //測試支援中文
|
|
137
|
+
*
|
|
138
|
+
* //output
|
|
139
|
+
* let output = {
|
|
140
|
+
* filename
|
|
141
|
+
* }
|
|
142
|
+
*
|
|
143
|
+
* pm.resolve(output)
|
|
144
|
+
* }
|
|
145
|
+
* catch (err) {
|
|
146
|
+
* console.log('download error', err)
|
|
147
|
+
* pm.reject('download error')
|
|
148
|
+
* }
|
|
149
|
+
*
|
|
150
|
+
* })
|
|
115
151
|
* wo.on('download', (input, pm) => {
|
|
116
152
|
* console.log(`Server[port:${opt.port}]: download`, input)
|
|
117
153
|
*
|
|
@@ -125,7 +161,7 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
125
161
|
* let streamRead = fs.createReadStream(fp)
|
|
126
162
|
*
|
|
127
163
|
* //fileName
|
|
128
|
-
* let fileName = `1mb
|
|
164
|
+
* let fileName = `1mb中文.7z` //測試支援中文
|
|
129
165
|
*
|
|
130
166
|
* //fileSize
|
|
131
167
|
* let stats = fs.statSync(fp)
|
|
@@ -150,10 +186,19 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
150
186
|
* }
|
|
151
187
|
*
|
|
152
188
|
* })
|
|
189
|
+
* wo.on('error', (err) => {
|
|
190
|
+
* console.log(`Server[port:${opt.port}]: error`, err)
|
|
191
|
+
* })
|
|
153
192
|
* wo.on('handler', (data) => {
|
|
154
193
|
* // console.log(`Server[port:${opt.port}]: handler`, data)
|
|
155
194
|
* })
|
|
156
195
|
*
|
|
196
|
+
* setTimeout(() => {
|
|
197
|
+
* console.log('ms', ms)
|
|
198
|
+
* // console.log('ms', JSON.stringify(ms))
|
|
199
|
+
* wo.stop()
|
|
200
|
+
* }, 3000)
|
|
201
|
+
*
|
|
157
202
|
*/
|
|
158
203
|
function WConverhpServer(opt = {}) {
|
|
159
204
|
|
|
@@ -181,12 +226,6 @@ function WConverhpServer(opt = {}) {
|
|
|
181
226
|
apiName = 'api'
|
|
182
227
|
}
|
|
183
228
|
|
|
184
|
-
//apiUploadSliceName
|
|
185
|
-
let apiUploadSliceName = `${apiName}slc`
|
|
186
|
-
|
|
187
|
-
//apiDownloadName
|
|
188
|
-
let apiDownloadName = `${apiName}dw`
|
|
189
|
-
|
|
190
229
|
//pathUploadTemp
|
|
191
230
|
let pathUploadTemp = get(opt, 'pathUploadTemp')
|
|
192
231
|
if (!isestr(pathUploadTemp)) {
|
|
@@ -196,6 +235,12 @@ function WConverhpServer(opt = {}) {
|
|
|
196
235
|
fsCreateFolder(pathUploadTemp)
|
|
197
236
|
}
|
|
198
237
|
|
|
238
|
+
//tokenType
|
|
239
|
+
let tokenType = get(opt, 'tokenType')
|
|
240
|
+
if (!isestr(tokenType)) {
|
|
241
|
+
tokenType = 'Bearer'
|
|
242
|
+
}
|
|
243
|
+
|
|
199
244
|
//verifyConn
|
|
200
245
|
let verifyConn = get(opt, 'verifyConn')
|
|
201
246
|
if (!isfun(verifyConn)) {
|
|
@@ -331,6 +376,36 @@ function WConverhpServer(opt = {}) {
|
|
|
331
376
|
return pm
|
|
332
377
|
}
|
|
333
378
|
|
|
379
|
+
//procDownloadGetFilename
|
|
380
|
+
async function procDownloadGetFilename(input) {
|
|
381
|
+
// console.log('procDownloadGetFilename', input)
|
|
382
|
+
|
|
383
|
+
//pm, pmm
|
|
384
|
+
let pm = genPm()
|
|
385
|
+
let pmm = genPm()
|
|
386
|
+
|
|
387
|
+
//重新處理回傳結果
|
|
388
|
+
pmm
|
|
389
|
+
.then((output) => {
|
|
390
|
+
|
|
391
|
+
//resolve
|
|
392
|
+
pm.resolve(output)
|
|
393
|
+
|
|
394
|
+
})
|
|
395
|
+
.catch((err) => {
|
|
396
|
+
pm.reject(err)
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
if (true) {
|
|
400
|
+
|
|
401
|
+
//download, 下載檔案
|
|
402
|
+
eeEmit('download-get-filename', input, pmm)
|
|
403
|
+
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return pm
|
|
407
|
+
}
|
|
408
|
+
|
|
334
409
|
//procDownload
|
|
335
410
|
async function procDownload(input) {
|
|
336
411
|
// console.log('procDownload', input)
|
|
@@ -387,12 +462,22 @@ function WConverhpServer(opt = {}) {
|
|
|
387
462
|
//responseU8aStreamWithError
|
|
388
463
|
function responseU8aStreamWithError(res, msg) {
|
|
389
464
|
|
|
465
|
+
//check
|
|
466
|
+
if (!isestr(msg)) {
|
|
467
|
+
console.log('msg', msg)
|
|
468
|
+
console.log(`msg is not an effective string, set msg=''`)
|
|
469
|
+
msg = ''
|
|
470
|
+
}
|
|
471
|
+
|
|
390
472
|
//u8aOut
|
|
391
473
|
let u8aOut = obj2u8arr({
|
|
392
474
|
error: msg,
|
|
393
475
|
})
|
|
394
476
|
// console.log('download u8aOut', u8aOut)
|
|
395
477
|
|
|
478
|
+
//str2b64
|
|
479
|
+
// msg = str2b64(msg) //預期程式內調用皆為英文, 不須轉base64來支援中文
|
|
480
|
+
|
|
396
481
|
return responseU8aStream(res, u8aOut, { returnType: 'error', returnMsg: msg })
|
|
397
482
|
}
|
|
398
483
|
|
|
@@ -546,7 +631,7 @@ function WConverhpServer(opt = {}) {
|
|
|
546
631
|
|
|
547
632
|
//apiUploadSlice
|
|
548
633
|
let apiUploadSlice = {
|
|
549
|
-
path: `/${
|
|
634
|
+
path: `/${apiName}slc`,
|
|
550
635
|
method: 'POST',
|
|
551
636
|
options: {
|
|
552
637
|
payload: {
|
|
@@ -688,7 +773,7 @@ function WConverhpServer(opt = {}) {
|
|
|
688
773
|
|
|
689
774
|
//apiUploadSliceMerge
|
|
690
775
|
let apiUploadSliceMerge = {
|
|
691
|
-
path: `/${
|
|
776
|
+
path: `/${apiName}slcm`,
|
|
692
777
|
method: 'POST',
|
|
693
778
|
options: {
|
|
694
779
|
payload: {
|
|
@@ -696,7 +781,7 @@ function WConverhpServer(opt = {}) {
|
|
|
696
781
|
maxParts: 1000 * 1000 * 1000, //預設為1000, 給予3次方
|
|
697
782
|
timeout: false, //避免請求未完成時中斷
|
|
698
783
|
// output: 'stream',
|
|
699
|
-
parse: true, //前端送obj
|
|
784
|
+
parse: true, //前端送obj過來須自動解析
|
|
700
785
|
},
|
|
701
786
|
timeout: {
|
|
702
787
|
server: false, //關閉伺服器超時
|
|
@@ -806,9 +891,229 @@ function WConverhpServer(opt = {}) {
|
|
|
806
891
|
},
|
|
807
892
|
}
|
|
808
893
|
|
|
894
|
+
//apiDownloadGetFilename
|
|
895
|
+
let apiDownloadGetFilename = {
|
|
896
|
+
path: `/${apiName}dwgfn`,
|
|
897
|
+
method: 'POST',
|
|
898
|
+
options: {
|
|
899
|
+
payload: {
|
|
900
|
+
maxBytes: 1024 * 1024 * 1024 * 1024, //預設為1mb, 調整至1tb, 也就是給予3次方
|
|
901
|
+
maxParts: 1000 * 1000 * 1000, //預設為1000, 給予3次方
|
|
902
|
+
timeout: false, //避免請求未完成時中斷
|
|
903
|
+
// output: 'stream',
|
|
904
|
+
parse: true, //前端送obj過來須自動解析
|
|
905
|
+
},
|
|
906
|
+
timeout: {
|
|
907
|
+
server: false, //關閉伺服器超時
|
|
908
|
+
socket: false, //關閉socket超時
|
|
909
|
+
},
|
|
910
|
+
},
|
|
911
|
+
handler: async function (req, res) {
|
|
912
|
+
// console.log(req, res)
|
|
913
|
+
// console.log('payload', req.payload)
|
|
914
|
+
|
|
915
|
+
//headers
|
|
916
|
+
let headers = get(req, 'headers')
|
|
917
|
+
headers = iseobj(headers) ? headers : ''
|
|
918
|
+
// console.log('headers', headers)
|
|
919
|
+
|
|
920
|
+
//query
|
|
921
|
+
let query = get(req, 'query')
|
|
922
|
+
query = iseobj(query) ? query : ''
|
|
923
|
+
// console.log('query', query)
|
|
924
|
+
|
|
925
|
+
//authorization
|
|
926
|
+
let authorization = get(headers, 'authorization', '')
|
|
927
|
+
authorization = isestr(authorization) ? authorization : ''
|
|
928
|
+
|
|
929
|
+
//check
|
|
930
|
+
if (true) {
|
|
931
|
+
|
|
932
|
+
//verifyConn
|
|
933
|
+
let m = verifyConn({ apiType: 'download-get-filename', authorization, headers, query })
|
|
934
|
+
if (ispm(m)) {
|
|
935
|
+
m = await m
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
//check
|
|
939
|
+
if (m !== true) {
|
|
940
|
+
return responseU8aStreamWithError(res, 'permission denied')
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
//eeEmit
|
|
946
|
+
eeEmit('handler', {
|
|
947
|
+
api: 'apiDownloadGetFilename',
|
|
948
|
+
headers,
|
|
949
|
+
query,
|
|
950
|
+
})
|
|
951
|
+
|
|
952
|
+
//fileId, 從payload接收
|
|
953
|
+
let fileId = get(req, 'payload.fileId', '')
|
|
954
|
+
// console.log('fileId', fileId)
|
|
955
|
+
|
|
956
|
+
//check
|
|
957
|
+
if (!isestr(fileId)) {
|
|
958
|
+
// console.log('invalid fileId in payload')
|
|
959
|
+
return responseU8aStreamWithError(res, 'invalid fileId in payload')
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
//inp
|
|
963
|
+
let inp = { fileId }
|
|
964
|
+
|
|
965
|
+
//procDownloadGetFilename
|
|
966
|
+
let out = {}
|
|
967
|
+
let returnType = ''
|
|
968
|
+
let returnMsg = ''
|
|
969
|
+
await procDownloadGetFilename(inp)
|
|
970
|
+
.then(function(msg) {
|
|
971
|
+
out.success = msg
|
|
972
|
+
returnType = 'success'
|
|
973
|
+
returnMsg = 'need to parse'
|
|
974
|
+
})
|
|
975
|
+
.catch(function(msg) {
|
|
976
|
+
out.error = msg
|
|
977
|
+
returnType = 'error'
|
|
978
|
+
returnMsg = 'need to parse'
|
|
979
|
+
})
|
|
980
|
+
// console.log('out', out)
|
|
981
|
+
|
|
982
|
+
//u8aOut
|
|
983
|
+
let u8aOut = obj2u8arr(out)
|
|
984
|
+
// console.log('u8aOut', u8aOut)
|
|
985
|
+
|
|
986
|
+
return responseU8aStream(res, u8aOut, { returnType, returnMsg })
|
|
987
|
+
},
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
//apiDownloadGetFile
|
|
991
|
+
let apiDownloadGetFile = {
|
|
992
|
+
path: `/${apiName}dwgf`,
|
|
993
|
+
method: 'GET',
|
|
994
|
+
options: {
|
|
995
|
+
timeout: {
|
|
996
|
+
server: false, //關閉伺服器超時
|
|
997
|
+
socket: false, //關閉socket超時
|
|
998
|
+
},
|
|
999
|
+
},
|
|
1000
|
+
handler: async function (req, res) {
|
|
1001
|
+
// console.log(req, res)
|
|
1002
|
+
// console.log('payload', req.payload)
|
|
1003
|
+
|
|
1004
|
+
//headers
|
|
1005
|
+
let headers = get(req, 'headers')
|
|
1006
|
+
headers = iseobj(headers) ? headers : ''
|
|
1007
|
+
// console.log('headers', headers)
|
|
1008
|
+
|
|
1009
|
+
//query
|
|
1010
|
+
let query = get(req, 'query')
|
|
1011
|
+
query = iseobj(query) ? query : ''
|
|
1012
|
+
console.log('query', query)
|
|
1013
|
+
|
|
1014
|
+
//token
|
|
1015
|
+
let token = get(query, 'token', '')
|
|
1016
|
+
token = isestr(token) ? token : ''
|
|
1017
|
+
console.log('token', token)
|
|
1018
|
+
|
|
1019
|
+
//authorization
|
|
1020
|
+
let authorization = ''
|
|
1021
|
+
if (isestr(token)) {
|
|
1022
|
+
authorization = `${tokenType} ${token}`
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
//check
|
|
1026
|
+
if (true) {
|
|
1027
|
+
|
|
1028
|
+
//verifyConn
|
|
1029
|
+
let m = verifyConn({ apiType: 'download-get-file', authorization, headers, query })
|
|
1030
|
+
if (ispm(m)) {
|
|
1031
|
+
m = await m
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
//check
|
|
1035
|
+
if (m !== true) {
|
|
1036
|
+
return responseU8aStreamWithError(res, 'permission denied')
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
//eeEmit
|
|
1042
|
+
eeEmit('handler', {
|
|
1043
|
+
api: 'apiDownloadGetFilename',
|
|
1044
|
+
headers,
|
|
1045
|
+
query,
|
|
1046
|
+
})
|
|
1047
|
+
|
|
1048
|
+
//fileId
|
|
1049
|
+
let fileId = get(query, 'fileId', '')
|
|
1050
|
+
fileId = isestr(fileId) ? fileId : ''
|
|
1051
|
+
console.log('fileId', fileId)
|
|
1052
|
+
|
|
1053
|
+
//check
|
|
1054
|
+
if (!isestr(fileId)) {
|
|
1055
|
+
// console.log('invalid fileId in query')
|
|
1056
|
+
return responseU8aStreamWithError(res, 'invalid fileId in query')
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
//inp
|
|
1060
|
+
let inp = { fileId }
|
|
1061
|
+
|
|
1062
|
+
//procDownload
|
|
1063
|
+
let out = {}
|
|
1064
|
+
await procDownload(inp)
|
|
1065
|
+
.then(function(msg) {
|
|
1066
|
+
out.success = msg
|
|
1067
|
+
})
|
|
1068
|
+
.catch(function(msg) {
|
|
1069
|
+
out.error = msg
|
|
1070
|
+
})
|
|
1071
|
+
// console.log('out', out)
|
|
1072
|
+
|
|
1073
|
+
//return
|
|
1074
|
+
if (haskey(out, 'error')) {
|
|
1075
|
+
// console.log('out.error', out.error)
|
|
1076
|
+
return responseU8aStreamWithError(res, `can not get file from fileId`)
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
//r
|
|
1080
|
+
let r = get(out, 'success')
|
|
1081
|
+
|
|
1082
|
+
//streamRead
|
|
1083
|
+
let streamRead = get(r, 'streamRead')
|
|
1084
|
+
|
|
1085
|
+
// //fileName
|
|
1086
|
+
// let fileName = get(r, 'fileName')
|
|
1087
|
+
// if (!isestr(fileName)) {
|
|
1088
|
+
// return responseU8aStreamWithError(res, 'invalid fileName')
|
|
1089
|
+
// }
|
|
1090
|
+
// fileName = str2b64(fileName) //headers內對中文支援度不佳須用base64傳
|
|
1091
|
+
// console.log('fileName', fileName)
|
|
1092
|
+
|
|
1093
|
+
//fileSize
|
|
1094
|
+
let fileSize = get(r, 'fileSize')
|
|
1095
|
+
if (!isNumber(fileSize)) {
|
|
1096
|
+
return responseU8aStreamWithError(res, 'invalid fileSize')
|
|
1097
|
+
}
|
|
1098
|
+
// fileSize = cstr(fileSize)
|
|
1099
|
+
|
|
1100
|
+
//fileType
|
|
1101
|
+
let fileType = get(r, 'fileType')
|
|
1102
|
+
if (!isestr(fileType)) {
|
|
1103
|
+
return responseU8aStreamWithError(res, 'invalid fileType')
|
|
1104
|
+
}
|
|
1105
|
+
fileType = cstr(fileType)
|
|
1106
|
+
|
|
1107
|
+
return res.response(streamRead)
|
|
1108
|
+
.type(fileType)
|
|
1109
|
+
// .header('Content-Disposition', `attachment; filename="${fileName}"`) //chrome會優先使用header內filename, 但header內支援中文度很差須用base64, 此導致chrome下載檔名只能為base64, 故一律改由前端(browser)先取得真實檔名後直接給予下載檔名, 避免用header提供真實檔名
|
|
1110
|
+
.header('Content-Length', fileSize)
|
|
1111
|
+
},
|
|
1112
|
+
}
|
|
1113
|
+
|
|
809
1114
|
//apiDownload
|
|
810
1115
|
let apiDownload = {
|
|
811
|
-
path: `/${
|
|
1116
|
+
path: `/${apiName}dw`,
|
|
812
1117
|
method: 'POST',
|
|
813
1118
|
options: {
|
|
814
1119
|
payload: {
|
|
@@ -816,7 +1121,7 @@ function WConverhpServer(opt = {}) {
|
|
|
816
1121
|
maxParts: 1000 * 1000 * 1000, //預設為1000, 給予3次方
|
|
817
1122
|
timeout: false, //避免請求未完成時中斷
|
|
818
1123
|
// output: 'stream',
|
|
819
|
-
parse: true, //前端送obj
|
|
1124
|
+
parse: true, //前端送obj過來須自動解析
|
|
820
1125
|
},
|
|
821
1126
|
timeout: {
|
|
822
1127
|
server: false, //關閉伺服器超時
|
|
@@ -891,28 +1196,39 @@ function WConverhpServer(opt = {}) {
|
|
|
891
1196
|
//return
|
|
892
1197
|
if (haskey(out, 'error')) {
|
|
893
1198
|
// console.log('out.error', out.error)
|
|
894
|
-
return responseU8aStreamWithError(res, `can not get file from fileId
|
|
1199
|
+
return responseU8aStreamWithError(res, `can not get file from fileId`)
|
|
895
1200
|
}
|
|
896
1201
|
|
|
897
|
-
//
|
|
1202
|
+
//r
|
|
898
1203
|
let r = get(out, 'success')
|
|
1204
|
+
|
|
1205
|
+
//streamRead
|
|
899
1206
|
let streamRead = get(r, 'streamRead')
|
|
1207
|
+
|
|
1208
|
+
//fileName
|
|
900
1209
|
let fileName = get(r, 'fileName')
|
|
901
1210
|
if (!isestr(fileName)) {
|
|
902
|
-
return res
|
|
1211
|
+
return responseU8aStreamWithError(res, 'invalid fileName')
|
|
903
1212
|
}
|
|
1213
|
+
fileName = str2b64(fileName) //headers內對中文支援度不佳須用base64傳
|
|
1214
|
+
|
|
1215
|
+
//fileSize
|
|
904
1216
|
let fileSize = get(r, 'fileSize')
|
|
905
|
-
if (!
|
|
906
|
-
return res
|
|
1217
|
+
if (!isNumber(fileSize)) {
|
|
1218
|
+
return responseU8aStreamWithError(res, 'invalid fileSize')
|
|
907
1219
|
}
|
|
1220
|
+
// fileSize = cstr(fileSize)
|
|
1221
|
+
|
|
1222
|
+
//fileType
|
|
908
1223
|
let fileType = get(r, 'fileType')
|
|
909
1224
|
if (!isestr(fileType)) {
|
|
910
|
-
return res
|
|
1225
|
+
return responseU8aStreamWithError(res, 'invalid fileType')
|
|
911
1226
|
}
|
|
1227
|
+
fileType = cstr(fileType)
|
|
912
1228
|
|
|
913
1229
|
return res.response(streamRead)
|
|
914
1230
|
.type(fileType)
|
|
915
|
-
.header('Content-Disposition', `attachment; filename="${fileName}"`)
|
|
1231
|
+
.header('Content-Disposition', `attachment; filename="${fileName}"`) //前端(nodejs)用POST下載代表, 可基於header內base64檔名解析出並直接給予檔名, 不用預先取得檔名
|
|
916
1232
|
.header('Content-Length', fileSize)
|
|
917
1233
|
},
|
|
918
1234
|
}
|
|
@@ -948,6 +1264,8 @@ function WConverhpServer(opt = {}) {
|
|
|
948
1264
|
apiMain,
|
|
949
1265
|
apiUploadSlice,
|
|
950
1266
|
apiUploadSliceMerge,
|
|
1267
|
+
apiDownloadGetFilename,
|
|
1268
|
+
apiDownloadGetFile,
|
|
951
1269
|
apiDownload,
|
|
952
1270
|
]
|
|
953
1271
|
}
|
|
@@ -964,8 +1282,7 @@ function WConverhpServer(opt = {}) {
|
|
|
964
1282
|
|
|
965
1283
|
//start
|
|
966
1284
|
if (get(opt, 'serverHapi')) {
|
|
967
|
-
|
|
968
|
-
server.route([apiMain, apiUploadSlice, apiUploadSliceMerge, apiDownload])
|
|
1285
|
+
server.route([apiMain, apiUploadSlice, apiUploadSliceMerge, apiDownloadGetFilename, apiDownloadGetFile, apiDownload])
|
|
969
1286
|
}
|
|
970
1287
|
else {
|
|
971
1288
|
startServer()
|
package/srv.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import _ from 'lodash-es'
|
|
|
3
3
|
import w from 'wsemi'
|
|
4
4
|
import WConverhpServer from './src/WConverhpServer.mjs'
|
|
5
5
|
|
|
6
|
+
|
|
6
7
|
let ms = []
|
|
7
8
|
|
|
8
9
|
let opt = {
|
|
@@ -73,6 +74,28 @@ wo.on('upload', (input, pm) => {
|
|
|
73
74
|
pm.reject('upload error')
|
|
74
75
|
}
|
|
75
76
|
|
|
77
|
+
})
|
|
78
|
+
wo.on('download-get-filename', (input, pm) => {
|
|
79
|
+
console.log(`Server[port:${opt.port}]: download-get-filename`, input)
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
ms.push({ 'download': input })
|
|
83
|
+
|
|
84
|
+
//filename
|
|
85
|
+
let filename = `1mb中文.7z` //測試支援中文
|
|
86
|
+
|
|
87
|
+
//output
|
|
88
|
+
let output = {
|
|
89
|
+
filename
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
pm.resolve(output)
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
console.log('download error', err)
|
|
96
|
+
pm.reject('download error')
|
|
97
|
+
}
|
|
98
|
+
|
|
76
99
|
})
|
|
77
100
|
wo.on('download', (input, pm) => {
|
|
78
101
|
console.log(`Server[port:${opt.port}]: download`, input)
|
|
@@ -87,7 +110,7 @@ wo.on('download', (input, pm) => {
|
|
|
87
110
|
let streamRead = fs.createReadStream(fp)
|
|
88
111
|
|
|
89
112
|
//fileName
|
|
90
|
-
let fileName = `1mb
|
|
113
|
+
let fileName = `1mb中文.7z` //測試支援中文
|
|
91
114
|
|
|
92
115
|
//fileSize
|
|
93
116
|
let stats = fs.statSync(fp)
|
|
@@ -123,7 +146,7 @@ setTimeout(() => {
|
|
|
123
146
|
console.log('ms', ms)
|
|
124
147
|
// console.log('ms', JSON.stringify(ms))
|
|
125
148
|
wo.stop()
|
|
126
|
-
},
|
|
149
|
+
}, 3000)
|
|
127
150
|
|
|
128
151
|
|
|
129
152
|
//node --experimental-modules srv.mjs
|