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