w-converhp 1.0.39 → 2.0.0

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.
@@ -1,25 +1,24 @@
1
- // import axiosNode from 'axios/lib/axios.js'
2
- // import axiosNode from 'axios'
3
- // import axiosBrowser from 'axios/dist/axios.min.js'
4
- // import axiosBrowser from 'axios/dist/esm/axios.min.js'
5
- import axios from 'axios' //axios已可自動依照調用環境切換
1
+ import axios from 'axios'
6
2
  // import * as FormData from 'form-data/lib/form_data.js'
7
3
  // import FormData from 'form-data'
8
- import get from 'lodash-es/get'
9
- import each from 'lodash-es/each'
10
- // import getGlobal from 'wsemi/src/getGlobal.mjs'
4
+ import get from 'lodash-es/get.js'
11
5
  import isWindow from 'wsemi/src/isWindow.mjs'
12
6
  import genPm from 'wsemi/src/genPm.mjs'
13
7
  import genID from 'wsemi/src/genID.mjs'
14
- import Evem from 'wsemi/src/evem.mjs'
15
- import pm2resolve from 'wsemi/src/pm2resolve.mjs'
8
+ import haskey from 'wsemi/src/haskey.mjs'
16
9
  import isfun from 'wsemi/src/isfun.mjs'
17
10
  import ispint from 'wsemi/src/ispint.mjs'
18
- import isearr from 'wsemi/src/isearr.mjs'
11
+ import isp0int from 'wsemi/src/isp0int.mjs'
12
+ import isestr from 'wsemi/src/isestr.mjs'
13
+ import isobj from 'wsemi/src/isobj.mjs'
14
+ import iseobj from 'wsemi/src/iseobj.mjs'
15
+ import cint from 'wsemi/src/cint.mjs'
19
16
  import strright from 'wsemi/src/strright.mjs'
20
17
  import blob2u8arr from 'wsemi/src/blob2u8arr.mjs'
21
18
  import obj2u8arr from 'wsemi/src/obj2u8arr.mjs'
22
19
  import u8arr2obj from 'wsemi/src/u8arr2obj.mjs'
20
+ import pmConvertResolve from 'wsemi/src/pmConvertResolve.mjs'
21
+ import now2strp from 'wsemi/src/now2strp.mjs'
23
22
 
24
23
 
