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
|
@@ -50,6 +50,7 @@ import stream from 'stream'
|
|
|
50
50
|
import Hapi from '@hapi/hapi'
|
|
51
51
|
import Inert from '@hapi/inert' //提供靜態檔案
|
|
52
52
|
import get from 'lodash-es/get.js'
|
|
53
|
+
import isNumber from 'lodash-es/isNumber.js'
|
|
53
54
|
import genPm from 'wsemi/src/genPm.mjs'
|
|
54
55
|
import evem from 'wsemi/src/evem.mjs'
|
|
55
56
|
import iseobj from 'wsemi/src/iseobj.mjs'
|
|
@@ -59,9 +60,10 @@ import ispint from 'wsemi/src/ispint.mjs'
|
|
|
59
60
|
import isearr from 'wsemi/src/isearr.mjs'
|
|
60
61
|
import isbol from 'wsemi/src/isbol.mjs'
|
|
61
62
|
import isfun from 'wsemi/src/isfun.mjs'
|
|
62
|
-
import isnum from 'wsemi/src/isnum.mjs'
|
|
63
63
|
import ispm from 'wsemi/src/ispm.mjs'
|
|
64
64
|
import cint from 'wsemi/src/cint.mjs'
|
|
65
|
+
import cstr from 'wsemi/src/cstr.mjs'
|
|
66
|
+
import str2b64 from 'wsemi/src/str2b64.mjs'
|
|
65
67
|
import haskey from 'wsemi/src/haskey.mjs'
|
|
66
68
|
import obj2u8arr from 'wsemi/src/obj2u8arr.mjs'
|
|
67
69
|
import u8arr2obj from 'wsemi/src/u8arr2obj.mjs'
|
|
@@ -71,6 +73,11 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
71
73
|
// import mergeFiles from './mergeFiles.mjs'
|
|
72
74
|
|
|
73
75
|
|
|
76
|
+
//回傳前端stream時(POST或GET皆可), 前端會須等stream傳完才能判斷是否為大檔或錯誤訊息, 此會導致若回傳超大檔, 會需要對超大檔進行解析會有記憶體上限問題, 故需要通過header提供基本成功或失敗訊息, 讓前端能進行解析判斷
|
|
77
|
+
//回傳前端(nodejs)時, 針對超大檔, 只能用POST並用stream回傳
|
|
78
|
+
//回傳前端(browser)時, 針對超大檔, 可用POST並用stream回傳但還要處理進度條, 若要交由瀏覽器下載器處理, 只能用GET並用stream回傳, 且前端只能用window.location.href或a.href+a.click()下載
|
|
79
|
+
|
|
80
|
+
|
|
74
81
|
/**
|
|
75
82
|
* 建立Hapi伺服器
|
|
76
83
|
*
|
|
@@ -81,6 +88,7 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
81
88
|
* @param {String} [opt.pathStaticFiles='dist'] 輸入當useInert=true時提供瀏覽資料夾字串,預設'dist'
|
|
82
89
|
* @param {String} [opt.apiName='api'] 輸入API名稱字串,預設'api'
|
|
83
90
|
* @param {String} [opt.pathUploadTemp='./uploadTemp'] 輸入暫時存放切片上傳檔案資料夾字串,預設'./uploadTemp'
|
|
91
|
+
* @param {String} [opt.tokenType='Bearer'] 輸入token類型字串,預設'Bearer'
|
|
84
92
|
* @param {Function} [opt.verifyConn=()=>{return true}] 輸入呼叫API時檢測函數,預設()=>{return true}
|
|
85
93
|
* @param {Array} [opt.corsOrigins=['*']] 輸入允許跨域網域陣列,若給予['*']代表允許全部,預設['*']
|
|
86
94
|
* @param {Integer} [opt.delayForBasic=0] 輸入基本API用延遲響應時間,單位ms,預設0
|
|
@@ -89,14 +97,24 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
89
97
|
* @returns {Object} 回傳事件物件,可監聽事件execute、upload、handler
|
|
90
98
|
* @example
|
|
91
99
|
*
|
|
100
|
+
* import fs from 'fs'
|
|
92
101
|
* import _ from 'lodash-es'
|
|
93
|
-
* import
|
|
102
|
+
* import w from 'wsemi'
|
|
103
|
+
* import WConverhpServer from './src/WConverhpServer.mjs'
|
|
104
|
+
*
|
|
105
|
+
* let ms = []
|
|
94
106
|
*
|
|
95
107
|
* let opt = {
|
|
96
108
|
* port: 8080,
|
|
97
109
|
* apiName: 'api',
|
|
98
110
|
* pathStaticFiles: '.', //要存取專案資料夾下web.html, 故不能給dist
|
|
99
|
-
* verifyConn: () => {
|
|
111
|
+
* verifyConn: async ({ apiType, authorization, headers, query }) => {
|
|
112
|
+
* console.log('verifyConn', `apiType[${apiType}]`, `authorization[${authorization}]`)
|
|
113
|
+
* let token = w.strdelleft(authorization, 7) //刪除Bearer
|
|
114
|
+
* if (!w.isestr(token)) {
|
|
115
|
+
* return false
|
|
116
|
+
* }
|
|
117
|
+
* // await w.delay(3000)
|
|
100
118
|
* return true
|
|
101
119
|
* },
|
|
102
120
|
* }
|
|
@@ -114,6 +132,7 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
114
132
|
*
|
|
115
133
|
* if (_.get(input, 'p.d.u8a', null)) {
|
|
116
134
|
* console.log('input.p.d.u8a', input.p.d.u8a)
|
|
135
|
+
* ms.push({ 'input.p.d.u8a': input.p.d.u8a })
|
|
117
136
|
* }
|
|
118
137
|
*
|
|
119
138
|
* let r = {
|
|
@@ -121,13 +140,7 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
121
140
|
* _data: [11, 22.22, 'abc', { x: '21', y: 65.43, z: 'test中文' }],
|
|
122
141
|
* _bin: {
|
|
123
142
|
* name: 'zdata.b2',
|
|
124
|
-
* u8a: new Uint8Array([66, 97, 115]),
|
|
125
|
-
* // name: '100mb.7z',
|
|
126
|
-
* // u8a: new Uint8Array(fs.readFileSync('D:\\開源-JS-006-2-w-converhp\\_temp\\100mb.7z')),
|
|
127
|
-
* // name: '500mb.7z',
|
|
128
|
-
* // u8a: new Uint8Array(fs.readFileSync('D:\\開源-JS-006-2-w-converhp\\_temp\\500mb.7z')),
|
|
129
|
-
* // name: '1000mb.7z',
|
|
130
|
-
* // u8a: new Uint8Array(fs.readFileSync('D:\\開源-JS-006-2-w-converhp\\_temp\\1000mb.7z')),
|
|
143
|
+
* u8a: new Uint8Array([52, 66, 97, 115]),
|
|
131
144
|
* },
|
|
132
145
|
* }
|
|
133
146
|
*
|
|
@@ -150,6 +163,7 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
150
163
|
* console.log(`Server[port:${opt.port}]: upload`, input)
|
|
151
164
|
*
|
|
152
165
|
* try {
|
|
166
|
+
* ms.push({ 'receive and return': input })
|
|
153
167
|
* let output = input
|
|
154
168
|
* pm.resolve(output)
|
|
155
169
|
* }
|
|
@@ -159,6 +173,28 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
159
173
|
* }
|
|
160
174
|
*
|
|
161
175
|
* })
|
|
176
|
+
* wo.on('download-get-filename', (input, pm) => {
|
|
177
|
+
* console.log(`Server[port:${opt.port}]: download-get-filename`, input)
|
|
178
|
+
*
|
|
179
|
+
* try {
|
|
180
|
+
* ms.push({ 'download': input })
|
|
181
|
+
*
|
|
182
|
+
* //filename
|
|
183
|
+
* let filename = `1mb中文.7z` //測試支援中文
|
|
184
|
+
*
|
|
185
|
+
* //output
|
|
186
|
+
* let output = {
|
|
187
|
+
* filename
|
|
188
|
+
* }
|
|
189
|
+
*
|
|
190
|
+
* pm.resolve(output)
|
|
191
|
+
* }
|
|
192
|
+
* catch (err) {
|
|
193
|
+
* console.log('download error', err)
|
|
194
|
+
* pm.reject('download error')
|
|
195
|
+
* }
|
|
196
|
+
*
|
|
197
|
+
* })
|
|
162
198
|
* wo.on('download', (input, pm) => {
|
|
163
199
|
* console.log(`Server[port:${opt.port}]: download`, input)
|
|
164
200
|
*
|
|
@@ -172,7 +208,7 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
172
208
|
* let streamRead = fs.createReadStream(fp)
|
|
173
209
|
*
|
|
174
210
|
* //fileName
|
|
175
|
-
* let fileName = `1mb
|
|
211
|
+
* let fileName = `1mb中文.7z` //測試支援中文
|
|
176
212
|
*
|
|
177
213
|
* //fileSize
|
|
178
214
|
* let stats = fs.statSync(fp)
|
|
@@ -197,10 +233,19 @@ import mergeFiles from './mergeFiles.wk.umd.js'
|
|
|
197
233
|
* }
|
|
198
234
|
*
|
|
199
235
|
* })
|
|
236
|
+
* wo.on('error', (err) => {
|
|
237
|
+
* console.log(`Server[port:${opt.port}]: error`, err)
|
|
238
|
+
* })
|
|
200
239
|
* wo.on('handler', (data) => {
|
|
201
240
|
* // console.log(`Server[port:${opt.port}]: handler`, data)
|
|
202
241
|
* })
|
|
203
242
|
*
|
|
243
|
+
* setTimeout(() => {
|
|
244
|
+
* console.log('ms', ms)
|
|
245
|
+
* // console.log('ms', JSON.stringify(ms))
|
|
246
|
+
* wo.stop()
|
|
247
|
+
* }, 3000)
|
|
248
|
+
*
|
|
204
249
|
*/
|
|
205
250
|
function WConverhpServer(opt = {}) {
|
|
206
251
|
|
|
@@ -228,12 +273,6 @@ function WConverhpServer(opt = {}) {
|
|
|
228
273
|
apiName = 'api'
|
|
229
274
|
}
|
|
230
275
|
|
|
231
|
-
//apiUploadSliceName
|
|
232
|
-
let apiUploadSliceName = `${apiName}slc`
|
|
233
|
-
|
|
234
|
-
//apiDownloadName
|
|
235
|
-
let apiDownloadName = `${apiName}dw`
|
|
236
|
-
|
|
237
276
|
//pathUploadTemp
|
|
238
277
|
let pathUploadTemp = get(opt, 'pathUploadTemp')
|
|
239
278
|
if (!isestr(pathUploadTemp)) {
|
|
@@ -243,6 +282,12 @@ function WConverhpServer(opt = {}) {
|
|
|
243
282
|
fsCreateFolder(pathUploadTemp)
|
|
244
283
|
}
|
|
245
284
|
|
|
285
|
+
//tokenType
|
|
286
|
+
let tokenType = get(opt, 'tokenType')
|
|
287
|
+
if (!isestr(tokenType)) {
|
|
288
|
+
tokenType = 'Bearer'
|
|
289
|
+
}
|
|
290
|
+
|
|
246
291
|
//verifyConn
|
|
247
292
|
let verifyConn = get(opt, 'verifyConn')
|
|
248
293
|
if (!isfun(verifyConn)) {
|
|
@@ -378,6 +423,36 @@ function WConverhpServer(opt = {}) {
|
|
|
378
423
|
return pm
|
|
379
424
|
}
|
|
380
425
|
|
|
426
|
+
//procDownloadGetFilename
|
|
427
|
+
async function procDownloadGetFilename(input) {
|
|
428
|
+
// console.log('procDownloadGetFilename', input)
|
|
429
|
+
|
|
430
|
+
//pm, pmm
|
|
431
|
+
let pm = genPm()
|
|
432
|
+
let pmm = genPm()
|
|
433
|
+
|
|
434
|
+
//重新處理回傳結果
|
|
435
|
+
pmm
|
|
436
|
+
.then((output) => {
|
|
437
|
+
|
|
438
|
+
//resolve
|
|
439
|
+
pm.resolve(output)
|
|
440
|
+
|
|
441
|
+
})
|
|
442
|
+
.catch((err) => {
|
|
443
|
+
pm.reject(err)
|
|
444
|
+
})
|
|
445
|
+
|
|
446
|
+
if (true) {
|
|
447
|
+
|
|
448
|
+
//download, 下載檔案
|
|
449
|
+
eeEmit('download-get-filename', input, pmm)
|
|
450
|
+
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return pm
|
|
454
|
+
}
|
|
455
|
+
|
|
381
456
|
//procDownload
|
|
382
457
|
async function procDownload(input) {
|
|
383
458
|
// console.log('procDownload', input)
|
|
@@ -434,12 +509,22 @@ function WConverhpServer(opt = {}) {
|
|
|
434
509
|
//responseU8aStreamWithError
|
|
435
510
|
function responseU8aStreamWithError(res, msg) {
|
|
436
511
|
|
|
512
|
+
//check
|
|
513
|
+
if (!isestr(msg)) {
|
|
514
|
+
console.log('msg', msg)
|
|
515
|
+
console.log(`msg is not an effective string, set msg=''`)
|
|
516
|
+
msg = ''
|
|
517
|
+
}
|
|
518
|
+
|
|
437
519
|
//u8aOut
|
|
438
520
|
let u8aOut = obj2u8arr({
|
|
439
521
|
error: msg,
|
|
440
522
|
})
|
|
441
523
|
// console.log('download u8aOut', u8aOut)
|
|
442
524
|
|
|
525
|
+
//str2b64
|
|
526
|
+
// msg = str2b64(msg) //預期程式內調用皆為英文, 不須轉base64來支援中文
|
|
527
|
+
|
|
443
528
|
return responseU8aStream(res, u8aOut, { returnType: 'error', returnMsg: msg })
|
|
444
529
|
}
|
|
445
530
|
|
|
@@ -593,7 +678,7 @@ function WConverhpServer(opt = {}) {
|
|
|
593
678
|
|
|
594
679
|
//apiUploadSlice
|
|
595
680
|
let apiUploadSlice = {
|
|
596
|
-
path: `/${
|
|
681
|
+
path: `/${apiName}slc`,
|
|
597
682
|
method: 'POST',
|
|
598
683
|
options: {
|
|
599
684
|
payload: {
|
|
@@ -735,7 +820,7 @@ function WConverhpServer(opt = {}) {
|
|
|
735
820
|
|
|
736
821
|
//apiUploadSliceMerge
|
|
737
822
|
let apiUploadSliceMerge = {
|
|
738
|
-
path: `/${
|
|
823
|
+
path: `/${apiName}slcm`,
|
|
739
824
|
method: 'POST',
|
|
740
825
|
options: {
|
|
741
826
|
payload: {
|
|
@@ -743,7 +828,7 @@ function WConverhpServer(opt = {}) {
|
|
|
743
828
|
maxParts: 1000 * 1000 * 1000, //預設為1000, 給予3次方
|
|
744
829
|
timeout: false, //避免請求未完成時中斷
|
|
745
830
|
// output: 'stream',
|
|
746
|
-
parse: true, //前端送obj
|
|
831
|
+
parse: true, //前端送obj過來須自動解析
|
|
747
832
|
},
|
|
748
833
|
timeout: {
|
|
749
834
|
server: false, //關閉伺服器超時
|
|
@@ -853,9 +938,229 @@ function WConverhpServer(opt = {}) {
|
|
|
853
938
|
},
|
|
854
939
|
}
|
|
855
940
|
|
|
941
|
+
//apiDownloadGetFilename
|
|
942
|
+
let apiDownloadGetFilename = {
|
|
943
|
+
path: `/${apiName}dwgfn`,
|
|
944
|
+
method: 'POST',
|
|
945
|
+
options: {
|
|
946
|
+
payload: {
|
|
947
|
+
maxBytes: 1024 * 1024 * 1024 * 1024, //預設為1mb, 調整至1tb, 也就是給予3次方
|
|
948
|
+
maxParts: 1000 * 1000 * 1000, //預設為1000, 給予3次方
|
|
949
|
+
timeout: false, //避免請求未完成時中斷
|
|
950
|
+
// output: 'stream',
|
|
951
|
+
parse: true, //前端送obj過來須自動解析
|
|
952
|
+
},
|
|
953
|
+
timeout: {
|
|
954
|
+
server: false, //關閉伺服器超時
|
|
955
|
+
socket: false, //關閉socket超時
|
|
956
|
+
},
|
|
957
|
+
},
|
|
958
|
+
handler: async function (req, res) {
|
|
959
|
+
// console.log(req, res)
|
|
960
|
+
// console.log('payload', req.payload)
|
|
961
|
+
|
|
962
|
+
//headers
|
|
963
|
+
let headers = get(req, 'headers')
|
|
964
|
+
headers = iseobj(headers) ? headers : ''
|
|
965
|
+
// console.log('headers', headers)
|
|
966
|
+
|
|
967
|
+
//query
|
|
968
|
+
let query = get(req, 'query')
|
|
969
|
+
query = iseobj(query) ? query : ''
|
|
970
|
+
// console.log('query', query)
|
|
971
|
+
|
|
972
|
+
//authorization
|
|
973
|
+
let authorization = get(headers, 'authorization', '')
|
|
974
|
+
authorization = isestr(authorization) ? authorization : ''
|
|
975
|
+
|
|
976
|
+
//check
|
|
977
|
+
if (true) {
|
|
978
|
+
|
|
979
|
+
//verifyConn
|
|
980
|
+
let m = verifyConn({ apiType: 'download-get-filename', authorization, headers, query })
|
|
981
|
+
if (ispm(m)) {
|
|
982
|
+
m = await m
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
//check
|
|
986
|
+
if (m !== true) {
|
|
987
|
+
return responseU8aStreamWithError(res, 'permission denied')
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
//eeEmit
|
|
993
|
+
eeEmit('handler', {
|
|
994
|
+
api: 'apiDownloadGetFilename',
|
|
995
|
+
headers,
|
|
996
|
+
query,
|
|
997
|
+
})
|
|
998
|
+
|
|
999
|
+
//fileId, 從payload接收
|
|
1000
|
+
let fileId = get(req, 'payload.fileId', '')
|
|
1001
|
+
// console.log('fileId', fileId)
|
|
1002
|
+
|
|
1003
|
+
//check
|
|
1004
|
+
if (!isestr(fileId)) {
|
|
1005
|
+
// console.log('invalid fileId in payload')
|
|
1006
|
+
return responseU8aStreamWithError(res, 'invalid fileId in payload')
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
//inp
|
|
1010
|
+
let inp = { fileId }
|
|
1011
|
+
|
|
1012
|
+
//procDownloadGetFilename
|
|
1013
|
+
let out = {}
|
|
1014
|
+
let returnType = ''
|
|
1015
|
+
let returnMsg = ''
|
|
1016
|
+
await procDownloadGetFilename(inp)
|
|
1017
|
+
.then(function(msg) {
|
|
1018
|
+
out.success = msg
|
|
1019
|
+
returnType = 'success'
|
|
1020
|
+
returnMsg = 'need to parse'
|
|
1021
|
+
})
|
|
1022
|
+
.catch(function(msg) {
|
|
1023
|
+
out.error = msg
|
|
1024
|
+
returnType = 'error'
|
|
1025
|
+
returnMsg = 'need to parse'
|
|
1026
|
+
})
|
|
1027
|
+
// console.log('out', out)
|
|
1028
|
+
|
|
1029
|
+
//u8aOut
|
|
1030
|
+
let u8aOut = obj2u8arr(out)
|
|
1031
|
+
// console.log('u8aOut', u8aOut)
|
|
1032
|
+
|
|
1033
|
+
return responseU8aStream(res, u8aOut, { returnType, returnMsg })
|
|
1034
|
+
},
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
//apiDownloadGetFile
|
|
1038
|
+
let apiDownloadGetFile = {
|
|
1039
|
+
path: `/${apiName}dwgf`,
|
|
1040
|
+
method: 'GET',
|
|
1041
|
+
options: {
|
|
1042
|
+
timeout: {
|
|
1043
|
+
server: false, //關閉伺服器超時
|
|
1044
|
+
socket: false, //關閉socket超時
|
|
1045
|
+
},
|
|
1046
|
+
},
|
|
1047
|
+
handler: async function (req, res) {
|
|
1048
|
+
// console.log(req, res)
|
|
1049
|
+
// console.log('payload', req.payload)
|
|
1050
|
+
|
|
1051
|
+
//headers
|
|
1052
|
+
let headers = get(req, 'headers')
|
|
1053
|
+
headers = iseobj(headers) ? headers : ''
|
|
1054
|
+
// console.log('headers', headers)
|
|
1055
|
+
|
|
1056
|
+
//query
|
|
1057
|
+
let query = get(req, 'query')
|
|
1058
|
+
query = iseobj(query) ? query : ''
|
|
1059
|
+
console.log('query', query)
|
|
1060
|
+
|
|
1061
|
+
//token
|
|
1062
|
+
let token = get(query, 'token', '')
|
|
1063
|
+
token = isestr(token) ? token : ''
|
|
1064
|
+
console.log('token', token)
|
|
1065
|
+
|
|
1066
|
+
//authorization
|
|
1067
|
+
let authorization = ''
|
|
1068
|
+
if (isestr(token)) {
|
|
1069
|
+
authorization = `${tokenType} ${token}`
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
//check
|
|
1073
|
+
if (true) {
|
|
1074
|
+
|
|
1075
|
+
//verifyConn
|
|
1076
|
+
let m = verifyConn({ apiType: 'download-get-file', authorization, headers, query })
|
|
1077
|
+
if (ispm(m)) {
|
|
1078
|
+
m = await m
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
//check
|
|
1082
|
+
if (m !== true) {
|
|
1083
|
+
return responseU8aStreamWithError(res, 'permission denied')
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
//eeEmit
|
|
1089
|
+
eeEmit('handler', {
|
|
1090
|
+
api: 'apiDownloadGetFilename',
|
|
1091
|
+
headers,
|
|
1092
|
+
query,
|
|
1093
|
+
})
|
|
1094
|
+
|
|
1095
|
+
//fileId
|
|
1096
|
+
let fileId = get(query, 'fileId', '')
|
|
1097
|
+
fileId = isestr(fileId) ? fileId : ''
|
|
1098
|
+
console.log('fileId', fileId)
|
|
1099
|
+
|
|
1100
|
+
//check
|
|
1101
|
+
if (!isestr(fileId)) {
|
|
1102
|
+
// console.log('invalid fileId in query')
|
|
1103
|
+
return responseU8aStreamWithError(res, 'invalid fileId in query')
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
//inp
|
|
1107
|
+
let inp = { fileId }
|
|
1108
|
+
|
|
1109
|
+
//procDownload
|
|
1110
|
+
let out = {}
|
|
1111
|
+
await procDownload(inp)
|
|
1112
|
+
.then(function(msg) {
|
|
1113
|
+
out.success = msg
|
|
1114
|
+
})
|
|
1115
|
+
.catch(function(msg) {
|
|
1116
|
+
out.error = msg
|
|
1117
|
+
})
|
|
1118
|
+
// console.log('out', out)
|
|
1119
|
+
|
|
1120
|
+
//return
|
|
1121
|
+
if (haskey(out, 'error')) {
|
|
1122
|
+
// console.log('out.error', out.error)
|
|
1123
|
+
return responseU8aStreamWithError(res, `can not get file from fileId`)
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
//r
|
|
1127
|
+
let r = get(out, 'success')
|
|
1128
|
+
|
|
1129
|
+
//streamRead
|
|
1130
|
+
let streamRead = get(r, 'streamRead')
|
|
1131
|
+
|
|
1132
|
+
// //fileName
|
|
1133
|
+
// let fileName = get(r, 'fileName')
|
|
1134
|
+
// if (!isestr(fileName)) {
|
|
1135
|
+
// return responseU8aStreamWithError(res, 'invalid fileName')
|
|
1136
|
+
// }
|
|
1137
|
+
// fileName = str2b64(fileName) //headers內對中文支援度不佳須用base64傳
|
|
1138
|
+
// console.log('fileName', fileName)
|
|
1139
|
+
|
|
1140
|
+
//fileSize
|
|
1141
|
+
let fileSize = get(r, 'fileSize')
|
|
1142
|
+
if (!isNumber(fileSize)) {
|
|
1143
|
+
return responseU8aStreamWithError(res, 'invalid fileSize')
|
|
1144
|
+
}
|
|
1145
|
+
// fileSize = cstr(fileSize)
|
|
1146
|
+
|
|
1147
|
+
//fileType
|
|
1148
|
+
let fileType = get(r, 'fileType')
|
|
1149
|
+
if (!isestr(fileType)) {
|
|
1150
|
+
return responseU8aStreamWithError(res, 'invalid fileType')
|
|
1151
|
+
}
|
|
1152
|
+
fileType = cstr(fileType)
|
|
1153
|
+
|
|
1154
|
+
return res.response(streamRead)
|
|
1155
|
+
.type(fileType)
|
|
1156
|
+
// .header('Content-Disposition', `attachment; filename="${fileName}"`) //chrome會優先使用header內filename, 但header內支援中文度很差須用base64, 此導致chrome下載檔名只能為base64, 故一律改由前端(browser)先取得真實檔名後直接給予下載檔名, 避免用header提供真實檔名
|
|
1157
|
+
.header('Content-Length', fileSize)
|
|
1158
|
+
},
|
|
1159
|
+
}
|
|
1160
|
+
|
|
856
1161
|
//apiDownload
|
|
857
1162
|
let apiDownload = {
|
|
858
|
-
path: `/${
|
|
1163
|
+
path: `/${apiName}dw`,
|
|
859
1164
|
method: 'POST',
|
|
860
1165
|
options: {
|
|
861
1166
|
payload: {
|
|
@@ -863,7 +1168,7 @@ function WConverhpServer(opt = {}) {
|
|
|
863
1168
|
maxParts: 1000 * 1000 * 1000, //預設為1000, 給予3次方
|
|
864
1169
|
timeout: false, //避免請求未完成時中斷
|
|
865
1170
|
// output: 'stream',
|
|
866
|
-
parse: true, //前端送obj
|
|
1171
|
+
parse: true, //前端送obj過來須自動解析
|
|
867
1172
|
},
|
|
868
1173
|
timeout: {
|
|
869
1174
|
server: false, //關閉伺服器超時
|
|
@@ -938,28 +1243,39 @@ function WConverhpServer(opt = {}) {
|
|
|
938
1243
|
//return
|
|
939
1244
|
if (haskey(out, 'error')) {
|
|
940
1245
|
// console.log('out.error', out.error)
|
|
941
|
-
return responseU8aStreamWithError(res, `can not get file from fileId
|
|
1246
|
+
return responseU8aStreamWithError(res, `can not get file from fileId`)
|
|
942
1247
|
}
|
|
943
1248
|
|
|
944
|
-
//
|
|
1249
|
+
//r
|
|
945
1250
|
let r = get(out, 'success')
|
|
1251
|
+
|
|
1252
|
+
//streamRead
|
|
946
1253
|
let streamRead = get(r, 'streamRead')
|
|
1254
|
+
|
|
1255
|
+
//fileName
|
|
947
1256
|
let fileName = get(r, 'fileName')
|
|
948
1257
|
if (!isestr(fileName)) {
|
|
949
|
-
return res
|
|
1258
|
+
return responseU8aStreamWithError(res, 'invalid fileName')
|
|
950
1259
|
}
|
|
1260
|
+
fileName = str2b64(fileName) //headers內對中文支援度不佳須用base64傳
|
|
1261
|
+
|
|
1262
|
+
//fileSize
|
|
951
1263
|
let fileSize = get(r, 'fileSize')
|
|
952
|
-
if (!
|
|
953
|
-
return res
|
|
1264
|
+
if (!isNumber(fileSize)) {
|
|
1265
|
+
return responseU8aStreamWithError(res, 'invalid fileSize')
|
|
954
1266
|
}
|
|
1267
|
+
// fileSize = cstr(fileSize)
|
|
1268
|
+
|
|
1269
|
+
//fileType
|
|
955
1270
|
let fileType = get(r, 'fileType')
|
|
956
1271
|
if (!isestr(fileType)) {
|
|
957
|
-
return res
|
|
1272
|
+
return responseU8aStreamWithError(res, 'invalid fileType')
|
|
958
1273
|
}
|
|
1274
|
+
fileType = cstr(fileType)
|
|
959
1275
|
|
|
960
1276
|
return res.response(streamRead)
|
|
961
1277
|
.type(fileType)
|
|
962
|
-
.header('Content-Disposition', `attachment; filename="${fileName}"`)
|
|
1278
|
+
.header('Content-Disposition', `attachment; filename="${fileName}"`) //前端(nodejs)用POST下載代表, 可基於header內base64檔名解析出並直接給予檔名, 不用預先取得檔名
|
|
963
1279
|
.header('Content-Length', fileSize)
|
|
964
1280
|
},
|
|
965
1281
|
}
|
|
@@ -995,6 +1311,8 @@ function WConverhpServer(opt = {}) {
|
|
|
995
1311
|
apiMain,
|
|
996
1312
|
apiUploadSlice,
|
|
997
1313
|
apiUploadSliceMerge,
|
|
1314
|
+
apiDownloadGetFilename,
|
|
1315
|
+
apiDownloadGetFile,
|
|
998
1316
|
apiDownload,
|
|
999
1317
|
]
|
|
1000
1318
|
}
|
|
@@ -1011,8 +1329,7 @@ function WConverhpServer(opt = {}) {
|
|
|
1011
1329
|
|
|
1012
1330
|
//start
|
|
1013
1331
|
if (get(opt, 'serverHapi')) {
|
|
1014
|
-
|
|
1015
|
-
server.route([apiMain, apiUploadSlice, apiUploadSliceMerge, apiDownload])
|
|
1332
|
+
server.route([apiMain, apiUploadSlice, apiUploadSliceMerge, apiDownloadGetFilename, apiDownloadGetFile, apiDownload])
|
|
1016
1333
|
}
|
|
1017
1334
|
else {
|
|
1018
1335
|
startServer()
|
|
@@ -1045,7 +1362,7 @@ export default WConverhpServer
|
|
|
1045
1362
|
<br class="clear">
|
|
1046
1363
|
|
|
1047
1364
|
<footer>
|
|
1048
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on
|
|
1365
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Wed Apr 09 2025 13:07:53 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
1049
1366
|
</footer>
|
|
1050
1367
|
|
|
1051
1368
|
<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
|
|
74
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.2</a> on Wed Apr 09 2025 13:07:53 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
package/scld.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import fs from 'fs'
|
|
3
|
-
import _ from 'lodash-es'
|
|
4
|
-
import w from 'wsemi'
|
|
1
|
+
// import path from 'path'
|
|
2
|
+
// import fs from 'fs'
|
|
3
|
+
// import _ from 'lodash-es'
|
|
4
|
+
// import w from 'wsemi'
|
|
5
5
|
import FormData from 'form-data'
|
|
6
6
|
import WConverhpClient from './src/WConverhpClient.mjs'
|
|
7
7
|
|
|
@@ -35,7 +35,7 @@ function downloadLargeFile() {
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
|
-
fdDownload: './',
|
|
38
|
+
fdDownload: './', //於後端nodejs環境才能提供
|
|
39
39
|
})
|
|
40
40
|
.then(function(res) {
|
|
41
41
|
console.log('client web: download: then', res)
|