@choiceform/os-client-core 3.6.34 → 3.6.36

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/dist/infer.js CHANGED
@@ -1 +1,401 @@
1
- const inferCommander={accumulated:[],consumingStarted:!1,ended:!1,postingCount:0,queryObj:null,iframeCount:0,startTime:0,messageDiv:null,errorDiv:null,workersDiv:null,typeColorMap:{error:"red",skip:"orange"},successCount:0,skipCount:0,errorCount:0,tryCount:0,rejectCount:0,requireCount:0,timeLog:null,start(){this.queryObj=this.queryToObj(),this.iframeCount=this.queryObj.thread||10,this.startTime=Date.now(),this.progressDiv=document.getElementById("message"),this.errorDiv=document.getElementById("error"),this.workersDiv=document.getElementById("workers"),this.timeLog=document.querySelector("#time-log tbody"),window.addEventListener("message",(t=>{const{name:e,id:s,progress:r,round:i}=t.data;"infer_worker"===e?this.accumulate(t.data):"infer_progress"===e&&this.updateWorkerStatus(r,s,i)})),this.requireCount=Number(this.queryObj.count),this.iframeCount=Math.min(this.requireCount,this.iframeCount),this.workersDiv.innerHTML=`<div>使用${this.iframeCount}个工人执行任务</div>`,this.iframes=[];const t=Object.keys(this.queryObj).reduce(((t,e)=>{let s=e;if(["time_range","status","collector_id"].includes(e))s="infer_"+e;else{if(!s.startsWith("$$_"))return t;s=s.substring(3)}return t+`&${s}=${this.queryObj[e]}`}),"");for(let e=0;e<this.iframeCount;e++){const s=document.createElement("iframe");let r=`../infer-worker.html?sid=${this.queryObj.sid}&infer_id=${e}${t}`;s.src=r,s.style.display="none",this.iframes.push(s),document.body.appendChild(s);const i=`<span>工人${e+1}:</span>\n <span class='worker_status'>准备中...</span>\n <span class='worker_progress'></span>`,n=document.createElement("div");n.setAttribute("id","infer_id_"+e),n.innerHTML=i,this.workersDiv.appendChild(n)}},enableImmediateNextTask(){return this.postingCount<this.requireCount-this.successCount},accumulate(t){this.accumulated.push(t),this.consumingStarted||(this.consumingStarted=!0,this.consume())},consume(){if(this.ended)return;if(!this.enableImmediateNextTask())return void(this.consumingStarted=!1);const t=this.accumulated.shift();if(t){this.tryCount++;const{type:e,message:s}=t;if("END"===e)if(this.queryObj.dry){this.successCount++,this.handleProgress("success");const e=t.data.result.answers.length,s=t.data.result.time_consuming,r=Math.round(s/e);console.info(s,e,r);const i=document.createElement("tr");i.innerHTML=`<td>${this.successCount}</td>\n <td>${s}</td><td>${e}</td><td>${r}</td>`,this.timeLog.appendChild(i)}else this.postData(t.data).then((()=>{this.successCount++,this.handleProgress("success")})).catch((t=>{"rejected"===t?(this.rejectCount++,this.handleProgress("reject")):(this.errorCount++,this.handleProgress("error",s))})),this.consume();else"ERROR"===e||"NEXT_FAIL"===e||"TIMEOUT"===e||"ABANDON"===e?(this.errorCount++,this.handleProgress("error",s)):"CHECK_END"===e&&(this.skipCount++,this.handleProgress("skip",s))}else this.consumingStarted=!1},postData(t){return this.postingCount++,new Promise(((e,s)=>{const r=new XMLHttpRequest;return r.onload=()=>{this.postingCount--,r.status>=200&&r.status<300?e():s()},r.onerror=()=>{this.postingCount--,s()},r.open("POST",t.url),r.setRequestHeader("content-type","application/json"),r.setRequestHeader("Authorization","bearer "+t.jwt),r.send(JSON.stringify(t.result)),r}))},queryToObj(){const t=location.href.split("?")[1].split("&"),e={};return t.forEach((t=>{const s=t.split("=");e[s[0]]=s[1]})),e},shouldEnd(){if(this.successCount>=this.requireCount||this.rejectCount)return!0;const{max_error_count:t,max_try_count:e,max_skip_count:s}=this.queryObj;return!!(e&&this.tryCount>=e)||!!(t&&this.errorCount>=t)||!!(s&&this.skipCount>=s)},updateWorkerStatus(t,e,s){if(!this.ended&&window.parent===window){const{percent:r,fullLength:i,index:n}=t,o=this.workersDiv.querySelector("#infer_id_"+e);o.querySelector(".worker_status").textContent=`轮次: ${s} `,o.querySelector(".worker_progress").textContent=`进度: ${n}/${i} ${r}%`}},handleProgress(t,e){if(this.shouldEnd()){this.ended=!0;let t=this.iframes.pop();for(;t;)document.body.removeChild(t),t=this.iframes.pop();const e=this.workersDiv.querySelectorAll(".worker_status"),s=this.workersDiv.querySelectorAll(".worker_progress");e.forEach((t=>t.innerHTML="收工")),s.forEach((t=>t.innerHTML=""))}if(window.parent!==window)window.parent.postMessage({name:"infer_result",requireCount:this.requireCount,successCount:this.successCount,skipCount:this.skipCount,errorCount:this.errorCount,tryCount:this.tryCount,rejectCount:this.rejectCount,ended:this.ended,cost:this.ended?Date.now()-this.startTime:void 0,type:t,message:e},"*");else if(this.progressDiv.innerHTML=[this.ended?`<div>已结束,耗时: ${(Date.now()-this.startTime)/1e3}s</div>`:"<div>运行中...</div>",`<div>要求总数量:${this.requireCount}</div>`,`<div>已尝试次数:${this.tryCount}</div>`,`<div style='color: green'>已成功次数:${this.successCount}</div>`,`<div style='color: red'>出错误次数:${this.errorCount}</div>`,`<div style='color: orange'>被甄别次数:${this.skipCount}</div>`,`<div style='color: tomato'>被拒绝次数:${this.rejectCount}</div>`].join("\n"),e){const s=`<div style='color: ${this.typeColorMap[t]}'>${e}</div>`;this.errorDiv.innerHTML+=s}this.ended||this.consume()}};inferCommander.start();
1
+ const inferCommander = {
2
+ /**
3
+ * 接受子任务发来的数据结果池
4
+ * 可能一下子接到很多工人发来的结果,来不及上传
5
+ * 先积累到这里
6
+ */
7
+ accumulated: [],
8
+
9
+ /**
10
+ * 是否开始了消耗数据结果池
11
+ */
12
+ consumingStarted: false,
13
+
14
+ /**
15
+ * 是否已经完成
16
+ */
17
+ ended: false,
18
+
19
+ /**
20
+ * 当前已发起并等待结果的请求数量
21
+ */
22
+ postingCount: 0,
23
+
24
+ /**
25
+ * 查询参数
26
+ * @type {{
27
+ * max_try_count:string;
28
+ * max_error_count:string;
29
+ * thread: string;
30
+ * dry: string;
31
+ * max_skip_count: string;
32
+ * sid: string;
33
+ * fake_port: string;
34
+ * real_port: string;
35
+ * dev: string;
36
+ * time_range: string;
37
+ * status: string;
38
+ * collector_id: string;
39
+ * }}
40
+ */
41
+ queryObj: null,
42
+
43
+ /**
44
+ * 派遣的工人个数
45
+ * @type {number}
46
+ */
47
+ iframeCount: 0,
48
+ /**
49
+ * 开始时间
50
+ * @type {number}
51
+ */
52
+ startTime: 0,
53
+ /**
54
+ * 消息展示div
55
+ * @type {HTMLElement}
56
+ */
57
+ messageDiv: null,
58
+ /**
59
+ * 错误展示div
60
+ * @type {HTMLElement}
61
+ */
62
+ errorDiv: null,
63
+ /**
64
+ * 工人状态展示div
65
+ * @type {HTMLElement}
66
+ */
67
+ workersDiv: null,
68
+ /**
69
+ * 消息颜色表
70
+ */
71
+ typeColorMap: {
72
+ error: 'red',
73
+ skip: 'orange',
74
+ },
75
+ /**
76
+ * 已成功次数
77
+ */
78
+ successCount: 0,
79
+ /**
80
+ * 已跳过次数
81
+ */
82
+ skipCount: 0,
83
+ /**
84
+ * 已错误次数
85
+ */
86
+ errorCount: 0,
87
+ /**
88
+ * 已尝试次数
89
+ */
90
+ tryCount: 0,
91
+ /**
92
+ * 已被拒绝次数
93
+ */
94
+ rejectCount: 0,
95
+
96
+ /**
97
+ * 要求的数量
98
+ */
99
+ requireCount: 0,
100
+
101
+ /**
102
+ * 时间日志
103
+ * @type {HTMLElement}
104
+ */
105
+ timeLog: null,
106
+
107
+ /**
108
+ * 开始运行
109
+ */
110
+ start() {
111
+ this.queryObj = this.queryToObj();
112
+ this.iframeCount = this.queryObj.thread || 10;
113
+ this.startTime = Date.now();
114
+ this.progressDiv = document.getElementById('message');
115
+ this.errorDiv = document.getElementById('error');
116
+ this.workersDiv = document.getElementById('workers');
117
+ this.timeLog = document.querySelector('#time-log tbody');
118
+ window.addEventListener('message', e => {
119
+ const { name, id, progress, round } = e.data;
120
+ if (name === 'infer_worker') {
121
+ this.accumulate(e.data);
122
+ } else if (name === 'infer_progress') {
123
+ this.updateWorkerStatus(progress, id, round);
124
+ }
125
+ });
126
+
127
+ this.requireCount = Number(this.queryObj.count);
128
+ this.iframeCount = Math.min(this.requireCount, this.iframeCount);
129
+ this.workersDiv.innerHTML = `<div>使用${this.iframeCount}个工人执行任务</div>`;
130
+ this.iframes = [];
131
+
132
+ const queryKeys = Object.keys(this.queryObj);
133
+ const suffix = queryKeys.reduce((rs, key) => {
134
+ let name = key;
135
+ // 智能推导参数
136
+ if (['time_range', 'status', 'collector_id'].includes(key)) {
137
+ name = 'infer_' + key;
138
+ // 调试传递的特殊参数
139
+ } else if (name.startsWith('$$_')) {
140
+ name = name.substring(3);
141
+ // 其他参数不传递
142
+ } else {
143
+ return rs;
144
+ }
145
+ rs += `&${name}=${this.queryObj[key]}`;
146
+ return rs;
147
+ }, '');
148
+
149
+ for (let i = 0; i < this.iframeCount; i++) {
150
+ const iframe = document.createElement('iframe');
151
+ let src = `../infer-worker.html?sid=${this.queryObj.sid}&infer_id=${i}${suffix}`;
152
+ iframe.src = src;
153
+ iframe.style.display = 'none';
154
+ this.iframes.push(iframe);
155
+ document.body.appendChild(iframe);
156
+
157
+ const html = `<span>工人${i + 1}:</span>
158
+ <span class='worker_status'>准备中...</span>
159
+ <span class='worker_progress'></span>`;
160
+ const div = document.createElement('div');
161
+ div.setAttribute('id', 'infer_id_' + i);
162
+ div.innerHTML = html;
163
+ this.workersDiv.appendChild(div);
164
+ }
165
+ },
166
+
167
+ /**
168
+ * 是否允许立刻发起后续的任务
169
+ * 如果可以发起则会立即发送下一个任务,不会等待当前任务的完整与否,
170
+ * 这样可以更多并发请求,速度更快
171
+ * 单页要注意不能导致成功总数超标
172
+ */
173
+ enableImmediateNextTask() {
174
+ // 如果当前已经发起并在等待中的任务数小于剩余要求的任务数时才发起
175
+ // 否则先不要发起,如果已发出的人有失败的场合则会继续发起.
176
+ // 如果不这样则可能发送过得的请求导致最终的成功总数大于期望数量
177
+ const result = this.postingCount < this.requireCount - this.successCount;
178
+ // console.info(postingCount, requireCount - successCount, result);
179
+ return result;
180
+ },
181
+
182
+ /**
183
+ * 接受子任务的数据并防止到数据池中,同时尝试开启/唤醒消耗数据的任务
184
+ * @param {*} data
185
+ */
186
+ accumulate(data) {
187
+ this.accumulated.push(data);
188
+ // console.info('receive and accumulate', data.type, accumulated.length)
189
+ if (!this.consumingStarted) {
190
+ // console.info('start/resume consume')
191
+ this.consumingStarted = true;
192
+ this.consume();
193
+ }
194
+ },
195
+
196
+ /**
197
+ * 消耗任务
198
+ */
199
+ consume() {
200
+ if (this.ended) {
201
+ return;
202
+ }
203
+ if (!this.enableImmediateNextTask()) {
204
+ this.consumingStarted = false;
205
+ return;
206
+ }
207
+ const data = this.accumulated.shift();
208
+ if (data) {
209
+ this.tryCount++;
210
+ const { type, message } = data;
211
+
212
+ if (type === 'END') {
213
+ if (this.queryObj.dry) {
214
+ this.successCount++;
215
+ this.handleProgress('success');
216
+ const count = data.data.result.answers.length;
217
+ const time = data.data.result.time_consuming;
218
+ const avg = Math.round(time / count);
219
+ console.info(time, count, avg); // eslint-disable-line
220
+ const row = document.createElement('tr');
221
+ row.innerHTML = `<td>${this.successCount}</td>
222
+ <td>${time}</td><td>${count}</td><td>${avg}</td>`;
223
+ this.timeLog.appendChild(row);
224
+ // console.info('dry run');
225
+ } else {
226
+ // console.info('start to post data');
227
+ this.postData(data.data)
228
+ .then(() => {
229
+ // console.info('post data success');
230
+ this.successCount++;
231
+ this.handleProgress('success');
232
+ })
233
+ .catch(err => {
234
+ // console.error('post data error');
235
+ if (err === 'rejected') {
236
+ this.rejectCount++;
237
+ this.handleProgress('reject');
238
+ } else {
239
+ this.errorCount++;
240
+ this.handleProgress('error', message);
241
+ }
242
+ });
243
+ // console.info('immediately start next concurrent consume')
244
+ this.consume();
245
+ }
246
+ } else {
247
+ if (type === 'ERROR' || type === 'NEXT_FAIL' || type === 'TIMEOUT' || type === 'ABANDON') {
248
+ this.errorCount++;
249
+ this.handleProgress('error', message);
250
+ } else if (type === 'CHECK_END') {
251
+ this.skipCount++;
252
+ this.handleProgress('skip', message);
253
+ }
254
+ }
255
+ } else {
256
+ // console.info('consume out all, pause');
257
+ this.consumingStarted = false;
258
+ }
259
+ },
260
+
261
+ /**
262
+ * 发起请求
263
+ */
264
+ postData(data) {
265
+ this.postingCount++;
266
+ return new Promise((resolve, reject) => {
267
+ const req = new XMLHttpRequest();
268
+ req.onload = () => {
269
+ this.postingCount--;
270
+ if (req.status >= 200 && req.status < 300) {
271
+ resolve();
272
+ } else {
273
+ reject();
274
+ }
275
+ };
276
+ req.onerror = () => {
277
+ this.postingCount--;
278
+ reject();
279
+ };
280
+ req.open('POST', data.url);
281
+ req.setRequestHeader('content-type', 'application/json');
282
+ req.setRequestHeader('Authorization', 'bearer ' + data.jwt);
283
+ req.send(JSON.stringify(data.result));
284
+ return req;
285
+ });
286
+ },
287
+
288
+ /**
289
+ * URL参数转换
290
+ */
291
+ queryToObj() {
292
+ const query = location.href.split('?')[1];
293
+ const parts = query.split('&');
294
+ const obj = {};
295
+ parts.forEach(part => {
296
+ const pair = part.split('=');
297
+ obj[pair[0]] = pair[1];
298
+ });
299
+ return obj;
300
+ },
301
+
302
+ /**
303
+ * 是否应该终止任务
304
+ */
305
+ shouldEnd() {
306
+ if (this.successCount >= this.requireCount || this.rejectCount) {
307
+ // console.info('should abandon', successCount, tryCount)
308
+ return true;
309
+ }
310
+ const { max_error_count, max_try_count, max_skip_count } = this.queryObj;
311
+ if (max_try_count && this.tryCount >= max_try_count) {
312
+ return true;
313
+ }
314
+ if (max_error_count && this.errorCount >= max_error_count) {
315
+ return true;
316
+ }
317
+ if (max_skip_count && this.skipCount >= max_skip_count) {
318
+ return true;
319
+ }
320
+ return false;
321
+ },
322
+
323
+ /**
324
+ * 更新工人状态
325
+ * @param {*} progress
326
+ * @param {*} id
327
+ * @param {*} round
328
+ */
329
+ updateWorkerStatus(progress, id, round) {
330
+ if (this.ended) {
331
+ return;
332
+ }
333
+ if (window.parent === window) {
334
+ const { percent, fullLength, index } = progress;
335
+ const elem = this.workersDiv.querySelector('#infer_id_' + id);
336
+ elem.querySelector('.worker_status').textContent = `轮次: ${round} `;
337
+ elem.querySelector('.worker_progress').textContent = `进度: ${index}/${fullLength} ${percent}%`;
338
+ }
339
+ },
340
+
341
+ /**
342
+ * 处理进度
343
+ * @param {*} type
344
+ * @param {*} message
345
+ */
346
+ handleProgress(type, message) {
347
+ // console.info('consumed ', tryCount, successCount);
348
+ if (this.shouldEnd()) {
349
+ // console.info('complete and abandon', accumulated.length)
350
+ this.ended = true;
351
+ let pop = this.iframes.pop();
352
+ while (pop) {
353
+ document.body.removeChild(pop);
354
+ pop = this.iframes.pop();
355
+ }
356
+ const statusList = this.workersDiv.querySelectorAll('.worker_status');
357
+ const progressList = this.workersDiv.querySelectorAll('.worker_progress');
358
+ statusList.forEach(item => (item.innerHTML = '收工'));
359
+ progressList.forEach(item => (item.innerHTML = ''));
360
+ }
361
+ if (window.parent !== window) {
362
+ window.parent.postMessage(
363
+ {
364
+ name: 'infer_result',
365
+ requireCount: this.requireCount,
366
+ successCount: this.successCount,
367
+ skipCount: this.skipCount,
368
+ errorCount: this.errorCount,
369
+ tryCount: this.tryCount,
370
+ rejectCount: this.rejectCount,
371
+ ended: this.ended,
372
+ cost: this.ended ? Date.now() - this.startTime : undefined,
373
+ type,
374
+ message,
375
+ },
376
+ '*'
377
+ );
378
+ } else {
379
+ this.progressDiv.innerHTML = [
380
+ this.ended ? `<div>已结束,耗时: ${(Date.now() - this.startTime) / 1000}s</div>` : `<div>运行中...</div>`,
381
+ `<div>要求总数量:${this.requireCount}</div>`,
382
+ `<div>已尝试次数:${this.tryCount}</div>`,
383
+ `<div style='color: green'>已成功次数:${this.successCount}</div>`,
384
+ `<div style='color: red'>出错误次数:${this.errorCount}</div>`,
385
+ `<div style='color: orange'>被甄别次数:${this.skipCount}</div>`,
386
+ `<div style='color: tomato'>被拒绝次数:${this.rejectCount}</div>`,
387
+ ].join('\n');
388
+ if (message) {
389
+ const error = `<div style='color: ${this.typeColorMap[type]}'>${message}</div>`;
390
+ this.errorDiv.innerHTML += error;
391
+ }
392
+ }
393
+
394
+ if (!this.ended) {
395
+ // console.info('next consume start');
396
+ this.consume();
397
+ }
398
+ },
399
+ };
400
+
401
+ inferCommander.start();
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ /*
3
+ * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
4
+ * This devtool is neither made for production nor for readable output files.
5
+ * It uses "eval()" calls to create a separate source file in the browser devtools.
6
+ * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
7
+ * or disable the default devtool with "devtool: false".
8
+ * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
9
+ */
10
+ self["webpackHotUpdate_choiceform_os_client_core"]("support/atcp",{},
11
+ /******/ function(__webpack_require__) { // webpackRuntimeModules
12
+ /******/ /* webpack/runtime/getFullHash */
13
+ /******/ (() => {
14
+ /******/ __webpack_require__.h = () => ("f10d2cac001999e27c6a")
15
+ /******/ })();
16
+ /******/
17
+ /******/ }
18
+ );