25
24
  /**
@@ -28,15 +27,16 @@ import u8arr2obj from 'wsemi/src/u8arr2obj.mjs'
28
27
  * @class
29
28
  * @param {Object} opt 輸入設定參數物件
30
29
  * @param {String} [opt.url='http://localhost:8080'] 輸入Hapi伺服器網址,預設為'http://localhost:8080'
31
- * @param {String} [opt.apiName='api'] 輸入api名稱,預設為'api'
32
- * @param {Integer} [opt.timePolling=2000] 輸入輪詢間隔時間整數,單位為毫秒,預設為2000
30
+ * @param {String} [opt.apiName='api'] 輸入API名稱字串,預設'api'
31
+ * @param {Integer} [opt.sizeSlice=1024*1024] 輸入切片上傳檔案之切片檔案大小整數,單位為Byte,預設為1024*1024
33
32
  * @param {Integer} [opt.retry=3] 輸入傳輸失敗重試次數整數,預設為3
34
- * @returns {Object} 回傳通訊物件,可監聽事件open、openOnce、close、error、reconn、broadcast、deliver,可使用函數execute、broadcast、deliver
33
+ * @returns {Object} 回傳通訊物件,可使用函數execute、upload
35
34
  * @example
36
35
  *
37
36
  * import WConverhpClient from 'w-converhp/dist/w-converhp-client.umd.js'
38
37
  *
39
38
  * let opt = {
39
+ * FormData,
40
40
  * url: 'http://localhost:8080',
41
41
  * apiName: 'api',
42
42
  * }
@@ -44,211 +44,219 @@ import u8arr2obj from 'wsemi/src/u8arr2obj.mjs'
44
44
  * //new
45
45
  * let wo = new WConverhpClient(opt)
46
46
  *
47
- * wo.on('open', function() {
48
- * console.log('client nodejs: open')
49
- * })
50
- * wo.on('openOnce', function() {
51
- * console.log('client nodejs: openOnce')
47
+ * async function execute(name, u8a) {
52
48
  *
53
49
  * //p
54
- * let name = 'zdata.b1'
55
50
  * let p = {
56
51
  * a: 12,
57
52
  * b: 34.56,
58
53
  * c: 'test中文',
59
54
  * d: {
60
- * name: name,
61
- * u8a: new Uint8Array([66, 97, 115]),
62
- * //u8a: new Uint8Array(fs.readFileSync('C:\\Users\\Administrator\\Desktop\\'+name)),
63
- * }
55
+ * name,
56
+ * u8a,
57
+ * },
64
58
  * }
59
+ * console.log('p', p)
65
60
  *
66
61
  * //execute
67
- * wo.execute('add', { p },
62
+ * await wo.execute('add', { p },
68
63
  * function (prog, p, m) {
69
- * console.log('client nodejs: execute: prog', prog, p, m)
64
+ * console.log('client web: execute: prog', prog, p, m)
70
65
  * })
71
66
  * .then(function(r) {
72
- * console.log('client nodejs: execute: add', r)
67
+ * console.log('client web: execute: add', r)
68
+ * console.log('r._bin.name', r._bin.name, 'r._bin.u8a', r._bin.u8a)
69
+ * // w.downloadFileFromU8Arr(r._bin.name, r._bin.u8a)
73
70
  * })
74
- * .catch(function(err) {
75
- * console.log('client nodejs: execute: catch', err)
71
+ * .catch(function (err) {
72
+ * console.log('client web: execute: catch', err)
76
73
  * })
77
74
  *
78
- * //broadcast
79
- * wo.broadcast('client nodejs broadcast hi', function (prog) {
80
- * console.log('client nodejs: broadcast: prog', prog)
81
- * })
82
- * .catch(function(err) {
83
- * console.log('client nodejs: broadcast: catch', err)
84
- * })
75
+ * }
85
76
  *
86
- * //deliver
87
- * wo.deliver('client nodejs deliver hi', function (prog) {
88
- * console.log('client nodejs: deliver: prog', prog)
89
- * })
90
- * .catch(function(err) {
91
- * console.log('client nodejs: deliver: catch', err)
92
- * })
77
+ * function executeWithU8a() {
78
+ * let core = async() => {
79
+ *
80
+ * //u8a
81
+ * let u8a = new Uint8Array([66, 97, 115])
82
+ * console.log('executeWithU8a u8a', u8a)
83
+ *
84
+ * //execute
85
+ * await execute('zdata.b1', u8a)
86
+ *
87
+ * }
88
+ * core()
89
+ * }
90
+ * executeWithU8a()
91
+ *
92
+ * function executeWithFile() {
93
+ * let core = async() => {
94
+ *
95
+ * //u8a
96
+ * let u8a = new Uint8Array(fs.readFileSync('../_data/10mb.7z'))
97
+ * console.log('executeWithFile u8a', u8a)
93
98
  *
94
- * })
95
- * wo.on('close', function() {
96
- * console.log('client nodejs: close')
97
- * })
98
- * wo.on('error', function(err) {
99
- * console.log('client nodejs: error', err)
100
- * })
101
- * wo.on('reconn', function() {
102
- * console.log('client nodejs: reconn')
103
- * })
104
- * wo.on('broadcast', function(data) {
105
- * console.log('client nodejs: broadcast', data)
106
- * })
107
- * wo.on('deliver', function(data) {
108
- * console.log('client nodejs: deliver', data)
109
- * })
99
+ * //execute
100
+ * await execute('10mb.7z', u8a)
101
+ *
102
+ * }
103
+ * core()
104
+ * }
105
+ * executeWithFile()
106
+ *
107
+ * function uploadLargeFile() {
108
+ * let core = async() => {
109
+ *
110
+ * //u8a
111
+ * let u8a = new Uint8Array(fs.readFileSync('../_data/1000mb.7z'))
112
+ * console.log('u8a.length', u8a.length)
113
+ * console.log('uploadLargeFile u8a', u8a)
114
+ *
115
+ * await wo.upload('1000mb.7z', u8a,
116
+ * function (prog, p, m) {
117
+ * console.log('client web: upload: prog', prog, p, m)
118
+ * })
119
+ * .then(function(res) {
120
+ * console.log('client web: upload: then', res)
121
+ * })
122
+ * .catch(function (err) {
123
+ * console.log('client web: upload: catch', err)
124
+ * })
125
+ *
126
+ * }
127
+ * core()
128
+ * }
129
+ * uploadLargeFile()
110
130
  *
111
131
  */
112
132
  function WConverhpClient(opt) {
113
- let clientId = genID() //供伺服器識別真實連線使用者
114
-
115
133
 
116
- //ee, ev
117
- let ee = new Evem()
118
- //let ev = new Evem()
134
+ //_url
135
+ let _url = get(opt, 'url')
136
+ if (!isestr(_url)) {
137
+ _url = 'http://localhost:8080'
138
+ }
119
139
 
140
+ //apiName
141
+ let apiName = get(opt, 'apiName')
142
+ if (!isestr(apiName)) {
143
+ apiName = 'api'
144
+ }
120
145
 
121
- //eeEmit
122
- function eeEmit(name, ...args) {
123
- setTimeout(() => {
124
- ee.emit(name, ...args)
125
- }, 1)
146
+ //url
147
+ let url = ''
148
+ if (strright(_url, 1) === '/') {
149
+ url = _url + apiName
150
+ }
151
+ else {
152
+ url = _url + '/' + apiName
126
153
  }
127
154
 
155
+ //sizeSlice
156
+ let sizeSlice = get(opt, 'sizeSlice')
157
+ if (!ispint(sizeSlice)) {
158
+ sizeSlice = 1024 * 1024 //1m
159
+ }
128
160
 
129
- function core() {
161
+ //retry
162
+ let retry = get(opt, 'retry')
163
+ if (!isp0int(retry)) {
164
+ retry = 3
165
+ }
130
166
 
167
+ //env
168
+ let env = isWindow() ? 'browser' : 'nodejs'
169
+ // console.log('env', env)
131
170
 
132
- //default
133
- if (!opt.url) {
134
- opt.url = 'http://localhost:8080'
171
+ //res2u8arr
172
+ async function res2u8arr(bb) {
173
+ //blob(in browser) or buffer(in nodejs) to u8a
174
+ let u8a
175
+ if (env === 'browser') {
176
+ u8a = await blob2u8arr(bb)
135
177
  }
136
- if (!opt.apiName) {
137
- opt.apiName = 'api'
138
- }
139
- if (!opt.timePolling) {
140
- opt.timePolling = 2000
141
- }
142
- if (!opt.retry) {
143
- opt.retry = 3
178
+ else {
179
+ u8a = new Uint8Array(bb)
144
180
  }
181
+ return u8a
182
+ }
145
183
 
146
-
147
- //url
148
- let url = ''
149
- if (strright(opt.url, 1) === '/') {
150
- url = opt.url + opt.apiName
184
+ //u8arr2bb
185
+ function u8arr2bb(u8a) {
186
+ //u8a to blob(in browser) or buffer(in nodejs)
187
+ let bb
188
+ if (env === 'browser') {
189
+ bb = new Blob([u8a.buffer])
151
190
  }
152
- else {
153
- url = opt.url + '/' + opt.apiName
191
+ else { //nodejs
192
+ bb = Buffer.from(u8a)
154
193
  }
194
+ return bb
195
+ }
155
196
 
197
+ //send
198
+ function send(type, pkg, opt = {}) {
156
199
 
157
- /**
158
- * Hapi監聽開啟事件
159
- *
160
- * @memberof WConverhpClient
161
- * @example
162
- * wo.on('open', function() {
163
- * ...
164
- * })
165
- */
166
- function onOpen() {} onOpen()
167
- function open() {
168
- eeEmit('open')
200
+ //headers
201
+ let headers = get(opt, 'headers')
202
+ if (!isobj(headers)) {
203
+ headers = {}
169
204
  }
205
+ // console.log('headers', headers)
170
206
 
171
-
172
- /**
173
- * Hapi監聽第一次開啟事件
174
- *
175
- * @memberof WConverhpClient
176
- * @example
177
- * wo.on('openOnce', function() {
178
- * ...
179
- * })
180
- */
181
- function onOpenOnce() {} onOpenOnce()
182
- function openOnce() {
183
- eeEmit('openOnce')
207
+ //dataType
208
+ let dataType = get(opt, 'dataType', '')
209
+ if (dataType !== 'blob' && dataType !== 'obj' && dataType !== 'fmd' && dataType !== 'json') {
210
+ dataType = 'blob'
184
211
  }
212
+ // console.log('dataType', dataType)
185
213
 
214
+ //cbProgress
215
+ let cbProgress = get(opt, 'cbProgress')
186
216
 
187
- /**
188
- * Hapi監聽錯誤事件
189
- *
190
- * @memberof WConverhpClient
191
- * @param {*} err 接收錯誤訊息
192
- * @example
193
- * wo.on('error', function(err) {
194
- * ...
195
- * })
196
- */
197
- function onError() {} onError()
198
- function error(msg, err) {
199
- eeEmit('error', { msg, err })
217
+ //urlUse
218
+ let urlUse = ''
219
+ if (type === 'basic') {
220
+ urlUse = url
200
221
  }
201
-
202
-
203
- //res2u8arr
204
- async function res2u8arr(env, bb) {
205
- let u8a
206
- if (env === 'browser') {
207
- u8a = await blob2u8arr(bb)
208
- }
209
- else {
210
- u8a = new Uint8Array(bb)
211
- }
212
- return u8a
222
+ else if (type === 'slice') {
223
+ urlUse = `${url}slc`
213
224
  }
225
+ else if (type === 'slicemerge') {
226
+ urlUse = `${url}slcm`
227
+ }
228
+ else {
229
+ throw new Error(`invalid type[${type}]`)
230
+ }
231
+ // console.log('urlUse', urlUse)
214
232
 
233
+ //pm
234
+ let pm = genPm()
215
235
 
216
- //sendDataCore
217
- function sendDataCore(data, cbProgress) {
218
- //console.log('sendData', data, cbProgress)
219
-
220
- //pm
221
- let pm = genPm()
222
-
223
- //env
224
- let env = isWindow() ? 'browser' : 'nodejs'
225
- // console.log('env', env)
236
+ //dd, ct
237
+ let dd = null
238
+ let ct = {}
239
+ if (dataType === 'blob') {
226
240
 
227
- // //g
228
- // let g = getGlobal()
241
+ //set ct
242
+ ct = {
243
+ 'Content-Type': 'application/octet-stream',
244
+ }
229
245
 
230
- //obj2u8arr
231
- let u8a = obj2u8arr(data)
232
- // console.log('u8a', u8a)
246
+ //set dd
247
+ dd = pkg
233
248
 
234
- //u8a to blob(in browser) or buffer(in nodejs)
235
- let bb
236
- if (env === 'browser') {
237
- bb = new Blob([u8a.buffer])
238
- }
239
- else { //nodejs
240
- bb = Buffer.from(u8a)
241
- }
242
- // console.log('bb', bb)
249
+ }
250
+ else if (dataType === 'fmd') {
243
251
 
244
- //new
252
+ //fmd
245
253
  let fmd
246
254
  if (env === 'browser') {
247
255
  fmd = new FormData()
248
256
  }
249
257
  else {
250
258
  if (isfun(opt.FormData)) {
251
- fmd = new opt.FormData({ maxDataSize: 1024 * 1024 * 1024 }) //nodejs, 使用套件form-data設定資料量最大為1g
259
+ fmd = new opt.FormData({ maxDataSize: 1024 * 1024 * 1024 * 1024 }) //nodejs, 使用套件form-data設定資料量最大為1tb
252
260
  }
253
261
  else {
254
262
  console.log(`invalid opt.FormData, need [npm i form-data] and [import FormData from 'form-data'] to set opt.FormData = FormData`)
@@ -257,441 +265,369 @@ function WConverhpClient(opt) {
257
265
  }
258
266
 
259
267
  //append
260
- //fmd.append('aa', 'test')
261
- fmd.append('bb', bb)
268
+ fmd.append('bb', pkg)
262
269
  // console.log('fmd', fmd)
263
270
 
264
- //ct
265
- let ct = 'multipart/form-data'
271
+ //set ct
266
272
  if (env === 'nodejs') {
267
- ct += `; boundary=${fmd.getBoundary()}` //nodejs, 使用套件form-data需設定boundary
268
- }
269
- // console.log('ct', ct)
270
-
271
- //rt
272
- let rt = 'blob'
273
- if (env === 'nodejs') {
274
- rt = 'arraybuffer' //nodejs下沒有blob, 只能設定'json', 'arraybuffer', 'document', 'json', 'text', 'stream'
275
- }
276
- // console.log('rt', rt)
277
-
278
- //s
279
- let s = {
280
- method: 'POST',
281
- url,
282
- data: fmd,
283
- headers: {
284
- 'Content-Type': ct, //數據視為file上傳
285
- },
286
- timeout: 5 * 60 * 1000, //5分鐘
287
- maxContentLength: Infinity, //1024 * 1024 * 1024, Infinity //axios於nodejs中會限制內容大小故需改為無限
288
- maxBodyLength: Infinity, //1024 * 1024 * 1024, Infinity //axios於nodejs中會限制內容大小故需改為無限
289
- responseType: rt,
290
- onUploadProgress: function(ev) {
291
- //console.log('onUploadProgress', ev)
292
-
293
- //r
294
- let r = 0
295
- let loaded = ev.loaded
296
- let total = ev.total
297
- if (ispint(total)) {
298
- r = (loaded * 100) / total
299
- }
300
-
301
- //cbProgress
302
- if (isfun(cbProgress)) {
303
- cbProgress(Math.floor(r), loaded, 'upload')
304
- }
305
-
306
- },
307
- onDownloadProgress: function (ev) {
308
- // console.log('onDownloadProgress', ev)
309
-
310
- //r
311
- let r = 0
312
- let loaded = ev.loaded
313
- // let total = ev.srcElement.getResponseHeader('Content-length') //若需要得知下載進度, 需於伺服器回傳時提供Content-length
314
- let total = ev.total
315
- if (ispint(total)) {
316
- r = (loaded * 100) / total
317
- }
318
-
319
- //cbProgress
320
- if (isfun(cbProgress)) {
321
- cbProgress(Math.floor(r), loaded, 'donwload')
322
- }
323
-
324
- },
273
+ ct = {
274
+ 'Content-Type': `multipart/form-data; boundary=${fmd.getBoundary()}` //nodejs, 使用套件form-data需設定boundary
275
+ }
276
+ // console.log('ct', ct)
325
277
  }
326
- // console.log('s', s)
327
-
328
- //axios
329
- //使用import axios from 'axios', 若於套件內測試, 由於執行時axios自動選用nodejs或browser版本, 分不出差異
330
- //但若是發佈成套件再由其他套件呼叫使用就會預設使用axiosNode版本, 導致瀏覽器端出錯: Cannot convert undefined or null to object[at mergeConfig]
331
- // let axios = null
332
- // if (env === 'browser') {
333
- // axios = axiosBrowser
334
- // }
335
- // else {
336
- // axios = axiosNode
337
- // }
338
-
339
- //axios
340
- axios(s)
341
- .then(async (res) => {
342
- // console.log('axios then', res)
343
-
344
- //bb
345
- let bb = get(res, 'data')
346
- // console.log('bb', bb)
347
-
348
- //res2u8arr
349
- let u8a = await res2u8arr(env, bb)
350
- // console.log('u8a', u8a)
351
-
352
- //u8arr2obj
353
- let data = u8arr2obj(u8a)
354
- // console.log('data', data)
355
-
356
- pm.resolve(data)
357
- })
358
- .catch(async (res) => {
359
- //console.log('axios catch', res.toJSON())
360
- //Network Error除可能是網路斷線之外, 亦可能因硬碟空間不足(<4g)無法下載, 或是被瀏覽器外掛封鎖阻擋
361
-
362
- //statusText, err
363
- let statusText = get(res, 'response.statusText') || get(res, 'message')
364
- let err = get(res, 'response.data') || get(res, 'stack')
365
-
366
- if (statusText) {
367
- // console.log('statusText', statusText)
368
- data = statusText
369
- }
370
- else if (err) {
371
- // console.log('err', err)
372
- data = err
373
- }
374
- else {
375
- try {
376
- res = res.toJSON()
377
- }
378
- catch (err) {}
379
- console.log('err', res)
380
- data = 'Can not connect to server.'
381
- }
382
- if (data === 'Network Error') {
383
- data = `${data}. Make sure your space of hard drive is large enough or blocking by browser plugins.`
384
- }
385
278
 
386
- pm.reject(data)
387
- })
279
+ //set dd
280
+ dd = fmd
388
281
 
389
- return pm
390
282
  }
283
+ else if (dataType === 'json') {
284
+ dd = JSON.stringify(pkg)
285
+ }
286
+ else if (dataType === 'obj') {
287
+ dd = pkg
288
+ }
289
+ // console.log('dd', dd)
391
290
 
291
+ //rt
292
+ let rt = 'blob'
293
+ if (env === 'nodejs') {
294
+ rt = 'arraybuffer' //nodejs下沒有blob, 只能設定'json', 'arraybuffer', 'document', 'json', 'text', 'stream'
295
+ }
296
+ // console.log('rt', rt)
297
+
298
+ //s
299
+ let s = {
300
+ method: 'POST',
301
+ url: urlUse,
302
+ data: dd,
303
+ headers: {
304
+ ...ct,
305
+ ...headers,
306
+ },
307
+ timeout: 60 * 60 * 1000, //1hr
308
+ maxContentLength: Infinity, //1024 * 1024 * 1024, Infinity //axios於nodejs中會限制內容大小故需改為無限
309
+ maxBodyLength: Infinity, //1024 * 1024 * 1024, Infinity //axios於nodejs中會限制內容大小故需改為無限
310
+ responseType: rt,
311
+ onUploadProgress: function(ev) {
312
+ //console.log('onUploadProgress', ev)
313
+
314
+ //r
315
+ let r = 0
316
+ let loaded = ev.loaded
317
+ let total = ev.total
318
+ if (ispint(total)) {
319
+ r = (loaded * 100) / total
320
+ }
392
321
 
393
- //sendData
394
- async function sendData(data, cbProgress) {
395
-
396
- //sendDataCore
397
- let r = await pm2resolve(sendDataCore)(data, cbProgress)
322
+ //cbProgress
323
+ if (isfun(cbProgress)) {
324
+ cbProgress(Math.floor(r), loaded, 'upload')
325
+ }
398
326
 
399
- let n = 0
400
- while (r.state === 'error') {
401
- n += 1
402
- if (n > opt.retry) {
403
- break
327
+ },
328
+ onDownloadProgress: function (ev) {
329
+ // console.log('onDownloadProgress', ev)
330
+
331
+ //r
332
+ let r = 0
333
+ let loaded = ev.loaded
334
+ // let total = ev.srcElement.getResponseHeader('Content-length') //若需要得知下載進度, 需於伺服器回傳時提供Content-length
335
+ let total = ev.total
336
+ if (ispint(total)) {
337
+ r = (loaded * 100) / total
404
338
  }
405
- console.log(`retry n=${n}`)
406
- r = await pm2resolve(sendDataCore)(data, cbProgress)
407
- }
408
339
 
409
- //return
410
- if (r.state === 'success') {
411
- return r.msg
412
- }
413
- else {
414
- return Promise.reject(r.msg)
415
- }
340
+ //cbProgress
341
+ if (isfun(cbProgress)) {
342
+ cbProgress(Math.floor(r), loaded, 'donwload')
343
+ }
416
344
 
345
+ },
417
346
  }
347
+ // console.log('s', s)
348
+
349
+ //axios
350
+ axios(s)
351
+ .then(async (res) => {
352
+ // console.log('axios then', res)
353
+
354
+ //bb
355
+ let bb = get(res, 'data')
356
+ // console.log('bb', bb)
357
+
358
+ //res2u8arr
359
+ let u8a = await res2u8arr(bb)
360
+ // console.log('u8a', u8a)
361
+
362
+ //u8arr2obj
363
+ let data = u8arr2obj(u8a)
364
+ // console.log('data', data)
365
+
366
+ //check
367
+ if (!iseobj(data)) {
368
+ console.log('data is not an effective object', data)
369
+ pm.reject(`data is not an effective object`)
370
+ return
371
+ }
418
372
 
373
+ //分離伺服器資料的success或error
374
+ if (haskey(data, 'success')) {
375
+ pm.resolve(data.success)
376
+ }
377
+ else if (haskey(data, 'error')) {
378
+ pm.resolve(data.error)
379
+ }
380
+ else {
381
+ console.log('invalid data', data)
382
+ pm.reject(`invalid data`)
383
+ }
419
384
 
420
- //sendMsg
421
- function sendMsg(msg, cbResult, cbProgress) {
422
- //console.log(msg, cbResult, cbProgress)
385
+ })
386
+ .catch(async (res) => {
387
+ //console.log('axios catch', res.toJSON())
388
+ //Network Error除可能是網路斷線之外, 可能被瀏覽器外掛封鎖阻擋, 亦可能因硬碟空間不足(<4g)無法下載被瀏覽器拒絕
423
389
 
424
- //sendData
425
- sendData(msg, cbProgress)
426
- .then((res) => {
427
- //console.log('sendData then', res)
390
+ //data
391
+ let data = null
428
392
 
429
- //cbResult
430
- cbResult(res)
393
+ //statusText, err
394
+ let statusText = get(res, 'response.statusText') || get(res, 'message')
395
+ let err = get(res, 'response.data') || get(res, 'stack')
431
396
 
432
- })
433
- .catch((err) => {
434
- //console.log('sendData catch', err)
397
+ if (statusText) {
398
+ // console.log('statusText', statusText)
399
+ data = statusText
400
+ }
401
+ else if (err) {
402
+ // console.log('err', err)
403
+ data = err
404
+ }
405
+ else {
406
+ try {
407
+ res = res.toJSON()
408
+ }
409
+ catch (err) {}
410
+ console.log('err', res)
411
+ data = 'Can not connect to server.'
412
+ }
413
+ if (data === 'Network Error') {
414
+ data = `Network Error. Make sure your space of hard drive is large enough or blocking by browser plugins.`
415
+ }
435
416
 
436
- //cbResult
437
- cbResult({
438
- error: err,
439
- })
417
+ pm.reject(data)
418
+ })
440
419
 
441
- })
420
+ return pm
421
+ }
442
422
 
443
- }
444
423
 
424
+ //sendPkg
425
+ async function sendPkg(type, data, cbProgress) {
445
426
 
446
- function polling() {
427
+ //bb
428
+ let bb = null
429
+ try {
447
430
 
448
- //setInterval
449
- setInterval(() => {
431
+ //obj2u8arr
432
+ let u8a = obj2u8arr(data)
433
+ // console.log('u8a', u8a)
450
434
 
451
- //triggerPolling
452
- triggerPolling()
453
- .then((res) => {
454
- //console.log('polling res', res)
435
+ //u8a to blob(in browser) or buffer(in nodejs)
436
+ bb = u8arr2bb(u8a)
437
+ // console.log('bb', bb)
455
438
 
456
- //output
457
- let output = get(res, 'success.output', null)
458
- //console.log('output', output)
439
+ }
440
+ catch (err) {
441
+ return Promise.reject(err)
442
+ }
459
443
 
460
- //check
461
- if (output === null) {
462
- return
463
- }
464
- if (!isearr(output)) {
465
- return
466
- }
444
+ //send
445
+ // console.log('send bb...')
446
+ let res = await send(type, bb, { dataType: 'blob', cbProgress })
447
+ // console.log('send done', res)
467
448
 
468
- //each
469
- each(output, (v, k) => {
470
- setTimeout(() => {
449
+ return res
450
+ }
471
451
 
472
- if (get(v, 'mode') === 'broadcast') {
473
- //broadcast 廣播
474
- eeEmit('broadcast', get(v, 'data'))
475
- }
476
- else if (get(v, 'mode') === 'deliver') {
477
- //deliver 發送
478
- eeEmit('deliver', get(v, 'data'))
479
- }
480
- else {
481
- error('invalid data.mode in polling', v)
482
- }
483
452
 
484
- }, 10 * (k + 1))
485
- })
453
+ //sendData
454
+ async function sendData(type, data, cbProgress) {
486
455
 
487
- })
488
- .catch((err) => {
489
- error('can not polling', err)
490
- eeEmit('reconn')
491
- })
456
+ //fun
457
+ let fun = pmConvertResolve(sendPkg)
492
458
 
493
- }, opt.timePolling)
459
+ //sendPkg
460
+ let r = await fun(type, data, cbProgress)
494
461
 
462
+ let n = 0
463
+ while (r.state === 'error') {
464
+ n += 1
465
+ if (n > retry) {
466
+ break
467
+ }
468
+ console.log(`retry n=${n}`)
469
+ r = await fun(data, cbProgress)
495
470
  }
496
471
 
472
+ if (r.state === 'success') {
473
+ return r.msg
474
+ }
475
+ else {
476
+ return Promise.reject(r.msg)
477
+ }
478
+ }
497
479
 
498
- function triggerPolling() {
499
-
500
- //pm
501
- let pm = genPm()
502
480
 
503
- //msg
504
- let msg = {
505
- _mode: 'polling',
506
- clientId,
507
- }
481
+ //sendDataSlice
482
+ async function sendDataSlice(tempId, bb, cbProgress) {
508
483
 
509
- //cb
510
- function cb(res) {
511
- pm.resolve(res)
484
+ //n
485
+ let n = 0
486
+ if (n === 0) {
487
+ try {
488
+ n = bb.size //for Blob
489
+ n = cint(n)
490
+ console.log('size n', n)
512
491
  }
513
-
514
- //sendMsg
515
- sendMsg(msg, cb, () => {})
516
-
517
- return pm
492
+ catch (err) {}
518
493
  }
519
-
520
-
521
- function triggerExecute(func, input, cbResult, cbProgress) {
522
- //console.log('triggerExecute', func, input, cbResult, cbProgress)
523
-
524
- //mode
525
- let mode = 'execute'
526
-
527
- //msg
528
- let msg = {
529
- _mode: mode,
530
- clientId,
531
- func,
532
- input,
494
+ if (n === 0) {
495
+ try {
496
+ n = bb.length //for Uint8Array
497
+ n = cint(n)
533
498
  }
534
-
535
- //sendMsg
536
- sendMsg(msg, cbResult, cbProgress)
537
-
499
+ catch (err) {}
538
500
  }
501
+ if (n === 0) {
502
+ return Promise.reject(`Can not get size of bb`)
503
+ }
504
+ // console.log('n', n)
539
505
 
506
+ //chunkTotal
507
+ let chunkTotal = Math.ceil(n / sizeSlice)
508
+ // console.log('chunkTotal', chunkTotal)
540
509
 
541
- function triggerBroadcast(input, cbResult, cbProgress) {
542
- triggerCommon(input, cbResult, cbProgress, 'broadcast')
543
- }
510
+ //packageId
511
+ let packageId = `${now2strp()}-${genID()}`
512
+ // console.log('packageId', packageId)
544
513
 
514
+ //upload slice
515
+ for (let i = 0; i < chunkTotal; i++) {
545
516
 
546
- function triggerDeliver(input, cbResult, cbProgress) {
547
- triggerCommon(input, cbResult, cbProgress, 'deliver')
548
- }
517
+ //start
518
+ let start = i * sizeSlice
549
519
 
520
+ //end
521
+ let end = Math.min(start + sizeSlice, n)
550
522
 
551
- function triggerCommon(input, cbResult, cbProgress, mode) {
523
+ //chunk
524
+ let chunk = bb.slice(start, end)
552
525
 
553
- //msg
554
- let msg = {
555
- _mode: mode,
556
- clientId,
557
- input,
526
+ //hd
527
+ let hd = {
528
+ 'chunk-index': i,
529
+ 'chunk-total': chunkTotal,
530
+ 'package-id': packageId,
558
531
  }
559
532
 
560
- //sendMsg
561
- sendMsg(msg, cbResult, cbProgress)
533
+ //send slice
534
+ // console.log(`uploading chunk[${i + 1}/${chunkTotal}] of packageId[${packageId}]...`)
535
+ await send('slice', chunk, { headers: hd, dataType: 'blob', cbProgress })
536
+ // console.log(`upload chunk[${i + 1}/${chunkTotal}] of packageId[${packageId}] done`, res)
562
537
 
563
538
  }
564
539
 
540
+ //send merge
541
+ // console.log(`merging tempId[${tempId}]...`)
542
+ let msg = {
543
+ 'filename': tempId,
544
+ 'chunk-total': chunkTotal,
545
+ 'package-id': packageId,
546
+ }
547
+ let resMg = await send('slicemerge', msg, { dataType: 'obj', cbProgress }) //bbb fmd obj
548
+ // console.log(`merge tempId[${tempId}] done`, resMg)
565
549
 
566
- //triggerExecute, 若斷線重連則需自動清除過去監聽事件
567
- ee.removeAllListeners('triggerExecute')
568
- ee.on('triggerExecute', triggerExecute)
569
-
570
-
571
- //triggerBroadcast, 若斷線重連則需自動清除過去監聽事件
572
- ee.removeAllListeners('triggerBroadcast')
573
- ee.on('triggerBroadcast', triggerBroadcast)
574
-
575
-
576
- //triggerDeliver, 若斷線重連則需自動清除過去監聽事件
577
- ee.removeAllListeners('triggerDeliver')
578
- ee.on('triggerDeliver', triggerDeliver)
579
-
580
-
581
- //open, openOnce, polling
582
- open()
583
- openOnce()
584
- polling()
585
-
586
-
550
+ return resMg
587
551
  }
588
552
 
553
+ //execute
554
+ async function execute(func, input, cbProgress) {
589
555
 
590
- //parseOutput
591
- function parseOutput(pm, data) {
592
- let resSuccess = get(data, 'success', null)
593
- let resError = get(data, 'error', null)
594
- if (resSuccess !== null) {
595
- let output = get(resSuccess, 'output')
596
- pm.resolve(output)
556
+ //msg
557
+ let msg = {
558
+ // _mode: mode,
559
+ // clientId,
560
+ func,
561
+ input,
597
562
  }
598
- else {
599
- pm.reject(resError)
600
- }
601
- }
602
563
 
564
+ //sendData
565
+ let state = ''
566
+ let res = null
567
+ await sendData('basic', msg, cbProgress)
568
+ .then((msg) => {
569
+ // console.log('msg', msg)
570
+
571
+ //check
572
+ if (!iseobj(msg)) {
573
+ console.log('msg is not an effective object', msg)
574
+ state = 'error'
575
+ res = 'msg is not an effective object'
576
+ return
577
+ }
603
578
 
604
- /**
605
- * Hapi通訊物件對伺服器端執行函數,表示傳送資料給伺服器,並請伺服器執行函數
606
- *
607
- * @memberof WConverhpClient
608
- * @function execute
609
- * @param {String} func 輸入執行函數之名稱字串
610
- * @param {*} [input=null] 輸入執行函數之輸入資訊
611
- * @example
612
- * let func = 'NameOfFunction'
613
- * let input = {...}
614
- * wo.execute(func, input)
615
- */
616
- ee.execute = function (func, input, cbProgress = function () {}) {
617
- let pm = genPm()
618
- eeEmit('triggerExecute', func, input,
619
- function(data) { //結果用promise回傳
620
- parseOutput(pm, data)
621
- },
622
- cbProgress //傳輸進度用cb回傳
623
- )
624
- return pm
625
- }
579
+ //check, 預期msg格式為{func,input,output}, 但input會刪除
580
+ if (!haskey(msg, 'output')) {
581
+ console.log('invalid msg.output', msg)
582
+ state = 'error'
583
+ res = 'invalid msg.output'
584
+ return
585
+ }
626
586
 
587
+ state = 'success'
588
+ res = msg.output
589
+ })
590
+ .catch((msg) => {
591
+ state = 'error'
592
+ res = msg
593
+ })
594
+
595
+ //r
596
+ let r = {
597
+ state,
598
+ msg: res,
599
+ }
600
+ // console.log('sendData r', r)
627
601
 
628
- /**
629
- * Hapi通訊物件對伺服器端廣播函數,表示傳送資料給伺服器,還需轉送其他客戶端
630
- *
631
- * @memberof WConverhpClient
632
- * @function broadcast
633
- * @param {*} data 輸入廣播函數之輸入資訊
634
- * @example
635
- * let data = {...}
636
- * wo.broadcast(data)
637
- */
638
- ee.broadcast = function (data, cbProgress = function () {}) {
639
- let pm = genPm()
640
- eeEmit('triggerBroadcast', data,
641
- function(data) { //結果用promise回傳
642
- parseOutput(pm, data)
643
- },
644
- cbProgress //傳輸進度用cb回傳
645
- )
646
- return pm
647
- }
602
+ //check
603
+ if (state === '') {
604
+ console.log('invalid state', state)
605
+ return Promise.reject('invalid state')
606
+ }
648
607
 
608
+ //check
609
+ if (state === 'error') {
610
+ return Promise.reject('invalid state')
611
+ }
649
612
 
650
- /**
651
- * Hapi通訊物件對伺服器端發送函數,表示僅傳送資料給伺服器
652
- *
653
- * @memberof WConverhpClient
654
- * @function deliver
655
- * @param {*} data 輸入發送函數之輸入資訊
656
- * @example
657
- * let data = {...}
658
- * wo.deliver(data)
659
- */
660
- ee.deliver = function (data, cbProgress = function () {}) {
661
- let pm = genPm()
662
- eeEmit('triggerDeliver', data,
663
- function(data) { //結果用promise回傳
664
- parseOutput(pm, data)
665
- },
666
- cbProgress //傳輸進度用cb回傳
667
- )
668
- return pm
613
+ return r.msg
669
614
  }
670
615
 
616
+ //upload
617
+ async function upload(tempId, input, cbProgress) {
671
618
 
672
- // /**
673
- // * Hapi監聽重連事件
674
- // *
675
- // * @memberof WConverhpClient
676
- // * @example
677
- // * wo.on('reconn', function() {
678
- // * ...
679
- // * })
680
- // */
681
- // function onReconn() {} onReconn()
682
- // function reconn() {
683
- // eeEmit('reconn')
684
- // setTimeout(function() {
685
- // core()
686
- // }, 1000)
687
- // }
619
+ //bb
620
+ let bb = input
688
621
 
622
+ return sendDataSlice(tempId, bb, cbProgress)
623
+ }
689
624
 
690
- //core
691
- core()
692
-
625
+ //r
626
+ let r = {}
627
+ r.execute = execute
628
+ r.upload = upload
693
629
 
694
- return ee
630
+ return r
695
631
  }
696
632
 
697
633