@hpcc-js/comms 3.15.4 → 3.15.5
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/LICENSE +43 -43
- package/README.md +50 -50
- package/dist/browser/index.js +1 -1
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.umd.cjs +1 -1
- package/dist/browser/index.umd.cjs.map +1 -1
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.cjs.map +2 -2
- package/dist/node/index.js +1 -1
- package/dist/node/index.js.map +2 -2
- package/package.json +5 -5
- package/src/__package__.ts +3 -3
- package/src/clienttools/eclMeta.ts +506 -506
- package/src/clienttools/eclcc.ts +628 -628
- package/src/connection.ts +288 -288
- package/src/ecl/activity.ts +82 -82
- package/src/ecl/dfuWorkunit.ts +363 -363
- package/src/ecl/graph.ts +196 -196
- package/src/ecl/logicalFile.ts +196 -196
- package/src/ecl/machine.ts +63 -63
- package/src/ecl/query.ts +265 -265
- package/src/ecl/queryGraph.ts +813 -813
- package/src/ecl/resource.ts +39 -39
- package/src/ecl/result.ts +245 -245
- package/src/ecl/scope.ts +188 -188
- package/src/ecl/sourceFile.ts +34 -34
- package/src/ecl/store.ts +154 -154
- package/src/ecl/targetCluster.ts +149 -149
- package/src/ecl/timer.ts +42 -42
- package/src/ecl/topology.ts +131 -131
- package/src/ecl/workunit.ts +1340 -1340
- package/src/ecl/xsdParser.ts +267 -267
- package/src/espConnection.ts +164 -164
- package/src/index.browser.ts +1 -1
- package/src/index.common.ts +40 -40
- package/src/index.node.ts +48 -48
- package/src/pem/trustwave.ts +909 -909
- package/src/services/fileSpray.ts +73 -73
- package/src/services/wsAccess.ts +8 -8
- package/src/services/wsAccount.ts +27 -27
- package/src/services/wsCloud.ts +73 -73
- package/src/services/wsCodesign.ts +18 -18
- package/src/services/wsDFU.ts +34 -34
- package/src/services/wsDFUXRef.ts +121 -121
- package/src/services/wsDali.ts +8 -8
- package/src/services/wsEcl.ts +123 -123
- package/src/services/wsElk.ts +8 -8
- package/src/services/wsLogaccess.ts +270 -270
- package/src/services/wsMachine.ts +89 -89
- package/src/services/wsPackageProcess.ts +8 -8
- package/src/services/wsResources.ts +8 -8
- package/src/services/wsSMC.ts +80 -80
- package/src/services/wsSasha.ts +7 -7
- package/src/services/wsStore.ts +32 -32
- package/src/services/wsTopology.ts +45 -45
- package/src/services/wsWorkunits.ts +151 -151
- package/src/services/wsdl/FileSpray/v1.23/FileSpray.ts +1008 -1008
- package/src/services/wsdl/FileSpray/v1.25/FileSpray.ts +1040 -1040
- package/src/services/wsdl/FileSpray/v1.26/FileSpray.ts +929 -929
- package/src/services/wsdl/FileSpray/v1.27/FileSpray.ts +930 -930
- package/src/services/wsdl/WsCloud/v1/WsCloud.ts +38 -38
- package/src/services/wsdl/WsCloud/v1.02/WsCloud.ts +77 -77
- package/src/services/wsdl/WsDFUXRef/v1.02/WsDFUXRef.ts +224 -224
- package/src/services/wsdl/WsDFUXRef/v1.04/WsDFUXRef.ts +227 -227
- package/src/services/wsdl/WsDali/v1.04/WsDali.ts +216 -216
- package/src/services/wsdl/WsDfu/v1.62/WsDfu.ts +1455 -1455
- package/src/services/wsdl/WsDfu/v1.63/WsDfu.ts +1465 -1465
- package/src/services/wsdl/WsDfu/v1.65/WsDfu.ts +1244 -1244
- package/src/services/wsdl/WsDfu/v1.66/WsDfu.ts +1267 -1267
- package/src/services/wsdl/WsDfu/v1.67/WsDfu.ts +1268 -1268
- package/src/services/wsdl/WsFileIO/v1.01/WsFileIO.ts +104 -104
- package/src/services/wsdl/WsPackageProcess/v1.04/WsPackageProcess.ts +519 -519
- package/src/services/wsdl/WsPackageProcess/v1.07/WsPackageProcess.ts +500 -500
- package/src/services/wsdl/WsResources/v1.01/WsResources.ts +119 -119
- package/src/services/wsdl/WsSMC/v1.24/WsSMC.ts +665 -665
- package/src/services/wsdl/WsSMC/v1.27/WsSMC.ts +591 -591
- package/src/services/wsdl/WsSMC/v1.28/WsSMC.ts +645 -645
- package/src/services/wsdl/WsSMC/v1.29/WsSMC.ts +660 -660
- package/src/services/wsdl/WsTopology/v1.31/WsTopology.ts +856 -856
- package/src/services/wsdl/WsTopology/v1.32/WsTopology.ts +786 -786
- package/src/services/wsdl/WsTopology/v1.33/WsTopology.ts +835 -835
- package/src/services/wsdl/WsWorkunits/v1.88/WsWorkunits.ts +2944 -2944
- package/src/services/wsdl/WsWorkunits/v1.94/WsWorkunits.ts +3072 -3072
- package/src/services/wsdl/WsWorkunits/v1.95/WsWorkunits.ts +3073 -3073
- package/src/services/wsdl/WsWorkunits/v1.97/WsWorkunits.ts +3134 -3134
- package/src/services/wsdl/WsWorkunits/v1.98/WsWorkunits.ts +3182 -3182
- package/src/services/wsdl/WsWorkunits/v1.99/WsWorkunits.ts +3162 -3162
- package/src/services/wsdl/WsWorkunits/v2/WsWorkunits.ts +3153 -3153
- package/src/services/wsdl/WsWorkunits/v2.02/WsWorkunits.ts +3162 -3162
- package/src/services/wsdl/WsWorkunits/v2.03/WsWorkunits.ts +3164 -3164
- package/src/services/wsdl/WsWorkunits/v2.04/WsWorkunits.ts +3171 -3171
- package/src/services/wsdl/ws_access/v1.16/ws_access.ts +1086 -1086
- package/src/services/wsdl/ws_access/v1.17/ws_access.ts +1023 -1023
- package/src/services/wsdl/ws_account/v1.05/ws_account.ts +111 -111
- package/src/services/wsdl/ws_account/v1.06/ws_account.ts +109 -109
- package/src/services/wsdl/ws_account/v1.07/ws_account.ts +114 -114
- package/src/services/wsdl/ws_codesign/v1.1/ws_codesign.ts +95 -95
- package/src/services/wsdl/ws_elk/v1/ws_elk.ts +47 -47
- package/src/services/wsdl/ws_logaccess/v1/ws_logaccess.ts +83 -83
- package/src/services/wsdl/ws_logaccess/v1.02/ws_logaccess.ts +161 -161
- package/src/services/wsdl/ws_logaccess/v1.03/ws_logaccess.ts +190 -190
- package/src/services/wsdl/ws_logaccess/v1.04/ws_logaccess.ts +215 -215
- package/src/services/wsdl/ws_logaccess/v1.05/ws_logaccess.ts +219 -219
- package/src/services/wsdl/ws_logaccess/v1.08/ws_logaccess.ts +267 -267
- package/src/services/wsdl/ws_machine/v1.17/ws_machine.ts +567 -567
- package/src/services/wsdl/ws_machine/v1.18/ws_machine.ts +497 -497
- package/src/services/wsdl/ws_machine/v1.19/ws_machine.ts +497 -497
- package/src/services/wsdl/wsstore/v1.02/wsstore.ts +239 -239
package/src/ecl/workunit.ts
CHANGED
|
@@ -1,1340 +1,1340 @@
|
|
|
1
|
-
import { Cache, deepMixinT, IEvent, RecursivePartial, scopedLogger, StateCallback, StateEvents, StateObject, StatePropCallback, StringAnyMap, XMLNode } from "@hpcc-js/util";
|
|
2
|
-
import { format as d3Format } from "d3-format";
|
|
3
|
-
import { utcFormat, utcParse } from "d3-time-format";
|
|
4
|
-
import { IConnection, IOptions } from "../connection.ts";
|
|
5
|
-
import { ESPExceptions } from "../espConnection.ts";
|
|
6
|
-
import { WsSMC } from "../services/wsSMC.ts";
|
|
7
|
-
import * as WsTopology from "../services/wsTopology.ts";
|
|
8
|
-
import { WsWorkunits, WUStateID, WorkunitsService, WorkunitsServiceEx, WUUpdate } from "../services/wsWorkunits.ts";
|
|
9
|
-
import { createGraph, createXGMMLGraph, ECLGraph, GraphCache, ScopeGraph, XGMMLGraph, XGMMLVertex } from "./graph.ts";
|
|
10
|
-
import { Resource } from "./resource.ts";
|
|
11
|
-
import { Result, ResultCache } from "./result.ts";
|
|
12
|
-
import { BaseScope, Scope } from "./scope.ts";
|
|
13
|
-
import { SourceFile } from "./sourceFile.ts";
|
|
14
|
-
import { Timer } from "./timer.ts";
|
|
15
|
-
|
|
16
|
-
const formatter = utcFormat("%Y-%m-%dT%H:%M:%S.%LZ");
|
|
17
|
-
const parser = utcParse("%Y-%m-%dT%H:%M:%S.%LZ");
|
|
18
|
-
const d3FormatNum = d3Format(",");
|
|
19
|
-
function formatNum(num: number | string): string {
|
|
20
|
-
if (num && !isNaN(+num)) {
|
|
21
|
-
return d3FormatNum(+num);
|
|
22
|
-
}
|
|
23
|
-
return num as string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function safeDelete(obj: { [id: string]: any; }, key: string, prop: string) {
|
|
27
|
-
if (obj[key] === undefined || obj[key][prop] === undefined) return;
|
|
28
|
-
if (key === "__proto__" || key === "constructor" || key === "prototype") return;
|
|
29
|
-
delete obj[key][prop];
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const DEFINITION_LIST = "DefinitionList";
|
|
33
|
-
const definitionRegex = /([a-zA-Z]:)?(.*[\\\/])(.*)(\((\d+),(\d+)\))/;
|
|
34
|
-
|
|
35
|
-
export const PropertyType = ["Avg", "Min", "Max", "Delta", "StdDev"];
|
|
36
|
-
export const RelatedProperty = ["SkewMin", "SkewMax", "NodeMin", "NodeMax"];
|
|
37
|
-
|
|
38
|
-
export interface IPropertyValue {
|
|
39
|
-
Key: string;
|
|
40
|
-
Value?: string;
|
|
41
|
-
|
|
42
|
-
// Extended properties ---
|
|
43
|
-
Avg?: string;
|
|
44
|
-
Min?: string;
|
|
45
|
-
Max?: string;
|
|
46
|
-
Delta?: string;
|
|
47
|
-
StdDev?: string;
|
|
48
|
-
StdDevs?: number;
|
|
49
|
-
|
|
50
|
-
// Related properties ---
|
|
51
|
-
SkewMin?: string;
|
|
52
|
-
SkewMax?: string;
|
|
53
|
-
NodeMin?: string;
|
|
54
|
-
NodeMax?: string;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface IScope {
|
|
58
|
-
__parentName?: string;
|
|
59
|
-
__children?: IScope[];
|
|
60
|
-
__formattedProps: { [key: string]: any };
|
|
61
|
-
__groupedProps: { [key: string]: IPropertyValue };
|
|
62
|
-
__StdDevs: number,
|
|
63
|
-
__StdDevsSource: string,
|
|
64
|
-
id: string;
|
|
65
|
-
name: string;
|
|
66
|
-
type: string;
|
|
67
|
-
Kind: string;
|
|
68
|
-
Label: string;
|
|
69
|
-
[key: string]: any;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export interface ISplitMetric {
|
|
73
|
-
measure: string;
|
|
74
|
-
ext: string;
|
|
75
|
-
label: string;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const metricKeyRegex = /[A-Z][a-z]*/g;
|
|
79
|
-
function _splitMetric(fullLabel: string): ISplitMetric {
|
|
80
|
-
|
|
81
|
-
// Related properties ---
|
|
82
|
-
for (const relProp of RelatedProperty) {
|
|
83
|
-
const index = fullLabel.indexOf(relProp);
|
|
84
|
-
if (index === 0) {
|
|
85
|
-
const measure = "";
|
|
86
|
-
const label = fullLabel.slice(index + relProp.length);
|
|
87
|
-
return { measure, ext: relProp, label };
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Primary properties ---
|
|
92
|
-
const labelParts = fullLabel.match(metricKeyRegex);
|
|
93
|
-
if (labelParts?.length) {
|
|
94
|
-
const measure = labelParts.shift();
|
|
95
|
-
let label = labelParts.join("");
|
|
96
|
-
for (const ext of PropertyType) {
|
|
97
|
-
const index = label.indexOf(ext);
|
|
98
|
-
if (index === 0) {
|
|
99
|
-
label = label.slice(index + ext.length);
|
|
100
|
-
return { measure, ext, label };
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
// Not an aggregate property ---
|
|
104
|
-
return { measure, ext: "", label };
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// No match found ---
|
|
108
|
-
return { measure: "", ext: "", label: fullLabel };
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const splitLabelCache: { [key: string]: ISplitMetric } = {};
|
|
112
|
-
export function splitMetric(key: string): ISplitMetric {
|
|
113
|
-
let retVal = splitLabelCache[key];
|
|
114
|
-
if (!retVal) {
|
|
115
|
-
retVal = _splitMetric(key);
|
|
116
|
-
splitLabelCache[key] = retVal;
|
|
117
|
-
}
|
|
118
|
-
return retVal;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function formatValue(item: IScope, key: string): string | undefined {
|
|
122
|
-
return item.__formattedProps?.[key] ?? item[key];
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
type DedupProperties = { [key: string]: boolean };
|
|
126
|
-
|
|
127
|
-
function safeParseFloat(val: string | undefined): number | undefined {
|
|
128
|
-
if (val === undefined) return undefined;
|
|
129
|
-
const retVal = parseFloat(val);
|
|
130
|
-
return isNaN(retVal) ? undefined : retVal;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function formatValues(item: IScope, key: string, dedup: DedupProperties): IPropertyValue | null {
|
|
134
|
-
const keyParts = splitMetric(key);
|
|
135
|
-
if (!dedup[keyParts.measure]) {
|
|
136
|
-
dedup[keyParts.label] = true;
|
|
137
|
-
const avg = safeParseFloat(item[`${keyParts.measure}Avg${keyParts.label}`]);
|
|
138
|
-
const min = safeParseFloat(item[`${keyParts.measure}Min${keyParts.label}`]);
|
|
139
|
-
const max = safeParseFloat(item[`${keyParts.measure}Max${keyParts.label}`]);
|
|
140
|
-
const stdDev = safeParseFloat(item[`${keyParts.measure}StdDev${keyParts.label}`]);
|
|
141
|
-
const StdDevs = Math.max((avg - min) / stdDev, (max - avg) / stdDev);
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
Key: `${keyParts.measure}${keyParts.label}`,
|
|
145
|
-
Value: formatValue(item, `${keyParts.measure}${keyParts.label}`),
|
|
146
|
-
|
|
147
|
-
// Extended properties ---
|
|
148
|
-
Avg: formatValue(item, `${keyParts.measure}Avg${keyParts.label}`),
|
|
149
|
-
Min: formatValue(item, `${keyParts.measure}Min${keyParts.label}`),
|
|
150
|
-
Max: formatValue(item, `${keyParts.measure}Max${keyParts.label}`),
|
|
151
|
-
Delta: formatValue(item, `${keyParts.measure}Delta${keyParts.label}`),
|
|
152
|
-
StdDev: formatValue(item, `${keyParts.measure}StdDev${keyParts.label}`),
|
|
153
|
-
StdDevs: isNaN(StdDevs) ? undefined : StdDevs,
|
|
154
|
-
|
|
155
|
-
// Related properties ---
|
|
156
|
-
SkewMin: formatValue(item, `SkewMin${keyParts.label}`),
|
|
157
|
-
SkewMax: formatValue(item, `SkewMax${keyParts.label}`),
|
|
158
|
-
NodeMin: formatValue(item, `NodeMin${keyParts.label}`),
|
|
159
|
-
NodeMax: formatValue(item, `NodeMax${keyParts.label}`)
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
return null;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const logger = scopedLogger("workunit.ts");
|
|
166
|
-
|
|
167
|
-
export class WorkunitCache extends Cache<{ BaseUrl: string, Wuid: string }, Workunit> {
|
|
168
|
-
constructor() {
|
|
169
|
-
super((obj) => {
|
|
170
|
-
return `${obj.BaseUrl}-${obj.Wuid}`;
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
const _workunits = new WorkunitCache();
|
|
175
|
-
|
|
176
|
-
export interface DebugState {
|
|
177
|
-
sequence: number;
|
|
178
|
-
state: string;
|
|
179
|
-
[key: string]: any;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export interface IWorkunit {
|
|
183
|
-
ResultViews: WsWorkunits.ResultViews;
|
|
184
|
-
HelpersCount: number;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export interface IDebugWorkunit {
|
|
188
|
-
DebugState?: DebugState;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export interface ITimeElapsed {
|
|
192
|
-
scope: string;
|
|
193
|
-
start: string;
|
|
194
|
-
elapsed: number;
|
|
195
|
-
finish: string;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export type WorkunitEvents = "completed" | StateEvents;
|
|
199
|
-
export type UWorkunitState = WsWorkunits.ECLWorkunit & WsWorkunits.Workunit & WsSMC.ActiveWorkunit & IWorkunit & IDebugWorkunit;
|
|
200
|
-
export type IWorkunitState = WsWorkunits.ECLWorkunit | WsWorkunits.Workunit | WsSMC.ActiveWorkunit | IWorkunit | IDebugWorkunit;
|
|
201
|
-
export class Workunit extends StateObject<UWorkunitState, IWorkunitState> implements WsWorkunits.Workunit {
|
|
202
|
-
connection: WorkunitsService;
|
|
203
|
-
topologyConnection: WsTopology.TopologyService;
|
|
204
|
-
get BaseUrl() { return this.connection.baseUrl; }
|
|
205
|
-
|
|
206
|
-
private _debugMode: boolean = false;
|
|
207
|
-
private _debugAllGraph: any;
|
|
208
|
-
private _submitAction: WUUpdate.Action;
|
|
209
|
-
|
|
210
|
-
// Accessors ---
|
|
211
|
-
get properties(): WsWorkunits.ECLWorkunit & WsWorkunits.Workunit { return this.get(); }
|
|
212
|
-
get Wuid(): string { return this.get("Wuid"); }
|
|
213
|
-
get Owner(): string { return this.get("Owner", ""); }
|
|
214
|
-
get Cluster(): string { return this.get("Cluster", ""); }
|
|
215
|
-
get Jobname(): string { return this.get("Jobname", ""); }
|
|
216
|
-
get Description(): string { return this.get("Description", ""); }
|
|
217
|
-
get ActionEx(): string { return this.get("ActionEx", ""); }
|
|
218
|
-
get StateID(): WUStateID { return this.get("StateID", WUStateID.Unknown); }
|
|
219
|
-
get State(): string { return this.get("State") || WUStateID[this.StateID]; }
|
|
220
|
-
get Protected(): boolean { return this.get("Protected", false); }
|
|
221
|
-
get Exceptions(): WsWorkunits.Exceptions2 { return this.get("Exceptions", { ECLException: [] }); }
|
|
222
|
-
get ResultViews(): WsWorkunits.ResultViews { return this.get("ResultViews", { View: [] }); }
|
|
223
|
-
|
|
224
|
-
private _resultCache = new ResultCache();
|
|
225
|
-
get ResultCount(): number { return this.get("ResultCount", 0); }
|
|
226
|
-
get Results(): WsWorkunits.Results { return this.get("Results", { ECLResult: [] }); }
|
|
227
|
-
get CResults(): Result[] {
|
|
228
|
-
return this.Results.ECLResult.map((eclResult) => {
|
|
229
|
-
return this._resultCache.get(eclResult, () => {
|
|
230
|
-
return Result.attach(this.connection, this.Wuid, eclResult, this.ResultViews.View);
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
get SequenceResults(): { [key: number]: Result } {
|
|
235
|
-
const retVal: { [key: number]: Result } = {};
|
|
236
|
-
this.CResults.forEach((result) => {
|
|
237
|
-
retVal[result.Sequence] = result;
|
|
238
|
-
});
|
|
239
|
-
return retVal;
|
|
240
|
-
}
|
|
241
|
-
get Timers(): WsWorkunits.Timers { return this.get("Timers", { ECLTimer: [] }); }
|
|
242
|
-
get CTimers(): Timer[] {
|
|
243
|
-
return this.Timers.ECLTimer.map((eclTimer) => {
|
|
244
|
-
return new Timer(this.connection, this.Wuid, eclTimer);
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
private _graphCache = new GraphCache();
|
|
249
|
-
get GraphCount(): number { return this.get("GraphCount", 0); }
|
|
250
|
-
get Graphs(): WsWorkunits.Graphs { return this.get("Graphs", { ECLGraph: [] }); }
|
|
251
|
-
get CGraphs(): ECLGraph[] {
|
|
252
|
-
return this.Graphs.ECLGraph.map((eclGraph) => {
|
|
253
|
-
return this._graphCache.get(eclGraph, () => {
|
|
254
|
-
return new ECLGraph(this, eclGraph, this.CTimers);
|
|
255
|
-
});
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
get ThorLogList(): WsWorkunits.ThorLogList { return this.get("ThorLogList"); }
|
|
259
|
-
get ResourceURLCount(): number { return this.get("ResourceURLCount", 0); }
|
|
260
|
-
get ResourceURLs(): WsWorkunits.ResourceURLs { return this.get("ResourceURLs", { URL: [] }); }
|
|
261
|
-
get CResourceURLs(): Resource[] {
|
|
262
|
-
return this.ResourceURLs.URL.map((url) => {
|
|
263
|
-
return new Resource(this, url);
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
get TotalClusterTime(): string { return this.get("TotalClusterTime", ""); }
|
|
267
|
-
get DateTimeScheduled(): string { return this.get("DateTimeScheduled"); }
|
|
268
|
-
get IsPausing(): boolean { return this.get("IsPausing"); }
|
|
269
|
-
get ThorLCR(): boolean { return this.get("ThorLCR"); }
|
|
270
|
-
get ApplicationValues(): WsWorkunits.ApplicationValues { return this.get("ApplicationValues", { ApplicationValue: [] }); }
|
|
271
|
-
get HasArchiveQuery(): boolean { return this.get("HasArchiveQuery"); }
|
|
272
|
-
get StateEx(): string { return this.get("StateEx"); }
|
|
273
|
-
get PriorityClass(): number { return this.get("PriorityClass"); }
|
|
274
|
-
get PriorityLevel(): number { return this.get("PriorityLevel"); }
|
|
275
|
-
get Snapshot(): string { return this.get("Snapshot"); }
|
|
276
|
-
get ResultLimit(): number { return this.get("ResultLimit"); }
|
|
277
|
-
get EventSchedule(): number { return this.get("EventSchedule"); }
|
|
278
|
-
get Query(): WsWorkunits.Query { return this.get("Query"); }
|
|
279
|
-
get HelpersCount(): number { return this.get("HelpersCount", 0); }
|
|
280
|
-
get Helpers(): WsWorkunits.Helpers { return this.get("Helpers", { ECLHelpFile: [] }); }
|
|
281
|
-
get DebugValues(): WsWorkunits.DebugValues { return this.get("DebugValues"); }
|
|
282
|
-
get AllowedClusters(): WsWorkunits.AllowedClusters { return this.get("AllowedClusters"); }
|
|
283
|
-
get ErrorCount(): number { return this.get("ErrorCount", 0); }
|
|
284
|
-
get WarningCount(): number { return this.get("WarningCount", 0); }
|
|
285
|
-
get InfoCount(): number { return this.get("InfoCount", 0); }
|
|
286
|
-
get AlertCount(): number { return this.get("AlertCount", 0); }
|
|
287
|
-
get SourceFileCount(): number { return this.get("SourceFileCount", 0); }
|
|
288
|
-
get SourceFiles(): WsWorkunits.SourceFiles { return this.get("SourceFiles", { ECLSourceFile: [] }); }
|
|
289
|
-
get CSourceFiles(): SourceFile[] {
|
|
290
|
-
return this.SourceFiles.ECLSourceFile.map(eclSourceFile => new SourceFile(this.connection, this.Wuid, eclSourceFile));
|
|
291
|
-
}
|
|
292
|
-
get VariableCount(): number { return this.get("VariableCount", 0); }
|
|
293
|
-
get Variables(): WsWorkunits.Variables { return this.get("Variables", { ECLResult: [] }); }
|
|
294
|
-
get TimerCount(): number { return this.get("TimerCount", 0); }
|
|
295
|
-
get HasDebugValue(): boolean { return this.get("HasDebugValue"); }
|
|
296
|
-
get ApplicationValueCount(): number { return this.get("ApplicationValueCount", 0); }
|
|
297
|
-
get XmlParams(): string { return this.get("XmlParams"); }
|
|
298
|
-
get AccessFlag(): number { return this.get("AccessFlag"); }
|
|
299
|
-
get ClusterFlag(): number { return this.get("ClusterFlag"); }
|
|
300
|
-
get ResultViewCount(): number { return this.get("ResultViewCount", 0); }
|
|
301
|
-
get DebugValueCount(): number { return this.get("DebugValueCount", 0); }
|
|
302
|
-
get WorkflowCount(): number { return this.get("WorkflowCount", 0); }
|
|
303
|
-
get Archived(): boolean { return this.get("Archived"); }
|
|
304
|
-
get RoxieCluster(): string { return this.get("RoxieCluster"); }
|
|
305
|
-
get DebugState(): DebugState { return this.get("DebugState", {} as DebugState)!; }
|
|
306
|
-
get Queue(): string { return this.get("Queue"); }
|
|
307
|
-
get Active(): boolean { return this.get("Active"); }
|
|
308
|
-
get Action(): number { return this.get("Action"); }
|
|
309
|
-
get Scope(): string { return this.get("Scope"); }
|
|
310
|
-
get AbortBy(): string { return this.get("AbortBy"); }
|
|
311
|
-
get AbortTime(): string { return this.get("AbortTime"); }
|
|
312
|
-
get Workflows(): WsWorkunits.Workflows { return this.get("Workflows"); }
|
|
313
|
-
get TimingData(): WsWorkunits.TimingData { return this.get("TimingData"); }
|
|
314
|
-
get HelpersDesc(): string { return this.get("HelpersDesc"); }
|
|
315
|
-
get GraphsDesc(): string { return this.get("GraphsDesc"); }
|
|
316
|
-
get SourceFilesDesc(): string { return this.get("SourceFilesDesc"); }
|
|
317
|
-
get ResultsDesc(): string { return this.get("ResultsDesc"); }
|
|
318
|
-
get VariablesDesc(): string { return this.get("VariablesDesc"); }
|
|
319
|
-
get TimersDesc(): string { return this.get("TimersDesc"); }
|
|
320
|
-
get DebugValuesDesc(): string { return this.get("DebugValuesDesc"); }
|
|
321
|
-
get ApplicationValuesDesc(): string { return this.get("ApplicationValuesDesc"); }
|
|
322
|
-
get WorkflowsDesc(): string { return this.get("WorkflowsDesc"); }
|
|
323
|
-
get ServiceNames(): WsWorkunits.ServiceNames { return this.get("ServiceNames"); }
|
|
324
|
-
get CompileCost(): number { return this.get("CompileCost"); }
|
|
325
|
-
get ExecuteCost(): number { return this.get("ExecuteCost"); }
|
|
326
|
-
get FileAccessCost(): number { return this.get("FileAccessCost"); }
|
|
327
|
-
get NoAccess(): boolean { return this.get("NoAccess"); }
|
|
328
|
-
get ECLWUProcessList(): WsWorkunits.ECLWUProcessList { return this.get("ECLWUProcessList"); }
|
|
329
|
-
get CostSavingPotential(): number { return this.get("CostSavingPotential"); }
|
|
330
|
-
|
|
331
|
-
// Factories ---
|
|
332
|
-
static create(optsConnection: IOptions | IConnection): Promise<Workunit> {
|
|
333
|
-
const retVal: Workunit = new Workunit(optsConnection);
|
|
334
|
-
return retVal.connection.WUCreate().then((response) => {
|
|
335
|
-
_workunits.set(retVal);
|
|
336
|
-
retVal.set(response.Workunit);
|
|
337
|
-
return retVal;
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
static attach(optsConnection: IOptions | IConnection, wuid: string, state?: IWorkunitState): Workunit {
|
|
342
|
-
const retVal: Workunit = _workunits.get({ BaseUrl: optsConnection.baseUrl, Wuid: wuid }, () => {
|
|
343
|
-
return new Workunit(optsConnection, wuid);
|
|
344
|
-
});
|
|
345
|
-
if (state) {
|
|
346
|
-
retVal.set(state);
|
|
347
|
-
}
|
|
348
|
-
return retVal;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
static existsLocal(baseUrl: string, wuid: string): boolean {
|
|
352
|
-
return _workunits.has({ BaseUrl: baseUrl, Wuid: wuid });
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
static submit(server: IOptions | IConnection, target: string, ecl: string, compileOnly = false): Promise<Workunit> {
|
|
356
|
-
return Workunit.create(server).then((wu) => {
|
|
357
|
-
return wu.update({ QueryText: ecl });
|
|
358
|
-
}).then((wu) => {
|
|
359
|
-
return compileOnly ? wu.submit(target, WUUpdate.Action.Compile) : wu.submit(target);
|
|
360
|
-
});
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
static compile(server: IOptions | IConnection, target: string, ecl: string): Promise<Workunit> {
|
|
364
|
-
return Workunit.submit(server, target, ecl, true);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
static query(server: IOptions | IConnection, opts: Partial<WsWorkunits.WUQuery>): Promise<Workunit[]> {
|
|
368
|
-
const wsWorkunits = new WorkunitsService(server);
|
|
369
|
-
return wsWorkunits.WUQuery(opts).then((response) => {
|
|
370
|
-
return response.Workunits.ECLWorkunit.map(function (wu) {
|
|
371
|
-
return Workunit.attach(server, wu.Wuid, wu);
|
|
372
|
-
});
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// --- --- ---
|
|
377
|
-
protected constructor(optsConnection: IOptions | IConnection, wuid?: string) {
|
|
378
|
-
super();
|
|
379
|
-
this.connection = new WorkunitsService(optsConnection);
|
|
380
|
-
this.topologyConnection = new WsTopology.TopologyService(optsConnection);
|
|
381
|
-
this.clearState(wuid);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
clearState(wuid?: string) {
|
|
385
|
-
this.clear({
|
|
386
|
-
Wuid: wuid,
|
|
387
|
-
StateID: WUStateID.Unknown
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
update(request: Partial<WsWorkunits.WUUpdate>): Promise<Workunit> {
|
|
392
|
-
return this.connection.WUUpdate({
|
|
393
|
-
...request,
|
|
394
|
-
...{
|
|
395
|
-
Wuid: this.Wuid,
|
|
396
|
-
StateOrig: this.StateID,
|
|
397
|
-
JobnameOrig: this.Jobname,
|
|
398
|
-
DescriptionOrig: this.Description,
|
|
399
|
-
ProtectedOrig: this.Protected,
|
|
400
|
-
ClusterOrig: this.Cluster
|
|
401
|
-
}
|
|
402
|
-
}).then((response) => {
|
|
403
|
-
this.set(response.Workunit);
|
|
404
|
-
return this;
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
submit(_cluster?: string, action: WUUpdate.Action = WUUpdate.Action.Run, resultLimit?: number): Promise<Workunit> {
|
|
409
|
-
let clusterPromise;
|
|
410
|
-
if (_cluster !== void 0) {
|
|
411
|
-
clusterPromise = Promise.resolve(_cluster);
|
|
412
|
-
} else {
|
|
413
|
-
clusterPromise = this.topologyConnection.DefaultTpLogicalClusterQuery().then((response) => {
|
|
414
|
-
return response.Name;
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
this._debugMode = false;
|
|
419
|
-
if (action === WUUpdate.Action.Debug) {
|
|
420
|
-
action = WUUpdate.Action.Run;
|
|
421
|
-
this._debugMode = true;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
return clusterPromise.then((cluster) => {
|
|
425
|
-
return this.connection.WUUpdate({
|
|
426
|
-
Wuid: this.Wuid,
|
|
427
|
-
Action: action,
|
|
428
|
-
ResultLimit: resultLimit,
|
|
429
|
-
DebugValues: {
|
|
430
|
-
DebugValue: [
|
|
431
|
-
{
|
|
432
|
-
Name: "Debug",
|
|
433
|
-
Value: this._debugMode ? "1" : ""
|
|
434
|
-
}
|
|
435
|
-
]
|
|
436
|
-
}
|
|
437
|
-
}).then((response) => {
|
|
438
|
-
this.set(response.Workunit);
|
|
439
|
-
this._submitAction = action;
|
|
440
|
-
return this.connection.WUSubmit({ Wuid: this.Wuid, Cluster: cluster });
|
|
441
|
-
});
|
|
442
|
-
}).then(() => {
|
|
443
|
-
return this;
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
isComplete(): boolean {
|
|
448
|
-
switch (this.StateID) {
|
|
449
|
-
case WUStateID.Compiled:
|
|
450
|
-
return this.ActionEx === "compile" || this._submitAction === WUUpdate.Action.Compile;
|
|
451
|
-
case WUStateID.Completed:
|
|
452
|
-
case WUStateID.Failed:
|
|
453
|
-
case WUStateID.Aborted:
|
|
454
|
-
case WUStateID.NotFound:
|
|
455
|
-
return true;
|
|
456
|
-
default:
|
|
457
|
-
}
|
|
458
|
-
return false;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
isFailed() {
|
|
462
|
-
switch (this.StateID) {
|
|
463
|
-
case WUStateID.Aborted:
|
|
464
|
-
case WUStateID.Failed:
|
|
465
|
-
return true;
|
|
466
|
-
default:
|
|
467
|
-
}
|
|
468
|
-
return false;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
isDeleted() {
|
|
472
|
-
switch (this.StateID) {
|
|
473
|
-
case WUStateID.NotFound:
|
|
474
|
-
return true;
|
|
475
|
-
default:
|
|
476
|
-
}
|
|
477
|
-
return false;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
isDebugging() {
|
|
481
|
-
switch (this.StateID) {
|
|
482
|
-
case WUStateID.DebugPaused:
|
|
483
|
-
case WUStateID.DebugRunning:
|
|
484
|
-
return true;
|
|
485
|
-
default:
|
|
486
|
-
}
|
|
487
|
-
return this._debugMode;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
isRunning(): boolean {
|
|
491
|
-
switch (this.StateID) {
|
|
492
|
-
case WUStateID.Compiled:
|
|
493
|
-
case WUStateID.Running:
|
|
494
|
-
case WUStateID.Aborting:
|
|
495
|
-
case WUStateID.Blocked:
|
|
496
|
-
case WUStateID.DebugPaused:
|
|
497
|
-
case WUStateID.DebugRunning:
|
|
498
|
-
return true;
|
|
499
|
-
default:
|
|
500
|
-
}
|
|
501
|
-
return false;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
setToFailed() {
|
|
505
|
-
return this.WUAction(WsWorkunits.ECLWUActions.SetToFailed);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
pause() {
|
|
509
|
-
return this.WUAction(WsWorkunits.ECLWUActions.Pause);
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
pauseNow() {
|
|
513
|
-
return this.WUAction(WsWorkunits.ECLWUActions.PauseNow);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
resume() {
|
|
517
|
-
return this.WUAction(WsWorkunits.ECLWUActions.Resume);
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
abort() {
|
|
521
|
-
return this.WUAction(WsWorkunits.ECLWUActions.Abort);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
protect() {
|
|
525
|
-
return this.WUAction(WsWorkunits.ECLWUActions.Protect);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
unprotect() {
|
|
529
|
-
return this.WUAction(WsWorkunits.ECLWUActions.Unprotect);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
delete() {
|
|
533
|
-
return this.WUAction(WsWorkunits.ECLWUActions.Delete);
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
restore() {
|
|
537
|
-
return this.WUAction(WsWorkunits.ECLWUActions.Restore);
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
deschedule() {
|
|
541
|
-
return this.WUAction(WsWorkunits.ECLWUActions.Deschedule);
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
reschedule() {
|
|
545
|
-
return this.WUAction(WsWorkunits.ECLWUActions.Reschedule);
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
resubmit(): Promise<Workunit> {
|
|
549
|
-
return this.WUResubmit({
|
|
550
|
-
CloneWorkunit: false,
|
|
551
|
-
ResetWorkflow: false
|
|
552
|
-
}).then(() => {
|
|
553
|
-
this.clearState(this.Wuid);
|
|
554
|
-
return this.refresh().then(() => {
|
|
555
|
-
this._monitor();
|
|
556
|
-
return this;
|
|
557
|
-
});
|
|
558
|
-
});
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
clone(): Promise<Workunit> {
|
|
562
|
-
return this.WUResubmit({
|
|
563
|
-
CloneWorkunit: true,
|
|
564
|
-
ResetWorkflow: false
|
|
565
|
-
}).then((response) => {
|
|
566
|
-
return Workunit.attach(this.connection.opts(), response.WUs.WU[0].WUID)
|
|
567
|
-
.refresh()
|
|
568
|
-
;
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
async refreshState(): Promise<this> {
|
|
573
|
-
await this.WUQuery();
|
|
574
|
-
// Ensure "isComplete" is correct for WUs that are only "Compiled".
|
|
575
|
-
if (this.StateID === WUStateID.Compiled && !this.ActionEx && !this._submitAction) {
|
|
576
|
-
await this.refreshInfo();
|
|
577
|
-
}
|
|
578
|
-
return this;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
async refreshInfo(request?: Partial<WsWorkunits.WUInfo>): Promise<this> {
|
|
582
|
-
await this.WUInfo(request);
|
|
583
|
-
return this;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
async refreshDebug(): Promise<this> {
|
|
587
|
-
await this.debugStatus();
|
|
588
|
-
return this;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
async refresh(full: boolean = false, request?: Partial<WsWorkunits.WUInfo>): Promise<this> {
|
|
592
|
-
if (full) {
|
|
593
|
-
await Promise.all([this.refreshInfo(request), this.refreshDebug()]);
|
|
594
|
-
} else {
|
|
595
|
-
await this.refreshState();
|
|
596
|
-
}
|
|
597
|
-
return this;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
eclExceptions(): WsWorkunits.ECLException[] {
|
|
601
|
-
return this.Exceptions.ECLException;
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
fetchArchive(): Promise<string> {
|
|
605
|
-
return this.connection.WUFileEx({
|
|
606
|
-
Wuid: this.Wuid,
|
|
607
|
-
Type: "ArchiveQuery"
|
|
608
|
-
});
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
fetchECLExceptions(): Promise<WsWorkunits.ECLException[]> {
|
|
612
|
-
return this.WUInfo({ IncludeExceptions: true }).then(() => {
|
|
613
|
-
return this.eclExceptions();
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
fetchResults(): Promise<Result[]> {
|
|
618
|
-
return this.WUInfo({ IncludeResults: true }).then(() => {
|
|
619
|
-
return this.CResults;
|
|
620
|
-
});
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
fetchGraphs(): Promise<ECLGraph[]> {
|
|
624
|
-
return this.WUInfo({ IncludeGraphs: true }).then(() => {
|
|
625
|
-
return this.CGraphs;
|
|
626
|
-
});
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
fetchQuery(): Promise<WsWorkunits.Query> {
|
|
630
|
-
return this.WUInfo({ IncludeECL: true, TruncateEclTo64k: false }).then(() => {
|
|
631
|
-
return this.Query;
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
fetchHelpers(): Promise<WsWorkunits.ECLHelpFile[]> {
|
|
636
|
-
return this.WUInfo({ IncludeHelpers: true }).then(() => {
|
|
637
|
-
return this.Helpers?.ECLHelpFile || [];
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
fetchAllowedClusters(): Promise<string[]> {
|
|
642
|
-
return this.WUInfo({ IncludeAllowedClusters: true }).then(() => {
|
|
643
|
-
return this.AllowedClusters?.AllowedCluster || [];
|
|
644
|
-
});
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
fetchTotalClusterTime(): Promise<string> {
|
|
648
|
-
return this.WUInfo({ IncludeTotalClusterTime: true }).then(() => {
|
|
649
|
-
return this.TotalClusterTime;
|
|
650
|
-
});
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
fetchServiceNames(): Promise<string[]> {
|
|
654
|
-
return this.WUInfo({ IncludeServiceNames: true }).then(() => {
|
|
655
|
-
return this.ServiceNames?.Item;
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
fetchDetailsMeta(request: RecursivePartial<WsWorkunits.WUDetailsMeta> = {}): Promise<WsWorkunits.WUDetailsMetaResponse> {
|
|
660
|
-
return this.WUDetailsMeta(request);
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
fetchDetailsRaw(request: RecursivePartial<WsWorkunits.WUDetails> = {}): Promise<WsWorkunits.Scope[]> {
|
|
664
|
-
return this.WUDetails(request).then(response => response.Scopes.Scope);
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
normalizeDetails(meta: WsWorkunits.WUDetailsMetaResponse, scopes: WsWorkunits.Scope[]): { meta: WsWorkunits.WUDetailsMetaResponse, columns: { [id: string]: any }, data: IScope[] } {
|
|
668
|
-
const columns: { [id: string]: any } = {
|
|
669
|
-
id: {
|
|
670
|
-
Measure: "label"
|
|
671
|
-
},
|
|
672
|
-
name: {
|
|
673
|
-
Measure: "label"
|
|
674
|
-
},
|
|
675
|
-
type: {
|
|
676
|
-
Measure: "label"
|
|
677
|
-
}
|
|
678
|
-
};
|
|
679
|
-
const activityMap = new Map<number, string>();
|
|
680
|
-
for (const activity of meta.Activities?.Activity ?? []) {
|
|
681
|
-
activityMap.set(activity.Kind, activity.Name);
|
|
682
|
-
}
|
|
683
|
-
const data: IScope[] = new Array(scopes.length);
|
|
684
|
-
for (let i = 0; i < scopes.length; i++) {
|
|
685
|
-
const scope = scopes[i];
|
|
686
|
-
const props: { [key: string]: any } = {};
|
|
687
|
-
const formattedProps: { [key: string]: any } = {};
|
|
688
|
-
if (scope.
|
|
689
|
-
for (const scopeProperty of scope.Properties.Property) {
|
|
690
|
-
const measure = scopeProperty.Measure;
|
|
691
|
-
const name = scopeProperty.Name;
|
|
692
|
-
const rawValue = scopeProperty.RawValue;
|
|
693
|
-
if (measure === "ns") {
|
|
694
|
-
scopeProperty.Measure = "s";
|
|
695
|
-
}
|
|
696
|
-
if (name === "Kind") {
|
|
697
|
-
const rawValueInt = parseInt(rawValue, 10);
|
|
698
|
-
scopeProperty.Formatted = activityMap.get(rawValueInt) ?? rawValue;
|
|
699
|
-
}
|
|
700
|
-
columns[name] = {
|
|
701
|
-
Name: scopeProperty.Name,
|
|
702
|
-
Measure: scopeProperty.Measure,
|
|
703
|
-
Creator: scopeProperty.Creator,
|
|
704
|
-
CreatorType: scopeProperty.CreatorType
|
|
705
|
-
};
|
|
706
|
-
switch (scopeProperty.Measure) {
|
|
707
|
-
case "bool":
|
|
708
|
-
props[name] = !!+rawValue;
|
|
709
|
-
break;
|
|
710
|
-
case "sz":
|
|
711
|
-
props[name] = +rawValue;
|
|
712
|
-
break;
|
|
713
|
-
case "s":
|
|
714
|
-
props[name] = +rawValue / 1000000000;
|
|
715
|
-
break;
|
|
716
|
-
case "ns":
|
|
717
|
-
props[name] = +rawValue;
|
|
718
|
-
break;
|
|
719
|
-
case "ts":
|
|
720
|
-
props[name] = new Date(+rawValue / 1000).toISOString();
|
|
721
|
-
break;
|
|
722
|
-
case "cnt":
|
|
723
|
-
props[name] = +rawValue;
|
|
724
|
-
break;
|
|
725
|
-
case "cost":
|
|
726
|
-
props[name] = +rawValue / 1000000;
|
|
727
|
-
break;
|
|
728
|
-
case "node":
|
|
729
|
-
props[name] = +rawValue;
|
|
730
|
-
break;
|
|
731
|
-
case "skw":
|
|
732
|
-
props[name] = +rawValue;
|
|
733
|
-
break;
|
|
734
|
-
case "cpu":
|
|
735
|
-
case "ppm":
|
|
736
|
-
case "ip":
|
|
737
|
-
case "cy":
|
|
738
|
-
case "en":
|
|
739
|
-
case "txt":
|
|
740
|
-
case "id":
|
|
741
|
-
case "fname":
|
|
742
|
-
default:
|
|
743
|
-
props[name] = rawValue;
|
|
744
|
-
}
|
|
745
|
-
formattedProps[name] = formatNum(scopeProperty.Formatted ?? props[name]);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
const normalizedScope: IScope = {
|
|
749
|
-
id: scope.Id,
|
|
750
|
-
name: scope.ScopeName,
|
|
751
|
-
type: scope.ScopeType,
|
|
752
|
-
Kind: scope["Kind"],
|
|
753
|
-
Label: scope["Label"],
|
|
754
|
-
__formattedProps: formattedProps,
|
|
755
|
-
__groupedProps: {},
|
|
756
|
-
__groupedRawProps: {},
|
|
757
|
-
__StdDevs: 0,
|
|
758
|
-
__StdDevsSource: "",
|
|
759
|
-
...props
|
|
760
|
-
};
|
|
761
|
-
const definitionList = normalizedScope[DEFINITION_LIST];
|
|
762
|
-
if (definitionList) {
|
|
763
|
-
try {
|
|
764
|
-
const parsedList = JSON.parse(definitionList.split("\\").join("\\\\"));
|
|
765
|
-
const processedDefinitions: Array<{ filePath: string, line: number, col: number }> = [];
|
|
766
|
-
|
|
767
|
-
for (let k = 0; k < parsedList.length; k++) {
|
|
768
|
-
const matches = parsedList[k].match(definitionRegex);
|
|
769
|
-
if (matches) {
|
|
770
|
-
processedDefinitions.push({
|
|
771
|
-
filePath: (matches[1] ?? "") + matches[2] + matches[3],
|
|
772
|
-
line: parseInt(matches[5], 10),
|
|
773
|
-
col: parseInt(matches[6], 10)
|
|
774
|
-
});
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
normalizedScope[DEFINITION_LIST] = processedDefinitions;
|
|
778
|
-
} catch (e) {
|
|
779
|
-
logger.error(`Unexpected "DefinitionList": ${definitionList}`);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
const dedup: DedupProperties = {};
|
|
784
|
-
let maxStdDevs = 0;
|
|
785
|
-
let maxStdDevsSource = "";
|
|
786
|
-
for (const key in normalizedScope) {
|
|
787
|
-
if (!key.startsWith("__")) {
|
|
788
|
-
const row = formatValues(normalizedScope, key, dedup);
|
|
789
|
-
if (row) {
|
|
790
|
-
normalizedScope.__groupedProps[row.Key] = row;
|
|
791
|
-
if (!isNaN(row.StdDevs) && row.StdDevs > maxStdDevs) {
|
|
792
|
-
maxStdDevs = row.StdDevs;
|
|
793
|
-
maxStdDevsSource = row.Key;
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
normalizedScope.__StdDevs = maxStdDevs;
|
|
799
|
-
normalizedScope.__StdDevsSource = maxStdDevsSource;
|
|
800
|
-
|
|
801
|
-
data[i] = normalizedScope;
|
|
802
|
-
}
|
|
803
|
-
return {
|
|
804
|
-
meta,
|
|
805
|
-
columns,
|
|
806
|
-
data
|
|
807
|
-
};
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
fetchDetailsNormalized(request: RecursivePartial<WsWorkunits.WUDetails> = {}): Promise<{ meta: WsWorkunits.WUDetailsMetaResponse, columns: { [id: string]: any }, data: IScope[] }> {
|
|
811
|
-
return Promise.all([this.fetchDetailsMeta(), this.fetchDetailsRaw(request)]).then(promises => {
|
|
812
|
-
return this.normalizeDetails(promises[0], promises[1]);
|
|
813
|
-
});
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
fetchInfo(request: Partial<WsWorkunits.WUInfo> = {}): Promise<WsWorkunits.WUInfoResponse> {
|
|
817
|
-
return this.WUInfo(request);
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
fetchDetails(request: RecursivePartial<WsWorkunits.WUDetails> = {}): Promise<Scope[]> {
|
|
821
|
-
return this.WUDetails(request).then((response) => {
|
|
822
|
-
return response.Scopes.Scope.map((rawScope) => {
|
|
823
|
-
return new Scope(this, rawScope);
|
|
824
|
-
});
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
fetchDetailsHierarchy(request: Partial<WsWorkunits.WUDetails> = {}): Promise<Scope[]> {
|
|
829
|
-
return this.WUDetails(request).then((response) => {
|
|
830
|
-
const retVal: Scope[] = [];
|
|
831
|
-
|
|
832
|
-
// Recreate
|
|
833
|
-
const scopeMap: { [key: string]: Scope } = {};
|
|
834
|
-
response.Scopes.Scope.forEach((rawScope) => {
|
|
835
|
-
if (scopeMap[rawScope.ScopeName]) {
|
|
836
|
-
scopeMap[rawScope.ScopeName].update(rawScope);
|
|
837
|
-
return null;
|
|
838
|
-
} else {
|
|
839
|
-
const scope = new Scope(this, rawScope);
|
|
840
|
-
scopeMap[scope.ScopeName] = scope;
|
|
841
|
-
return scope;
|
|
842
|
-
}
|
|
843
|
-
});
|
|
844
|
-
for (const key in scopeMap) {
|
|
845
|
-
if (scopeMap.hasOwnProperty(key)) {
|
|
846
|
-
const scope = scopeMap[key];
|
|
847
|
-
const parentScopeID = scope.parentScope();
|
|
848
|
-
if (parentScopeID && scopeMap[parentScopeID]) {
|
|
849
|
-
scopeMap[parentScopeID].children().push(scope);
|
|
850
|
-
} else {
|
|
851
|
-
retVal.push(scope);
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
return retVal;
|
|
857
|
-
});
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
fetchGraphDetails(graphIDs: string[] = [], rootTypes: string[]): Promise<BaseScope[]> {
|
|
861
|
-
return this.fetchDetails({
|
|
862
|
-
ScopeFilter: {
|
|
863
|
-
MaxDepth: 999999,
|
|
864
|
-
Ids: graphIDs,
|
|
865
|
-
ScopeTypes: rootTypes,
|
|
866
|
-
},
|
|
867
|
-
NestedFilter: {
|
|
868
|
-
Depth: 999999,
|
|
869
|
-
ScopeTypes: ["graph", "subgraph", "activity", "edge", "function"]
|
|
870
|
-
},
|
|
871
|
-
PropertiesToReturn: {
|
|
872
|
-
AllStatistics: true,
|
|
873
|
-
AllAttributes: true,
|
|
874
|
-
AllHints: true,
|
|
875
|
-
AllProperties: true,
|
|
876
|
-
AllScopes: true
|
|
877
|
-
},
|
|
878
|
-
ScopeOptions: {
|
|
879
|
-
IncludeId: true,
|
|
880
|
-
IncludeScope: true,
|
|
881
|
-
IncludeScopeType: true
|
|
882
|
-
},
|
|
883
|
-
PropertyOptions: {
|
|
884
|
-
IncludeName: true,
|
|
885
|
-
IncludeRawValue: true,
|
|
886
|
-
IncludeFormatted: true,
|
|
887
|
-
IncludeMeasure: true,
|
|
888
|
-
IncludeCreator: false,
|
|
889
|
-
IncludeCreatorType: false
|
|
890
|
-
}
|
|
891
|
-
});
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
fetchScopeGraphs(graphIDs: string[] = []): Promise<ScopeGraph> {
|
|
895
|
-
return this.fetchGraphDetails(graphIDs, ["graph"]).then((scopes) => {
|
|
896
|
-
return createGraph(scopes);
|
|
897
|
-
});
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
fetchTimeElapsed(): Promise<ITimeElapsed[]> {
|
|
901
|
-
return this.fetchDetails({
|
|
902
|
-
ScopeFilter: {
|
|
903
|
-
PropertyFilters: {
|
|
904
|
-
PropertyFilter: [{ Name: "TimeElapsed" }]
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
}).then((scopes) => {
|
|
908
|
-
const scopeInfo: { [key: string]: ITimeElapsed } = {};
|
|
909
|
-
scopes.forEach((scope) => {
|
|
910
|
-
scopeInfo[scope.ScopeName] = scopeInfo[scope.ScopeName] || {
|
|
911
|
-
scope: scope.ScopeName,
|
|
912
|
-
start: null,
|
|
913
|
-
elapsed: null,
|
|
914
|
-
finish: null
|
|
915
|
-
};
|
|
916
|
-
scope.CAttributes.forEach((attr) => {
|
|
917
|
-
if (attr.Name === "TimeElapsed") {
|
|
918
|
-
scopeInfo[scope.ScopeName].elapsed = +attr.RawValue;
|
|
919
|
-
} else if (attr.Measure === "ts" && attr.Name.indexOf("Started") >= 0) {
|
|
920
|
-
scopeInfo[scope.ScopeName].start = attr.Formatted;
|
|
921
|
-
}
|
|
922
|
-
});
|
|
923
|
-
});
|
|
924
|
-
// Workaround duplicate scope responses
|
|
925
|
-
const retVal: ITimeElapsed[] = [];
|
|
926
|
-
for (const key in scopeInfo) {
|
|
927
|
-
const scope = scopeInfo[key];
|
|
928
|
-
if (scope.start && scope.elapsed) {
|
|
929
|
-
const endTime = parser(scope.start);
|
|
930
|
-
endTime!.setMilliseconds(endTime!.getMilliseconds() + scope.elapsed / 1000000);
|
|
931
|
-
scope.finish = formatter(endTime!);
|
|
932
|
-
retVal.push(scope);
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
retVal.sort((l, r) => {
|
|
936
|
-
if (l.start < r.start) return -1;
|
|
937
|
-
if (l.start > r.start) return 1;
|
|
938
|
-
return 0;
|
|
939
|
-
});
|
|
940
|
-
return retVal;
|
|
941
|
-
});
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
// Monitoring ---
|
|
945
|
-
protected _monitor(): void {
|
|
946
|
-
if (this.isComplete()) {
|
|
947
|
-
this._monitorTickCount = 0;
|
|
948
|
-
return;
|
|
949
|
-
}
|
|
950
|
-
super._monitor();
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
protected _monitorTimeoutDuration(): number {
|
|
954
|
-
const retVal = super._monitorTimeoutDuration();
|
|
955
|
-
if (this._monitorTickCount <= 1) { // Once
|
|
956
|
-
return 1000;
|
|
957
|
-
} else if (this._monitorTickCount <= 3) { // Twice
|
|
958
|
-
return 3000;
|
|
959
|
-
} else if (this._monitorTickCount <= 5) { // Twice
|
|
960
|
-
return 5000;
|
|
961
|
-
} else if (this._monitorTickCount <= 7) { // Twice
|
|
962
|
-
return 10000;
|
|
963
|
-
}
|
|
964
|
-
return retVal;
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
// Events ---
|
|
968
|
-
on(eventID: WorkunitEvents, propIDorCallback: StateCallback | keyof UWorkunitState, callback?: StatePropCallback): this {
|
|
969
|
-
if (this.isCallback(propIDorCallback)) {
|
|
970
|
-
switch (eventID) {
|
|
971
|
-
case "completed":
|
|
972
|
-
super.on("propChanged", "StateID", (changeInfo: IEvent) => {
|
|
973
|
-
if (this.isComplete()) {
|
|
974
|
-
propIDorCallback([changeInfo]);
|
|
975
|
-
}
|
|
976
|
-
});
|
|
977
|
-
break;
|
|
978
|
-
case "changed":
|
|
979
|
-
super.on(eventID, propIDorCallback);
|
|
980
|
-
break;
|
|
981
|
-
default:
|
|
982
|
-
}
|
|
983
|
-
} else {
|
|
984
|
-
switch (eventID) {
|
|
985
|
-
case "changed":
|
|
986
|
-
super.on(eventID, propIDorCallback, callback!);
|
|
987
|
-
break;
|
|
988
|
-
default:
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
this._monitor();
|
|
992
|
-
return this;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
watchUntilComplete(callback?: StateCallback): Promise<this> {
|
|
996
|
-
return new Promise((resolve, _) => {
|
|
997
|
-
const watchHandle = this.watch((changes) => {
|
|
998
|
-
if (callback) {
|
|
999
|
-
callback(changes);
|
|
1000
|
-
}
|
|
1001
|
-
if (this.isComplete()) {
|
|
1002
|
-
watchHandle.release();
|
|
1003
|
-
resolve(this);
|
|
1004
|
-
}
|
|
1005
|
-
});
|
|
1006
|
-
});
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
watchUntilRunning(callback?: StateCallback): Promise<this> {
|
|
1010
|
-
return new Promise((resolve, _) => {
|
|
1011
|
-
const watchHandle = this.watch((changes) => {
|
|
1012
|
-
if (callback) {
|
|
1013
|
-
callback(changes);
|
|
1014
|
-
}
|
|
1015
|
-
if (this.isComplete() || this.isRunning()) {
|
|
1016
|
-
watchHandle.release();
|
|
1017
|
-
resolve(this);
|
|
1018
|
-
}
|
|
1019
|
-
});
|
|
1020
|
-
});
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
// WsWorkunits passthroughs ---
|
|
1024
|
-
protected WUQuery(_request: Partial<WsWorkunits.WUQuery> = {}): Promise<WsWorkunits.WUQueryResponse> {
|
|
1025
|
-
return this.connection.WUQuery({ ..._request, Wuid: this.Wuid }).then((response) => {
|
|
1026
|
-
if (response.Workunits.ECLWorkunit.length === 0) {
|
|
1027
|
-
// deleted ---
|
|
1028
|
-
this.clearState(this.Wuid);
|
|
1029
|
-
this.set("StateID", WUStateID.NotFound);
|
|
1030
|
-
} else {
|
|
1031
|
-
this.set(response.Workunits.ECLWorkunit[0]);
|
|
1032
|
-
}
|
|
1033
|
-
return response;
|
|
1034
|
-
}).catch((e: ESPExceptions) => {
|
|
1035
|
-
// deleted ---
|
|
1036
|
-
const wuMissing = e.Exception.some((exception) => {
|
|
1037
|
-
if (exception.Code === 20081) {
|
|
1038
|
-
this.clearState(this.Wuid);
|
|
1039
|
-
this.set("StateID", WUStateID.NotFound);
|
|
1040
|
-
return true;
|
|
1041
|
-
}
|
|
1042
|
-
return false;
|
|
1043
|
-
});
|
|
1044
|
-
if (!wuMissing) {
|
|
1045
|
-
logger.warning(`Unexpected ESP exception: ${e.message}`);
|
|
1046
|
-
throw e;
|
|
1047
|
-
}
|
|
1048
|
-
return {} as WsWorkunits.WUQueryResponse;
|
|
1049
|
-
});
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
protected WUCreate() {
|
|
1053
|
-
return this.connection.WUCreate().then((response) => {
|
|
1054
|
-
this.set(response.Workunit);
|
|
1055
|
-
_workunits.set(this);
|
|
1056
|
-
return response;
|
|
1057
|
-
});
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
protected WUInfo(_request: Partial<WsWorkunits.WUInfo> = {}): Promise<WsWorkunits.WUInfoResponse> {
|
|
1061
|
-
const includeResults = _request.IncludeResults || _request.IncludeResultsViewNames;
|
|
1062
|
-
return this.connection.WUInfo({
|
|
1063
|
-
..._request,
|
|
1064
|
-
Wuid: this.Wuid,
|
|
1065
|
-
IncludeResults: includeResults,
|
|
1066
|
-
IncludeResultsViewNames: includeResults,
|
|
1067
|
-
SuppressResultSchemas: false
|
|
1068
|
-
}).then((response) => {
|
|
1069
|
-
this.set(response.Workunit);
|
|
1070
|
-
if (includeResults) {
|
|
1071
|
-
this.set({
|
|
1072
|
-
ResultViews: response.ResultViews
|
|
1073
|
-
} as IWorkunitState);
|
|
1074
|
-
}
|
|
1075
|
-
return response;
|
|
1076
|
-
}).catch((e: ESPExceptions) => {
|
|
1077
|
-
// deleted ---
|
|
1078
|
-
const wuMissing = e.Exception.some((exception) => {
|
|
1079
|
-
if (exception.Code === 20080) {
|
|
1080
|
-
this.clearState(this.Wuid);
|
|
1081
|
-
this.set("StateID", WUStateID.NotFound);
|
|
1082
|
-
return true;
|
|
1083
|
-
}
|
|
1084
|
-
return false;
|
|
1085
|
-
});
|
|
1086
|
-
if (!wuMissing) {
|
|
1087
|
-
logger.warning(`Unexpected ESP exception: ${e.message}`);
|
|
1088
|
-
throw e;
|
|
1089
|
-
}
|
|
1090
|
-
return {} as WsWorkunits.WUInfoResponse;
|
|
1091
|
-
});
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
protected WUResubmit(request: Partial<WsWorkunits.WUResubmit>): Promise<WsWorkunits.WUResubmitResponse> {
|
|
1095
|
-
return this.connection.WUResubmit(deepMixinT<WsWorkunits.WUResubmit>({}, request, {
|
|
1096
|
-
Wuids: { Item: [this.Wuid] }
|
|
1097
|
-
}));
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
protected WUDetailsMeta(request: Partial<WsWorkunits.WUDetailsMeta>): Promise<WsWorkunits.WUDetailsMetaResponse> {
|
|
1101
|
-
return this.connection.WUDetailsMeta(request);
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
protected WUDetails(request: RecursivePartial<WsWorkunits.WUDetails>): Promise<WsWorkunits.WUDetailsResponse> {
|
|
1105
|
-
return this.connection.WUDetails(deepMixinT<WsWorkunits.WUDetails>({
|
|
1106
|
-
ScopeFilter: {
|
|
1107
|
-
MaxDepth: 9999
|
|
1108
|
-
},
|
|
1109
|
-
ScopeOptions: {
|
|
1110
|
-
IncludeMatchedScopesInResults: true,
|
|
1111
|
-
IncludeScope: true,
|
|
1112
|
-
IncludeId: false,
|
|
1113
|
-
IncludeScopeType: false
|
|
1114
|
-
},
|
|
1115
|
-
PropertyOptions: {
|
|
1116
|
-
IncludeName: true,
|
|
1117
|
-
IncludeRawValue: false,
|
|
1118
|
-
IncludeFormatted: true,
|
|
1119
|
-
IncludeMeasure: true,
|
|
1120
|
-
IncludeCreator: false,
|
|
1121
|
-
IncludeCreatorType: false
|
|
1122
|
-
}
|
|
1123
|
-
}, request, { WUID: this.Wuid })).then((response) => {
|
|
1124
|
-
return deepMixinT<WsWorkunits.WUDetailsResponse>({
|
|
1125
|
-
Scopes: {
|
|
1126
|
-
Scope: []
|
|
1127
|
-
}
|
|
1128
|
-
}, response);
|
|
1129
|
-
});
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
protected WUAction(actionType: WsWorkunits.ECLWUActions): Promise<WsWorkunits.WUActionResponse> {
|
|
1133
|
-
return this.connection.WUAction({
|
|
1134
|
-
Wuids: { Item: [this.Wuid] },
|
|
1135
|
-
WUActionType: actionType
|
|
1136
|
-
}).then((response) => {
|
|
1137
|
-
return this.refresh().then(() => {
|
|
1138
|
-
this._monitor();
|
|
1139
|
-
return response;
|
|
1140
|
-
});
|
|
1141
|
-
});
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
publish(name?: string) {
|
|
1145
|
-
return this.connection.WUPublishWorkunit({
|
|
1146
|
-
Wuid: this.Wuid,
|
|
1147
|
-
Cluster: this.Cluster,
|
|
1148
|
-
JobName: name || this.Jobname,
|
|
1149
|
-
AllowForeignFiles: true,
|
|
1150
|
-
Activate: WsWorkunits.WUQueryActivationMode.ActivateQuery,
|
|
1151
|
-
Wait: 5000
|
|
1152
|
-
});
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
publishEx(request: Partial<WsWorkunits.WUPublishWorkunit>) {
|
|
1156
|
-
const service = new WorkunitsServiceEx({ baseUrl: "" });
|
|
1157
|
-
const publishRequest = {
|
|
1158
|
-
Wuid: this.Wuid,
|
|
1159
|
-
Cluster: this.Cluster,
|
|
1160
|
-
JobName: this.Jobname,
|
|
1161
|
-
AllowForeignFiles: true,
|
|
1162
|
-
Activate: 1,
|
|
1163
|
-
Wait: 5000,
|
|
1164
|
-
...request
|
|
1165
|
-
};
|
|
1166
|
-
return service.WUPublishWorkunitEx(publishRequest);
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
protected WUCDebug(command: string, opts: any = {}): Promise<XMLNode | null> {
|
|
1170
|
-
let optsStr = "";
|
|
1171
|
-
for (const key in opts) {
|
|
1172
|
-
if (opts.hasOwnProperty(key)) {
|
|
1173
|
-
optsStr += ` ${key}='${opts[key]}'`;
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
return this.connection.WUCDebugEx({
|
|
1177
|
-
Wuid: this.Wuid,
|
|
1178
|
-
Command: `<debug:${command} uid='${this.Wuid}'${optsStr}/>`
|
|
1179
|
-
}).then((response) => {
|
|
1180
|
-
return response;
|
|
1181
|
-
});
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
debug(command: string, opts?: object): Promise<XMLNode> {
|
|
1185
|
-
if (!this.isDebugging()) {
|
|
1186
|
-
return Promise.resolve(new XMLNode(command));
|
|
1187
|
-
}
|
|
1188
|
-
return this.WUCDebug(command, opts).then((response: XMLNode) => {
|
|
1189
|
-
const retVal: XMLNode[] = response.children(command);
|
|
1190
|
-
if (retVal.length) {
|
|
1191
|
-
return retVal[0];
|
|
1192
|
-
}
|
|
1193
|
-
return new XMLNode(command);
|
|
1194
|
-
}).catch((_) => {
|
|
1195
|
-
logger.error(_);
|
|
1196
|
-
return Promise.resolve(new XMLNode(command));
|
|
1197
|
-
});
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
debugStatus(): Promise<XMLNode> {
|
|
1201
|
-
if (!this.isDebugging()) {
|
|
1202
|
-
return Promise.resolve<any>({
|
|
1203
|
-
DebugState: { state: "unknown" }
|
|
1204
|
-
});
|
|
1205
|
-
}
|
|
1206
|
-
return this.debug("status").then((response) => {
|
|
1207
|
-
const debugState = { ...this.DebugState, ...response.$ };
|
|
1208
|
-
this.set({
|
|
1209
|
-
DebugState: debugState
|
|
1210
|
-
});
|
|
1211
|
-
return response;
|
|
1212
|
-
});
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
debugContinue(mode = ""): Promise<XMLNode> {
|
|
1216
|
-
return this.debug("continue", {
|
|
1217
|
-
mode
|
|
1218
|
-
});
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
debugStep(mode: string): Promise<XMLNode> {
|
|
1222
|
-
return this.debug("step", {
|
|
1223
|
-
mode
|
|
1224
|
-
});
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
debugPause(): Promise<XMLNode> {
|
|
1228
|
-
return this.debug("interrupt");
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
|
-
debugQuit(): Promise<XMLNode> {
|
|
1232
|
-
return this.debug("quit");
|
|
1233
|
-
}
|
|
1234
|
-
|
|
1235
|
-
debugDeleteAllBreakpoints(): Promise<XMLNode> {
|
|
1236
|
-
return this.debug("delete", {
|
|
1237
|
-
idx: 0
|
|
1238
|
-
});
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
protected debugBreakpointResponseParser(rootNode: StringAnyMap) {
|
|
1242
|
-
return rootNode.children().map((childNode: XMLNode) => {
|
|
1243
|
-
if (childNode.name === "break") {
|
|
1244
|
-
return childNode.$;
|
|
1245
|
-
}
|
|
1246
|
-
});
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
debugBreakpointAdd(id: string, mode: string, action: string): Promise<XMLNode> {
|
|
1250
|
-
return this.debug("breakpoint", {
|
|
1251
|
-
id,
|
|
1252
|
-
mode,
|
|
1253
|
-
action
|
|
1254
|
-
}).then((rootNode) => {
|
|
1255
|
-
return this.debugBreakpointResponseParser(rootNode);
|
|
1256
|
-
});
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
debugBreakpointList(): Promise<any[]> {
|
|
1260
|
-
return this.debug("list").then((rootNode) => {
|
|
1261
|
-
return this.debugBreakpointResponseParser(rootNode);
|
|
1262
|
-
});
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
debugGraph(): Promise<XGMMLGraph> {
|
|
1266
|
-
if (this._debugAllGraph && this.DebugState["_prevGraphSequenceNum"] === this.DebugState["graphSequenceNum"]) {
|
|
1267
|
-
return Promise.resolve(this._debugAllGraph);
|
|
1268
|
-
}
|
|
1269
|
-
return this.debug("graph", { name: "all" }).then((response) => {
|
|
1270
|
-
this.DebugState["_prevGraphSequenceNum"] = this.DebugState["graphSequenceNum"];
|
|
1271
|
-
this._debugAllGraph = createXGMMLGraph(this.Wuid, response);
|
|
1272
|
-
return this._debugAllGraph;
|
|
1273
|
-
});
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
debugBreakpointValid(path: string): Promise<IECLDefintion[]> {
|
|
1277
|
-
return this.debugGraph().then((graph) => {
|
|
1278
|
-
return breakpointLocations(graph, path);
|
|
1279
|
-
});
|
|
1280
|
-
}
|
|
1281
|
-
|
|
1282
|
-
debugPrint(edgeID: string, startRow: number = 0, numRows: number = 10): Promise<StringAnyMap[]> {
|
|
1283
|
-
return this.debug("print", {
|
|
1284
|
-
edgeID,
|
|
1285
|
-
startRow,
|
|
1286
|
-
numRows
|
|
1287
|
-
}).then((response: XMLNode) => {
|
|
1288
|
-
return response.children().map((rowNode) => {
|
|
1289
|
-
const retVal: StringAnyMap = {};
|
|
1290
|
-
rowNode.children().forEach((cellNode) => {
|
|
1291
|
-
retVal[cellNode.name] = cellNode.content;
|
|
1292
|
-
});
|
|
1293
|
-
return retVal;
|
|
1294
|
-
});
|
|
1295
|
-
});
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
export interface IECLDefintion {
|
|
1300
|
-
id: string;
|
|
1301
|
-
file: string;
|
|
1302
|
-
line: number;
|
|
1303
|
-
column: number;
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
const ATTR_DEFINITION = "definition";
|
|
1307
|
-
|
|
1308
|
-
function hasECLDefinition(vertex: XGMMLVertex): boolean {
|
|
1309
|
-
return vertex._![ATTR_DEFINITION] !== undefined;
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
function getECLDefinition(vertex: XGMMLVertex): IECLDefintion {
|
|
1313
|
-
const match = /([a-z]:\\(?:[-\w\.\d]+\\)*(?:[-\w\.\d]+)?|(?:\/[\w\.\-]+)+)\((\d*),(\d*)\)/.exec(vertex._![ATTR_DEFINITION]);
|
|
1314
|
-
if (match) {
|
|
1315
|
-
const [, _file, _row, _col] = match;
|
|
1316
|
-
_file.replace(/\/\.\//g, "/");
|
|
1317
|
-
return {
|
|
1318
|
-
id: vertex._!["id"],
|
|
1319
|
-
file: _file,
|
|
1320
|
-
line: +_row,
|
|
1321
|
-
column: +_col
|
|
1322
|
-
};
|
|
1323
|
-
}
|
|
1324
|
-
throw new Error(`Bad definition: ${vertex._![ATTR_DEFINITION]}`);
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
function breakpointLocations(graph: XGMMLGraph, path?: string): IECLDefintion[] {
|
|
1328
|
-
const retVal: IECLDefintion[] = [];
|
|
1329
|
-
for (const vertex of graph.vertices) {
|
|
1330
|
-
if (hasECLDefinition(vertex)) {
|
|
1331
|
-
const definition = getECLDefinition(vertex);
|
|
1332
|
-
if (definition && !path || path === definition.file) {
|
|
1333
|
-
retVal.push(definition);
|
|
1334
|
-
}
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
return retVal.sort((l, r) => {
|
|
1338
|
-
return l.line - r.line;
|
|
1339
|
-
});
|
|
1340
|
-
}
|
|
1
|
+
import { Cache, deepMixinT, IEvent, RecursivePartial, scopedLogger, StateCallback, StateEvents, StateObject, StatePropCallback, StringAnyMap, XMLNode } from "@hpcc-js/util";
|
|
2
|
+
import { format as d3Format } from "d3-format";
|
|
3
|
+
import { utcFormat, utcParse } from "d3-time-format";
|
|
4
|
+
import { IConnection, IOptions } from "../connection.ts";
|
|
5
|
+
import { ESPExceptions } from "../espConnection.ts";
|
|
6
|
+
import { WsSMC } from "../services/wsSMC.ts";
|
|
7
|
+
import * as WsTopology from "../services/wsTopology.ts";
|
|
8
|
+
import { WsWorkunits, WUStateID, WorkunitsService, WorkunitsServiceEx, WUUpdate } from "../services/wsWorkunits.ts";
|
|
9
|
+
import { createGraph, createXGMMLGraph, ECLGraph, GraphCache, ScopeGraph, XGMMLGraph, XGMMLVertex } from "./graph.ts";
|
|
10
|
+
import { Resource } from "./resource.ts";
|
|
11
|
+
import { Result, ResultCache } from "./result.ts";
|
|
12
|
+
import { BaseScope, Scope } from "./scope.ts";
|
|
13
|
+
import { SourceFile } from "./sourceFile.ts";
|
|
14
|
+
import { Timer } from "./timer.ts";
|
|
15
|
+
|
|
16
|
+
const formatter = utcFormat("%Y-%m-%dT%H:%M:%S.%LZ");
|
|
17
|
+
const parser = utcParse("%Y-%m-%dT%H:%M:%S.%LZ");
|
|
18
|
+
const d3FormatNum = d3Format(",");
|
|
19
|
+
function formatNum(num: number | string): string {
|
|
20
|
+
if (num && !isNaN(+num)) {
|
|
21
|
+
return d3FormatNum(+num);
|
|
22
|
+
}
|
|
23
|
+
return num as string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function safeDelete(obj: { [id: string]: any; }, key: string, prop: string) {
|
|
27
|
+
if (obj[key] === undefined || obj[key][prop] === undefined) return;
|
|
28
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") return;
|
|
29
|
+
delete obj[key][prop];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const DEFINITION_LIST = "DefinitionList";
|
|
33
|
+
const definitionRegex = /([a-zA-Z]:)?(.*[\\\/])(.*)(\((\d+),(\d+)\))/;
|
|
34
|
+
|
|
35
|
+
export const PropertyType = ["Avg", "Min", "Max", "Delta", "StdDev"];
|
|
36
|
+
export const RelatedProperty = ["SkewMin", "SkewMax", "NodeMin", "NodeMax"];
|
|
37
|
+
|
|
38
|
+
export interface IPropertyValue {
|
|
39
|
+
Key: string;
|
|
40
|
+
Value?: string;
|
|
41
|
+
|
|
42
|
+
// Extended properties ---
|
|
43
|
+
Avg?: string;
|
|
44
|
+
Min?: string;
|
|
45
|
+
Max?: string;
|
|
46
|
+
Delta?: string;
|
|
47
|
+
StdDev?: string;
|
|
48
|
+
StdDevs?: number;
|
|
49
|
+
|
|
50
|
+
// Related properties ---
|
|
51
|
+
SkewMin?: string;
|
|
52
|
+
SkewMax?: string;
|
|
53
|
+
NodeMin?: string;
|
|
54
|
+
NodeMax?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface IScope {
|
|
58
|
+
__parentName?: string;
|
|
59
|
+
__children?: IScope[];
|
|
60
|
+
__formattedProps: { [key: string]: any };
|
|
61
|
+
__groupedProps: { [key: string]: IPropertyValue };
|
|
62
|
+
__StdDevs: number,
|
|
63
|
+
__StdDevsSource: string,
|
|
64
|
+
id: string;
|
|
65
|
+
name: string;
|
|
66
|
+
type: string;
|
|
67
|
+
Kind: string;
|
|
68
|
+
Label: string;
|
|
69
|
+
[key: string]: any;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface ISplitMetric {
|
|
73
|
+
measure: string;
|
|
74
|
+
ext: string;
|
|
75
|
+
label: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const metricKeyRegex = /[A-Z][a-z]*/g;
|
|
79
|
+
function _splitMetric(fullLabel: string): ISplitMetric {
|
|
80
|
+
|
|
81
|
+
// Related properties ---
|
|
82
|
+
for (const relProp of RelatedProperty) {
|
|
83
|
+
const index = fullLabel.indexOf(relProp);
|
|
84
|
+
if (index === 0) {
|
|
85
|
+
const measure = "";
|
|
86
|
+
const label = fullLabel.slice(index + relProp.length);
|
|
87
|
+
return { measure, ext: relProp, label };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Primary properties ---
|
|
92
|
+
const labelParts = fullLabel.match(metricKeyRegex);
|
|
93
|
+
if (labelParts?.length) {
|
|
94
|
+
const measure = labelParts.shift();
|
|
95
|
+
let label = labelParts.join("");
|
|
96
|
+
for (const ext of PropertyType) {
|
|
97
|
+
const index = label.indexOf(ext);
|
|
98
|
+
if (index === 0) {
|
|
99
|
+
label = label.slice(index + ext.length);
|
|
100
|
+
return { measure, ext, label };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Not an aggregate property ---
|
|
104
|
+
return { measure, ext: "", label };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// No match found ---
|
|
108
|
+
return { measure: "", ext: "", label: fullLabel };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const splitLabelCache: { [key: string]: ISplitMetric } = {};
|
|
112
|
+
export function splitMetric(key: string): ISplitMetric {
|
|
113
|
+
let retVal = splitLabelCache[key];
|
|
114
|
+
if (!retVal) {
|
|
115
|
+
retVal = _splitMetric(key);
|
|
116
|
+
splitLabelCache[key] = retVal;
|
|
117
|
+
}
|
|
118
|
+
return retVal;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function formatValue(item: IScope, key: string): string | undefined {
|
|
122
|
+
return item.__formattedProps?.[key] ?? item[key];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
type DedupProperties = { [key: string]: boolean };
|
|
126
|
+
|
|
127
|
+
function safeParseFloat(val: string | undefined): number | undefined {
|
|
128
|
+
if (val === undefined) return undefined;
|
|
129
|
+
const retVal = parseFloat(val);
|
|
130
|
+
return isNaN(retVal) ? undefined : retVal;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function formatValues(item: IScope, key: string, dedup: DedupProperties): IPropertyValue | null {
|
|
134
|
+
const keyParts = splitMetric(key);
|
|
135
|
+
if (!dedup[keyParts.measure]) {
|
|
136
|
+
dedup[keyParts.label] = true;
|
|
137
|
+
const avg = safeParseFloat(item[`${keyParts.measure}Avg${keyParts.label}`]);
|
|
138
|
+
const min = safeParseFloat(item[`${keyParts.measure}Min${keyParts.label}`]);
|
|
139
|
+
const max = safeParseFloat(item[`${keyParts.measure}Max${keyParts.label}`]);
|
|
140
|
+
const stdDev = safeParseFloat(item[`${keyParts.measure}StdDev${keyParts.label}`]);
|
|
141
|
+
const StdDevs = Math.max((avg - min) / stdDev, (max - avg) / stdDev);
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
Key: `${keyParts.measure}${keyParts.label}`,
|
|
145
|
+
Value: formatValue(item, `${keyParts.measure}${keyParts.label}`),
|
|
146
|
+
|
|
147
|
+
// Extended properties ---
|
|
148
|
+
Avg: formatValue(item, `${keyParts.measure}Avg${keyParts.label}`),
|
|
149
|
+
Min: formatValue(item, `${keyParts.measure}Min${keyParts.label}`),
|
|
150
|
+
Max: formatValue(item, `${keyParts.measure}Max${keyParts.label}`),
|
|
151
|
+
Delta: formatValue(item, `${keyParts.measure}Delta${keyParts.label}`),
|
|
152
|
+
StdDev: formatValue(item, `${keyParts.measure}StdDev${keyParts.label}`),
|
|
153
|
+
StdDevs: isNaN(StdDevs) ? undefined : StdDevs,
|
|
154
|
+
|
|
155
|
+
// Related properties ---
|
|
156
|
+
SkewMin: formatValue(item, `SkewMin${keyParts.label}`),
|
|
157
|
+
SkewMax: formatValue(item, `SkewMax${keyParts.label}`),
|
|
158
|
+
NodeMin: formatValue(item, `NodeMin${keyParts.label}`),
|
|
159
|
+
NodeMax: formatValue(item, `NodeMax${keyParts.label}`)
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const logger = scopedLogger("workunit.ts");
|
|
166
|
+
|
|
167
|
+
export class WorkunitCache extends Cache<{ BaseUrl: string, Wuid: string }, Workunit> {
|
|
168
|
+
constructor() {
|
|
169
|
+
super((obj) => {
|
|
170
|
+
return `${obj.BaseUrl}-${obj.Wuid}`;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const _workunits = new WorkunitCache();
|
|
175
|
+
|
|
176
|
+
export interface DebugState {
|
|
177
|
+
sequence: number;
|
|
178
|
+
state: string;
|
|
179
|
+
[key: string]: any;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export interface IWorkunit {
|
|
183
|
+
ResultViews: WsWorkunits.ResultViews;
|
|
184
|
+
HelpersCount: number;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface IDebugWorkunit {
|
|
188
|
+
DebugState?: DebugState;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export interface ITimeElapsed {
|
|
192
|
+
scope: string;
|
|
193
|
+
start: string;
|
|
194
|
+
elapsed: number;
|
|
195
|
+
finish: string;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export type WorkunitEvents = "completed" | StateEvents;
|
|
199
|
+
export type UWorkunitState = WsWorkunits.ECLWorkunit & WsWorkunits.Workunit & WsSMC.ActiveWorkunit & IWorkunit & IDebugWorkunit;
|
|
200
|
+
export type IWorkunitState = WsWorkunits.ECLWorkunit | WsWorkunits.Workunit | WsSMC.ActiveWorkunit | IWorkunit | IDebugWorkunit;
|
|
201
|
+
export class Workunit extends StateObject<UWorkunitState, IWorkunitState> implements WsWorkunits.Workunit {
|
|
202
|
+
connection: WorkunitsService;
|
|
203
|
+
topologyConnection: WsTopology.TopologyService;
|
|
204
|
+
get BaseUrl() { return this.connection.baseUrl; }
|
|
205
|
+
|
|
206
|
+
private _debugMode: boolean = false;
|
|
207
|
+
private _debugAllGraph: any;
|
|
208
|
+
private _submitAction: WUUpdate.Action;
|
|
209
|
+
|
|
210
|
+
// Accessors ---
|
|
211
|
+
get properties(): WsWorkunits.ECLWorkunit & WsWorkunits.Workunit { return this.get(); }
|
|
212
|
+
get Wuid(): string { return this.get("Wuid"); }
|
|
213
|
+
get Owner(): string { return this.get("Owner", ""); }
|
|
214
|
+
get Cluster(): string { return this.get("Cluster", ""); }
|
|
215
|
+
get Jobname(): string { return this.get("Jobname", ""); }
|
|
216
|
+
get Description(): string { return this.get("Description", ""); }
|
|
217
|
+
get ActionEx(): string { return this.get("ActionEx", ""); }
|
|
218
|
+
get StateID(): WUStateID { return this.get("StateID", WUStateID.Unknown); }
|
|
219
|
+
get State(): string { return this.get("State") || WUStateID[this.StateID]; }
|
|
220
|
+
get Protected(): boolean { return this.get("Protected", false); }
|
|
221
|
+
get Exceptions(): WsWorkunits.Exceptions2 { return this.get("Exceptions", { ECLException: [] }); }
|
|
222
|
+
get ResultViews(): WsWorkunits.ResultViews { return this.get("ResultViews", { View: [] }); }
|
|
223
|
+
|
|
224
|
+
private _resultCache = new ResultCache();
|
|
225
|
+
get ResultCount(): number { return this.get("ResultCount", 0); }
|
|
226
|
+
get Results(): WsWorkunits.Results { return this.get("Results", { ECLResult: [] }); }
|
|
227
|
+
get CResults(): Result[] {
|
|
228
|
+
return this.Results.ECLResult.map((eclResult) => {
|
|
229
|
+
return this._resultCache.get(eclResult, () => {
|
|
230
|
+
return Result.attach(this.connection, this.Wuid, eclResult, this.ResultViews.View);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
get SequenceResults(): { [key: number]: Result } {
|
|
235
|
+
const retVal: { [key: number]: Result } = {};
|
|
236
|
+
this.CResults.forEach((result) => {
|
|
237
|
+
retVal[result.Sequence] = result;
|
|
238
|
+
});
|
|
239
|
+
return retVal;
|
|
240
|
+
}
|
|
241
|
+
get Timers(): WsWorkunits.Timers { return this.get("Timers", { ECLTimer: [] }); }
|
|
242
|
+
get CTimers(): Timer[] {
|
|
243
|
+
return this.Timers.ECLTimer.map((eclTimer) => {
|
|
244
|
+
return new Timer(this.connection, this.Wuid, eclTimer);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
private _graphCache = new GraphCache();
|
|
249
|
+
get GraphCount(): number { return this.get("GraphCount", 0); }
|
|
250
|
+
get Graphs(): WsWorkunits.Graphs { return this.get("Graphs", { ECLGraph: [] }); }
|
|
251
|
+
get CGraphs(): ECLGraph[] {
|
|
252
|
+
return this.Graphs.ECLGraph.map((eclGraph) => {
|
|
253
|
+
return this._graphCache.get(eclGraph, () => {
|
|
254
|
+
return new ECLGraph(this, eclGraph, this.CTimers);
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
get ThorLogList(): WsWorkunits.ThorLogList { return this.get("ThorLogList"); }
|
|
259
|
+
get ResourceURLCount(): number { return this.get("ResourceURLCount", 0); }
|
|
260
|
+
get ResourceURLs(): WsWorkunits.ResourceURLs { return this.get("ResourceURLs", { URL: [] }); }
|
|
261
|
+
get CResourceURLs(): Resource[] {
|
|
262
|
+
return this.ResourceURLs.URL.map((url) => {
|
|
263
|
+
return new Resource(this, url);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
get TotalClusterTime(): string { return this.get("TotalClusterTime", ""); }
|
|
267
|
+
get DateTimeScheduled(): string { return this.get("DateTimeScheduled"); }
|
|
268
|
+
get IsPausing(): boolean { return this.get("IsPausing"); }
|
|
269
|
+
get ThorLCR(): boolean { return this.get("ThorLCR"); }
|
|
270
|
+
get ApplicationValues(): WsWorkunits.ApplicationValues { return this.get("ApplicationValues", { ApplicationValue: [] }); }
|
|
271
|
+
get HasArchiveQuery(): boolean { return this.get("HasArchiveQuery"); }
|
|
272
|
+
get StateEx(): string { return this.get("StateEx"); }
|
|
273
|
+
get PriorityClass(): number { return this.get("PriorityClass"); }
|
|
274
|
+
get PriorityLevel(): number { return this.get("PriorityLevel"); }
|
|
275
|
+
get Snapshot(): string { return this.get("Snapshot"); }
|
|
276
|
+
get ResultLimit(): number { return this.get("ResultLimit"); }
|
|
277
|
+
get EventSchedule(): number { return this.get("EventSchedule"); }
|
|
278
|
+
get Query(): WsWorkunits.Query { return this.get("Query"); }
|
|
279
|
+
get HelpersCount(): number { return this.get("HelpersCount", 0); }
|
|
280
|
+
get Helpers(): WsWorkunits.Helpers { return this.get("Helpers", { ECLHelpFile: [] }); }
|
|
281
|
+
get DebugValues(): WsWorkunits.DebugValues { return this.get("DebugValues"); }
|
|
282
|
+
get AllowedClusters(): WsWorkunits.AllowedClusters { return this.get("AllowedClusters"); }
|
|
283
|
+
get ErrorCount(): number { return this.get("ErrorCount", 0); }
|
|
284
|
+
get WarningCount(): number { return this.get("WarningCount", 0); }
|
|
285
|
+
get InfoCount(): number { return this.get("InfoCount", 0); }
|
|
286
|
+
get AlertCount(): number { return this.get("AlertCount", 0); }
|
|
287
|
+
get SourceFileCount(): number { return this.get("SourceFileCount", 0); }
|
|
288
|
+
get SourceFiles(): WsWorkunits.SourceFiles { return this.get("SourceFiles", { ECLSourceFile: [] }); }
|
|
289
|
+
get CSourceFiles(): SourceFile[] {
|
|
290
|
+
return this.SourceFiles.ECLSourceFile.map(eclSourceFile => new SourceFile(this.connection, this.Wuid, eclSourceFile));
|
|
291
|
+
}
|
|
292
|
+
get VariableCount(): number { return this.get("VariableCount", 0); }
|
|
293
|
+
get Variables(): WsWorkunits.Variables { return this.get("Variables", { ECLResult: [] }); }
|
|
294
|
+
get TimerCount(): number { return this.get("TimerCount", 0); }
|
|
295
|
+
get HasDebugValue(): boolean { return this.get("HasDebugValue"); }
|
|
296
|
+
get ApplicationValueCount(): number { return this.get("ApplicationValueCount", 0); }
|
|
297
|
+
get XmlParams(): string { return this.get("XmlParams"); }
|
|
298
|
+
get AccessFlag(): number { return this.get("AccessFlag"); }
|
|
299
|
+
get ClusterFlag(): number { return this.get("ClusterFlag"); }
|
|
300
|
+
get ResultViewCount(): number { return this.get("ResultViewCount", 0); }
|
|
301
|
+
get DebugValueCount(): number { return this.get("DebugValueCount", 0); }
|
|
302
|
+
get WorkflowCount(): number { return this.get("WorkflowCount", 0); }
|
|
303
|
+
get Archived(): boolean { return this.get("Archived"); }
|
|
304
|
+
get RoxieCluster(): string { return this.get("RoxieCluster"); }
|
|
305
|
+
get DebugState(): DebugState { return this.get("DebugState", {} as DebugState)!; }
|
|
306
|
+
get Queue(): string { return this.get("Queue"); }
|
|
307
|
+
get Active(): boolean { return this.get("Active"); }
|
|
308
|
+
get Action(): number { return this.get("Action"); }
|
|
309
|
+
get Scope(): string { return this.get("Scope"); }
|
|
310
|
+
get AbortBy(): string { return this.get("AbortBy"); }
|
|
311
|
+
get AbortTime(): string { return this.get("AbortTime"); }
|
|
312
|
+
get Workflows(): WsWorkunits.Workflows { return this.get("Workflows"); }
|
|
313
|
+
get TimingData(): WsWorkunits.TimingData { return this.get("TimingData"); }
|
|
314
|
+
get HelpersDesc(): string { return this.get("HelpersDesc"); }
|
|
315
|
+
get GraphsDesc(): string { return this.get("GraphsDesc"); }
|
|
316
|
+
get SourceFilesDesc(): string { return this.get("SourceFilesDesc"); }
|
|
317
|
+
get ResultsDesc(): string { return this.get("ResultsDesc"); }
|
|
318
|
+
get VariablesDesc(): string { return this.get("VariablesDesc"); }
|
|
319
|
+
get TimersDesc(): string { return this.get("TimersDesc"); }
|
|
320
|
+
get DebugValuesDesc(): string { return this.get("DebugValuesDesc"); }
|
|
321
|
+
get ApplicationValuesDesc(): string { return this.get("ApplicationValuesDesc"); }
|
|
322
|
+
get WorkflowsDesc(): string { return this.get("WorkflowsDesc"); }
|
|
323
|
+
get ServiceNames(): WsWorkunits.ServiceNames { return this.get("ServiceNames"); }
|
|
324
|
+
get CompileCost(): number { return this.get("CompileCost"); }
|
|
325
|
+
get ExecuteCost(): number { return this.get("ExecuteCost"); }
|
|
326
|
+
get FileAccessCost(): number { return this.get("FileAccessCost"); }
|
|
327
|
+
get NoAccess(): boolean { return this.get("NoAccess"); }
|
|
328
|
+
get ECLWUProcessList(): WsWorkunits.ECLWUProcessList { return this.get("ECLWUProcessList"); }
|
|
329
|
+
get CostSavingPotential(): number { return this.get("CostSavingPotential"); }
|
|
330
|
+
|
|
331
|
+
// Factories ---
|
|
332
|
+
static create(optsConnection: IOptions | IConnection): Promise<Workunit> {
|
|
333
|
+
const retVal: Workunit = new Workunit(optsConnection);
|
|
334
|
+
return retVal.connection.WUCreate().then((response) => {
|
|
335
|
+
_workunits.set(retVal);
|
|
336
|
+
retVal.set(response.Workunit);
|
|
337
|
+
return retVal;
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
static attach(optsConnection: IOptions | IConnection, wuid: string, state?: IWorkunitState): Workunit {
|
|
342
|
+
const retVal: Workunit = _workunits.get({ BaseUrl: optsConnection.baseUrl, Wuid: wuid }, () => {
|
|
343
|
+
return new Workunit(optsConnection, wuid);
|
|
344
|
+
});
|
|
345
|
+
if (state) {
|
|
346
|
+
retVal.set(state);
|
|
347
|
+
}
|
|
348
|
+
return retVal;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
static existsLocal(baseUrl: string, wuid: string): boolean {
|
|
352
|
+
return _workunits.has({ BaseUrl: baseUrl, Wuid: wuid });
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
static submit(server: IOptions | IConnection, target: string, ecl: string, compileOnly = false): Promise<Workunit> {
|
|
356
|
+
return Workunit.create(server).then((wu) => {
|
|
357
|
+
return wu.update({ QueryText: ecl });
|
|
358
|
+
}).then((wu) => {
|
|
359
|
+
return compileOnly ? wu.submit(target, WUUpdate.Action.Compile) : wu.submit(target);
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
static compile(server: IOptions | IConnection, target: string, ecl: string): Promise<Workunit> {
|
|
364
|
+
return Workunit.submit(server, target, ecl, true);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
static query(server: IOptions | IConnection, opts: Partial<WsWorkunits.WUQuery>): Promise<Workunit[]> {
|
|
368
|
+
const wsWorkunits = new WorkunitsService(server);
|
|
369
|
+
return wsWorkunits.WUQuery(opts).then((response) => {
|
|
370
|
+
return response.Workunits.ECLWorkunit.map(function (wu) {
|
|
371
|
+
return Workunit.attach(server, wu.Wuid, wu);
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// --- --- ---
|
|
377
|
+
protected constructor(optsConnection: IOptions | IConnection, wuid?: string) {
|
|
378
|
+
super();
|
|
379
|
+
this.connection = new WorkunitsService(optsConnection);
|
|
380
|
+
this.topologyConnection = new WsTopology.TopologyService(optsConnection);
|
|
381
|
+
this.clearState(wuid);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
clearState(wuid?: string) {
|
|
385
|
+
this.clear({
|
|
386
|
+
Wuid: wuid,
|
|
387
|
+
StateID: WUStateID.Unknown
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
update(request: Partial<WsWorkunits.WUUpdate>): Promise<Workunit> {
|
|
392
|
+
return this.connection.WUUpdate({
|
|
393
|
+
...request,
|
|
394
|
+
...{
|
|
395
|
+
Wuid: this.Wuid,
|
|
396
|
+
StateOrig: this.StateID,
|
|
397
|
+
JobnameOrig: this.Jobname,
|
|
398
|
+
DescriptionOrig: this.Description,
|
|
399
|
+
ProtectedOrig: this.Protected,
|
|
400
|
+
ClusterOrig: this.Cluster
|
|
401
|
+
}
|
|
402
|
+
}).then((response) => {
|
|
403
|
+
this.set(response.Workunit);
|
|
404
|
+
return this;
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
submit(_cluster?: string, action: WUUpdate.Action = WUUpdate.Action.Run, resultLimit?: number): Promise<Workunit> {
|
|
409
|
+
let clusterPromise;
|
|
410
|
+
if (_cluster !== void 0) {
|
|
411
|
+
clusterPromise = Promise.resolve(_cluster);
|
|
412
|
+
} else {
|
|
413
|
+
clusterPromise = this.topologyConnection.DefaultTpLogicalClusterQuery().then((response) => {
|
|
414
|
+
return response.Name;
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
this._debugMode = false;
|
|
419
|
+
if (action === WUUpdate.Action.Debug) {
|
|
420
|
+
action = WUUpdate.Action.Run;
|
|
421
|
+
this._debugMode = true;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return clusterPromise.then((cluster) => {
|
|
425
|
+
return this.connection.WUUpdate({
|
|
426
|
+
Wuid: this.Wuid,
|
|
427
|
+
Action: action,
|
|
428
|
+
ResultLimit: resultLimit,
|
|
429
|
+
DebugValues: {
|
|
430
|
+
DebugValue: [
|
|
431
|
+
{
|
|
432
|
+
Name: "Debug",
|
|
433
|
+
Value: this._debugMode ? "1" : ""
|
|
434
|
+
}
|
|
435
|
+
]
|
|
436
|
+
}
|
|
437
|
+
}).then((response) => {
|
|
438
|
+
this.set(response.Workunit);
|
|
439
|
+
this._submitAction = action;
|
|
440
|
+
return this.connection.WUSubmit({ Wuid: this.Wuid, Cluster: cluster });
|
|
441
|
+
});
|
|
442
|
+
}).then(() => {
|
|
443
|
+
return this;
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
isComplete(): boolean {
|
|
448
|
+
switch (this.StateID) {
|
|
449
|
+
case WUStateID.Compiled:
|
|
450
|
+
return this.ActionEx === "compile" || this._submitAction === WUUpdate.Action.Compile;
|
|
451
|
+
case WUStateID.Completed:
|
|
452
|
+
case WUStateID.Failed:
|
|
453
|
+
case WUStateID.Aborted:
|
|
454
|
+
case WUStateID.NotFound:
|
|
455
|
+
return true;
|
|
456
|
+
default:
|
|
457
|
+
}
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
isFailed() {
|
|
462
|
+
switch (this.StateID) {
|
|
463
|
+
case WUStateID.Aborted:
|
|
464
|
+
case WUStateID.Failed:
|
|
465
|
+
return true;
|
|
466
|
+
default:
|
|
467
|
+
}
|
|
468
|
+
return false;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
isDeleted() {
|
|
472
|
+
switch (this.StateID) {
|
|
473
|
+
case WUStateID.NotFound:
|
|
474
|
+
return true;
|
|
475
|
+
default:
|
|
476
|
+
}
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
isDebugging() {
|
|
481
|
+
switch (this.StateID) {
|
|
482
|
+
case WUStateID.DebugPaused:
|
|
483
|
+
case WUStateID.DebugRunning:
|
|
484
|
+
return true;
|
|
485
|
+
default:
|
|
486
|
+
}
|
|
487
|
+
return this._debugMode;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
isRunning(): boolean {
|
|
491
|
+
switch (this.StateID) {
|
|
492
|
+
case WUStateID.Compiled:
|
|
493
|
+
case WUStateID.Running:
|
|
494
|
+
case WUStateID.Aborting:
|
|
495
|
+
case WUStateID.Blocked:
|
|
496
|
+
case WUStateID.DebugPaused:
|
|
497
|
+
case WUStateID.DebugRunning:
|
|
498
|
+
return true;
|
|
499
|
+
default:
|
|
500
|
+
}
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
setToFailed() {
|
|
505
|
+
return this.WUAction(WsWorkunits.ECLWUActions.SetToFailed);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
pause() {
|
|
509
|
+
return this.WUAction(WsWorkunits.ECLWUActions.Pause);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
pauseNow() {
|
|
513
|
+
return this.WUAction(WsWorkunits.ECLWUActions.PauseNow);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
resume() {
|
|
517
|
+
return this.WUAction(WsWorkunits.ECLWUActions.Resume);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
abort() {
|
|
521
|
+
return this.WUAction(WsWorkunits.ECLWUActions.Abort);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
protect() {
|
|
525
|
+
return this.WUAction(WsWorkunits.ECLWUActions.Protect);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
unprotect() {
|
|
529
|
+
return this.WUAction(WsWorkunits.ECLWUActions.Unprotect);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
delete() {
|
|
533
|
+
return this.WUAction(WsWorkunits.ECLWUActions.Delete);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
restore() {
|
|
537
|
+
return this.WUAction(WsWorkunits.ECLWUActions.Restore);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
deschedule() {
|
|
541
|
+
return this.WUAction(WsWorkunits.ECLWUActions.Deschedule);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
reschedule() {
|
|
545
|
+
return this.WUAction(WsWorkunits.ECLWUActions.Reschedule);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
resubmit(): Promise<Workunit> {
|
|
549
|
+
return this.WUResubmit({
|
|
550
|
+
CloneWorkunit: false,
|
|
551
|
+
ResetWorkflow: false
|
|
552
|
+
}).then(() => {
|
|
553
|
+
this.clearState(this.Wuid);
|
|
554
|
+
return this.refresh().then(() => {
|
|
555
|
+
this._monitor();
|
|
556
|
+
return this;
|
|
557
|
+
});
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
clone(): Promise<Workunit> {
|
|
562
|
+
return this.WUResubmit({
|
|
563
|
+
CloneWorkunit: true,
|
|
564
|
+
ResetWorkflow: false
|
|
565
|
+
}).then((response) => {
|
|
566
|
+
return Workunit.attach(this.connection.opts(), response.WUs.WU[0].WUID)
|
|
567
|
+
.refresh()
|
|
568
|
+
;
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
async refreshState(): Promise<this> {
|
|
573
|
+
await this.WUQuery();
|
|
574
|
+
// Ensure "isComplete" is correct for WUs that are only "Compiled".
|
|
575
|
+
if (this.StateID === WUStateID.Compiled && !this.ActionEx && !this._submitAction) {
|
|
576
|
+
await this.refreshInfo();
|
|
577
|
+
}
|
|
578
|
+
return this;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
async refreshInfo(request?: Partial<WsWorkunits.WUInfo>): Promise<this> {
|
|
582
|
+
await this.WUInfo(request);
|
|
583
|
+
return this;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
async refreshDebug(): Promise<this> {
|
|
587
|
+
await this.debugStatus();
|
|
588
|
+
return this;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
async refresh(full: boolean = false, request?: Partial<WsWorkunits.WUInfo>): Promise<this> {
|
|
592
|
+
if (full) {
|
|
593
|
+
await Promise.all([this.refreshInfo(request), this.refreshDebug()]);
|
|
594
|
+
} else {
|
|
595
|
+
await this.refreshState();
|
|
596
|
+
}
|
|
597
|
+
return this;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
eclExceptions(): WsWorkunits.ECLException[] {
|
|
601
|
+
return this.Exceptions.ECLException;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
fetchArchive(): Promise<string> {
|
|
605
|
+
return this.connection.WUFileEx({
|
|
606
|
+
Wuid: this.Wuid,
|
|
607
|
+
Type: "ArchiveQuery"
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
fetchECLExceptions(): Promise<WsWorkunits.ECLException[]> {
|
|
612
|
+
return this.WUInfo({ IncludeExceptions: true }).then(() => {
|
|
613
|
+
return this.eclExceptions();
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
fetchResults(): Promise<Result[]> {
|
|
618
|
+
return this.WUInfo({ IncludeResults: true }).then(() => {
|
|
619
|
+
return this.CResults;
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
fetchGraphs(): Promise<ECLGraph[]> {
|
|
624
|
+
return this.WUInfo({ IncludeGraphs: true }).then(() => {
|
|
625
|
+
return this.CGraphs;
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
fetchQuery(): Promise<WsWorkunits.Query> {
|
|
630
|
+
return this.WUInfo({ IncludeECL: true, TruncateEclTo64k: false }).then(() => {
|
|
631
|
+
return this.Query;
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
fetchHelpers(): Promise<WsWorkunits.ECLHelpFile[]> {
|
|
636
|
+
return this.WUInfo({ IncludeHelpers: true }).then(() => {
|
|
637
|
+
return this.Helpers?.ECLHelpFile || [];
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
fetchAllowedClusters(): Promise<string[]> {
|
|
642
|
+
return this.WUInfo({ IncludeAllowedClusters: true }).then(() => {
|
|
643
|
+
return this.AllowedClusters?.AllowedCluster || [];
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
fetchTotalClusterTime(): Promise<string> {
|
|
648
|
+
return this.WUInfo({ IncludeTotalClusterTime: true }).then(() => {
|
|
649
|
+
return this.TotalClusterTime;
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
fetchServiceNames(): Promise<string[]> {
|
|
654
|
+
return this.WUInfo({ IncludeServiceNames: true }).then(() => {
|
|
655
|
+
return this.ServiceNames?.Item;
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
fetchDetailsMeta(request: RecursivePartial<WsWorkunits.WUDetailsMeta> = {}): Promise<WsWorkunits.WUDetailsMetaResponse> {
|
|
660
|
+
return this.WUDetailsMeta(request);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
fetchDetailsRaw(request: RecursivePartial<WsWorkunits.WUDetails> = {}): Promise<WsWorkunits.Scope[]> {
|
|
664
|
+
return this.WUDetails(request).then(response => response.Scopes.Scope);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
normalizeDetails(meta: WsWorkunits.WUDetailsMetaResponse, scopes: WsWorkunits.Scope[]): { meta: WsWorkunits.WUDetailsMetaResponse, columns: { [id: string]: any }, data: IScope[] } {
|
|
668
|
+
const columns: { [id: string]: any } = {
|
|
669
|
+
id: {
|
|
670
|
+
Measure: "label"
|
|
671
|
+
},
|
|
672
|
+
name: {
|
|
673
|
+
Measure: "label"
|
|
674
|
+
},
|
|
675
|
+
type: {
|
|
676
|
+
Measure: "label"
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
const activityMap = new Map<number, string>();
|
|
680
|
+
for (const activity of meta.Activities?.Activity ?? []) {
|
|
681
|
+
activityMap.set(activity.Kind, activity.Name);
|
|
682
|
+
}
|
|
683
|
+
const data: IScope[] = new Array(scopes.length);
|
|
684
|
+
for (let i = 0; i < scopes.length; i++) {
|
|
685
|
+
const scope = scopes[i];
|
|
686
|
+
const props: { [key: string]: any } = {};
|
|
687
|
+
const formattedProps: { [key: string]: any } = {};
|
|
688
|
+
if (scope.Properties?.Property) {
|
|
689
|
+
for (const scopeProperty of scope.Properties.Property) {
|
|
690
|
+
const measure = scopeProperty.Measure;
|
|
691
|
+
const name = scopeProperty.Name;
|
|
692
|
+
const rawValue = scopeProperty.RawValue;
|
|
693
|
+
if (measure === "ns") {
|
|
694
|
+
scopeProperty.Measure = "s";
|
|
695
|
+
}
|
|
696
|
+
if (name === "Kind") {
|
|
697
|
+
const rawValueInt = parseInt(rawValue, 10);
|
|
698
|
+
scopeProperty.Formatted = activityMap.get(rawValueInt) ?? rawValue;
|
|
699
|
+
}
|
|
700
|
+
columns[name] = {
|
|
701
|
+
Name: scopeProperty.Name,
|
|
702
|
+
Measure: scopeProperty.Measure,
|
|
703
|
+
Creator: scopeProperty.Creator,
|
|
704
|
+
CreatorType: scopeProperty.CreatorType
|
|
705
|
+
};
|
|
706
|
+
switch (scopeProperty.Measure) {
|
|
707
|
+
case "bool":
|
|
708
|
+
props[name] = !!+rawValue;
|
|
709
|
+
break;
|
|
710
|
+
case "sz":
|
|
711
|
+
props[name] = +rawValue;
|
|
712
|
+
break;
|
|
713
|
+
case "s":
|
|
714
|
+
props[name] = +rawValue / 1000000000;
|
|
715
|
+
break;
|
|
716
|
+
case "ns":
|
|
717
|
+
props[name] = +rawValue;
|
|
718
|
+
break;
|
|
719
|
+
case "ts":
|
|
720
|
+
props[name] = new Date(+rawValue / 1000).toISOString();
|
|
721
|
+
break;
|
|
722
|
+
case "cnt":
|
|
723
|
+
props[name] = +rawValue;
|
|
724
|
+
break;
|
|
725
|
+
case "cost":
|
|
726
|
+
props[name] = +rawValue / 1000000;
|
|
727
|
+
break;
|
|
728
|
+
case "node":
|
|
729
|
+
props[name] = +rawValue;
|
|
730
|
+
break;
|
|
731
|
+
case "skw":
|
|
732
|
+
props[name] = +rawValue;
|
|
733
|
+
break;
|
|
734
|
+
case "cpu":
|
|
735
|
+
case "ppm":
|
|
736
|
+
case "ip":
|
|
737
|
+
case "cy":
|
|
738
|
+
case "en":
|
|
739
|
+
case "txt":
|
|
740
|
+
case "id":
|
|
741
|
+
case "fname":
|
|
742
|
+
default:
|
|
743
|
+
props[name] = rawValue;
|
|
744
|
+
}
|
|
745
|
+
formattedProps[name] = formatNum(scopeProperty.Formatted ?? props[name]);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
const normalizedScope: IScope = {
|
|
749
|
+
id: scope.Id,
|
|
750
|
+
name: scope.ScopeName,
|
|
751
|
+
type: scope.ScopeType,
|
|
752
|
+
Kind: scope["Kind"],
|
|
753
|
+
Label: scope["Label"],
|
|
754
|
+
__formattedProps: formattedProps,
|
|
755
|
+
__groupedProps: {},
|
|
756
|
+
__groupedRawProps: {},
|
|
757
|
+
__StdDevs: 0,
|
|
758
|
+
__StdDevsSource: "",
|
|
759
|
+
...props
|
|
760
|
+
};
|
|
761
|
+
const definitionList = normalizedScope[DEFINITION_LIST];
|
|
762
|
+
if (definitionList) {
|
|
763
|
+
try {
|
|
764
|
+
const parsedList = JSON.parse(definitionList.split("\\").join("\\\\"));
|
|
765
|
+
const processedDefinitions: Array<{ filePath: string, line: number, col: number }> = [];
|
|
766
|
+
|
|
767
|
+
for (let k = 0; k < parsedList.length; k++) {
|
|
768
|
+
const matches = parsedList[k].match(definitionRegex);
|
|
769
|
+
if (matches) {
|
|
770
|
+
processedDefinitions.push({
|
|
771
|
+
filePath: (matches[1] ?? "") + matches[2] + matches[3],
|
|
772
|
+
line: parseInt(matches[5], 10),
|
|
773
|
+
col: parseInt(matches[6], 10)
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
normalizedScope[DEFINITION_LIST] = processedDefinitions;
|
|
778
|
+
} catch (e) {
|
|
779
|
+
logger.error(`Unexpected "DefinitionList": ${definitionList}`);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
const dedup: DedupProperties = {};
|
|
784
|
+
let maxStdDevs = 0;
|
|
785
|
+
let maxStdDevsSource = "";
|
|
786
|
+
for (const key in normalizedScope) {
|
|
787
|
+
if (!key.startsWith("__")) {
|
|
788
|
+
const row = formatValues(normalizedScope, key, dedup);
|
|
789
|
+
if (row) {
|
|
790
|
+
normalizedScope.__groupedProps[row.Key] = row;
|
|
791
|
+
if (!isNaN(row.StdDevs) && row.StdDevs > maxStdDevs) {
|
|
792
|
+
maxStdDevs = row.StdDevs;
|
|
793
|
+
maxStdDevsSource = row.Key;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
normalizedScope.__StdDevs = maxStdDevs;
|
|
799
|
+
normalizedScope.__StdDevsSource = maxStdDevsSource;
|
|
800
|
+
|
|
801
|
+
data[i] = normalizedScope;
|
|
802
|
+
}
|
|
803
|
+
return {
|
|
804
|
+
meta,
|
|
805
|
+
columns,
|
|
806
|
+
data
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
fetchDetailsNormalized(request: RecursivePartial<WsWorkunits.WUDetails> = {}): Promise<{ meta: WsWorkunits.WUDetailsMetaResponse, columns: { [id: string]: any }, data: IScope[] }> {
|
|
811
|
+
return Promise.all([this.fetchDetailsMeta(), this.fetchDetailsRaw(request)]).then(promises => {
|
|
812
|
+
return this.normalizeDetails(promises[0], promises[1]);
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
fetchInfo(request: Partial<WsWorkunits.WUInfo> = {}): Promise<WsWorkunits.WUInfoResponse> {
|
|
817
|
+
return this.WUInfo(request);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
fetchDetails(request: RecursivePartial<WsWorkunits.WUDetails> = {}): Promise<Scope[]> {
|
|
821
|
+
return this.WUDetails(request).then((response) => {
|
|
822
|
+
return response.Scopes.Scope.map((rawScope) => {
|
|
823
|
+
return new Scope(this, rawScope);
|
|
824
|
+
});
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
fetchDetailsHierarchy(request: Partial<WsWorkunits.WUDetails> = {}): Promise<Scope[]> {
|
|
829
|
+
return this.WUDetails(request).then((response) => {
|
|
830
|
+
const retVal: Scope[] = [];
|
|
831
|
+
|
|
832
|
+
// Recreate scope hierarchy and dedup ---
|
|
833
|
+
const scopeMap: { [key: string]: Scope } = {};
|
|
834
|
+
response.Scopes.Scope.forEach((rawScope) => {
|
|
835
|
+
if (scopeMap[rawScope.ScopeName]) {
|
|
836
|
+
scopeMap[rawScope.ScopeName].update(rawScope);
|
|
837
|
+
return null;
|
|
838
|
+
} else {
|
|
839
|
+
const scope = new Scope(this, rawScope);
|
|
840
|
+
scopeMap[scope.ScopeName] = scope;
|
|
841
|
+
return scope;
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
for (const key in scopeMap) {
|
|
845
|
+
if (scopeMap.hasOwnProperty(key)) {
|
|
846
|
+
const scope = scopeMap[key];
|
|
847
|
+
const parentScopeID = scope.parentScope();
|
|
848
|
+
if (parentScopeID && scopeMap[parentScopeID]) {
|
|
849
|
+
scopeMap[parentScopeID].children().push(scope);
|
|
850
|
+
} else {
|
|
851
|
+
retVal.push(scope);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
return retVal;
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
fetchGraphDetails(graphIDs: string[] = [], rootTypes: string[]): Promise<BaseScope[]> {
|
|
861
|
+
return this.fetchDetails({
|
|
862
|
+
ScopeFilter: {
|
|
863
|
+
MaxDepth: 999999,
|
|
864
|
+
Ids: graphIDs,
|
|
865
|
+
ScopeTypes: rootTypes,
|
|
866
|
+
},
|
|
867
|
+
NestedFilter: {
|
|
868
|
+
Depth: 999999,
|
|
869
|
+
ScopeTypes: ["graph", "subgraph", "activity", "edge", "function"]
|
|
870
|
+
},
|
|
871
|
+
PropertiesToReturn: {
|
|
872
|
+
AllStatistics: true,
|
|
873
|
+
AllAttributes: true,
|
|
874
|
+
AllHints: true,
|
|
875
|
+
AllProperties: true,
|
|
876
|
+
AllScopes: true
|
|
877
|
+
},
|
|
878
|
+
ScopeOptions: {
|
|
879
|
+
IncludeId: true,
|
|
880
|
+
IncludeScope: true,
|
|
881
|
+
IncludeScopeType: true
|
|
882
|
+
},
|
|
883
|
+
PropertyOptions: {
|
|
884
|
+
IncludeName: true,
|
|
885
|
+
IncludeRawValue: true,
|
|
886
|
+
IncludeFormatted: true,
|
|
887
|
+
IncludeMeasure: true,
|
|
888
|
+
IncludeCreator: false,
|
|
889
|
+
IncludeCreatorType: false
|
|
890
|
+
}
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
fetchScopeGraphs(graphIDs: string[] = []): Promise<ScopeGraph> {
|
|
895
|
+
return this.fetchGraphDetails(graphIDs, ["graph"]).then((scopes) => {
|
|
896
|
+
return createGraph(scopes);
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
fetchTimeElapsed(): Promise<ITimeElapsed[]> {
|
|
901
|
+
return this.fetchDetails({
|
|
902
|
+
ScopeFilter: {
|
|
903
|
+
PropertyFilters: {
|
|
904
|
+
PropertyFilter: [{ Name: "TimeElapsed" }]
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}).then((scopes) => {
|
|
908
|
+
const scopeInfo: { [key: string]: ITimeElapsed } = {};
|
|
909
|
+
scopes.forEach((scope) => {
|
|
910
|
+
scopeInfo[scope.ScopeName] = scopeInfo[scope.ScopeName] || {
|
|
911
|
+
scope: scope.ScopeName,
|
|
912
|
+
start: null,
|
|
913
|
+
elapsed: null,
|
|
914
|
+
finish: null
|
|
915
|
+
};
|
|
916
|
+
scope.CAttributes.forEach((attr) => {
|
|
917
|
+
if (attr.Name === "TimeElapsed") {
|
|
918
|
+
scopeInfo[scope.ScopeName].elapsed = +attr.RawValue;
|
|
919
|
+
} else if (attr.Measure === "ts" && attr.Name.indexOf("Started") >= 0) {
|
|
920
|
+
scopeInfo[scope.ScopeName].start = attr.Formatted;
|
|
921
|
+
}
|
|
922
|
+
});
|
|
923
|
+
});
|
|
924
|
+
// Workaround duplicate scope responses
|
|
925
|
+
const retVal: ITimeElapsed[] = [];
|
|
926
|
+
for (const key in scopeInfo) {
|
|
927
|
+
const scope = scopeInfo[key];
|
|
928
|
+
if (scope.start && scope.elapsed) {
|
|
929
|
+
const endTime = parser(scope.start);
|
|
930
|
+
endTime!.setMilliseconds(endTime!.getMilliseconds() + scope.elapsed / 1000000);
|
|
931
|
+
scope.finish = formatter(endTime!);
|
|
932
|
+
retVal.push(scope);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
retVal.sort((l, r) => {
|
|
936
|
+
if (l.start < r.start) return -1;
|
|
937
|
+
if (l.start > r.start) return 1;
|
|
938
|
+
return 0;
|
|
939
|
+
});
|
|
940
|
+
return retVal;
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
// Monitoring ---
|
|
945
|
+
protected _monitor(): void {
|
|
946
|
+
if (this.isComplete()) {
|
|
947
|
+
this._monitorTickCount = 0;
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
super._monitor();
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
protected _monitorTimeoutDuration(): number {
|
|
954
|
+
const retVal = super._monitorTimeoutDuration();
|
|
955
|
+
if (this._monitorTickCount <= 1) { // Once
|
|
956
|
+
return 1000;
|
|
957
|
+
} else if (this._monitorTickCount <= 3) { // Twice
|
|
958
|
+
return 3000;
|
|
959
|
+
} else if (this._monitorTickCount <= 5) { // Twice
|
|
960
|
+
return 5000;
|
|
961
|
+
} else if (this._monitorTickCount <= 7) { // Twice
|
|
962
|
+
return 10000;
|
|
963
|
+
}
|
|
964
|
+
return retVal;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// Events ---
|
|
968
|
+
on(eventID: WorkunitEvents, propIDorCallback: StateCallback | keyof UWorkunitState, callback?: StatePropCallback): this {
|
|
969
|
+
if (this.isCallback(propIDorCallback)) {
|
|
970
|
+
switch (eventID) {
|
|
971
|
+
case "completed":
|
|
972
|
+
super.on("propChanged", "StateID", (changeInfo: IEvent) => {
|
|
973
|
+
if (this.isComplete()) {
|
|
974
|
+
propIDorCallback([changeInfo]);
|
|
975
|
+
}
|
|
976
|
+
});
|
|
977
|
+
break;
|
|
978
|
+
case "changed":
|
|
979
|
+
super.on(eventID, propIDorCallback);
|
|
980
|
+
break;
|
|
981
|
+
default:
|
|
982
|
+
}
|
|
983
|
+
} else {
|
|
984
|
+
switch (eventID) {
|
|
985
|
+
case "changed":
|
|
986
|
+
super.on(eventID, propIDorCallback, callback!);
|
|
987
|
+
break;
|
|
988
|
+
default:
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
this._monitor();
|
|
992
|
+
return this;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
watchUntilComplete(callback?: StateCallback): Promise<this> {
|
|
996
|
+
return new Promise((resolve, _) => {
|
|
997
|
+
const watchHandle = this.watch((changes) => {
|
|
998
|
+
if (callback) {
|
|
999
|
+
callback(changes);
|
|
1000
|
+
}
|
|
1001
|
+
if (this.isComplete()) {
|
|
1002
|
+
watchHandle.release();
|
|
1003
|
+
resolve(this);
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
watchUntilRunning(callback?: StateCallback): Promise<this> {
|
|
1010
|
+
return new Promise((resolve, _) => {
|
|
1011
|
+
const watchHandle = this.watch((changes) => {
|
|
1012
|
+
if (callback) {
|
|
1013
|
+
callback(changes);
|
|
1014
|
+
}
|
|
1015
|
+
if (this.isComplete() || this.isRunning()) {
|
|
1016
|
+
watchHandle.release();
|
|
1017
|
+
resolve(this);
|
|
1018
|
+
}
|
|
1019
|
+
});
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
// WsWorkunits passthroughs ---
|
|
1024
|
+
protected WUQuery(_request: Partial<WsWorkunits.WUQuery> = {}): Promise<WsWorkunits.WUQueryResponse> {
|
|
1025
|
+
return this.connection.WUQuery({ ..._request, Wuid: this.Wuid }).then((response) => {
|
|
1026
|
+
if (response.Workunits.ECLWorkunit.length === 0) {
|
|
1027
|
+
// deleted ---
|
|
1028
|
+
this.clearState(this.Wuid);
|
|
1029
|
+
this.set("StateID", WUStateID.NotFound);
|
|
1030
|
+
} else {
|
|
1031
|
+
this.set(response.Workunits.ECLWorkunit[0]);
|
|
1032
|
+
}
|
|
1033
|
+
return response;
|
|
1034
|
+
}).catch((e: ESPExceptions) => {
|
|
1035
|
+
// deleted ---
|
|
1036
|
+
const wuMissing = e.Exception.some((exception) => {
|
|
1037
|
+
if (exception.Code === 20081) {
|
|
1038
|
+
this.clearState(this.Wuid);
|
|
1039
|
+
this.set("StateID", WUStateID.NotFound);
|
|
1040
|
+
return true;
|
|
1041
|
+
}
|
|
1042
|
+
return false;
|
|
1043
|
+
});
|
|
1044
|
+
if (!wuMissing) {
|
|
1045
|
+
logger.warning(`Unexpected ESP exception: ${e.message}`);
|
|
1046
|
+
throw e;
|
|
1047
|
+
}
|
|
1048
|
+
return {} as WsWorkunits.WUQueryResponse;
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
protected WUCreate() {
|
|
1053
|
+
return this.connection.WUCreate().then((response) => {
|
|
1054
|
+
this.set(response.Workunit);
|
|
1055
|
+
_workunits.set(this);
|
|
1056
|
+
return response;
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
protected WUInfo(_request: Partial<WsWorkunits.WUInfo> = {}): Promise<WsWorkunits.WUInfoResponse> {
|
|
1061
|
+
const includeResults = _request.IncludeResults || _request.IncludeResultsViewNames;
|
|
1062
|
+
return this.connection.WUInfo({
|
|
1063
|
+
..._request,
|
|
1064
|
+
Wuid: this.Wuid,
|
|
1065
|
+
IncludeResults: includeResults,
|
|
1066
|
+
IncludeResultsViewNames: includeResults,
|
|
1067
|
+
SuppressResultSchemas: false
|
|
1068
|
+
}).then((response) => {
|
|
1069
|
+
this.set(response.Workunit);
|
|
1070
|
+
if (includeResults) {
|
|
1071
|
+
this.set({
|
|
1072
|
+
ResultViews: response.ResultViews
|
|
1073
|
+
} as IWorkunitState);
|
|
1074
|
+
}
|
|
1075
|
+
return response;
|
|
1076
|
+
}).catch((e: ESPExceptions) => {
|
|
1077
|
+
// deleted ---
|
|
1078
|
+
const wuMissing = e.Exception.some((exception) => {
|
|
1079
|
+
if (exception.Code === 20080) {
|
|
1080
|
+
this.clearState(this.Wuid);
|
|
1081
|
+
this.set("StateID", WUStateID.NotFound);
|
|
1082
|
+
return true;
|
|
1083
|
+
}
|
|
1084
|
+
return false;
|
|
1085
|
+
});
|
|
1086
|
+
if (!wuMissing) {
|
|
1087
|
+
logger.warning(`Unexpected ESP exception: ${e.message}`);
|
|
1088
|
+
throw e;
|
|
1089
|
+
}
|
|
1090
|
+
return {} as WsWorkunits.WUInfoResponse;
|
|
1091
|
+
});
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
protected WUResubmit(request: Partial<WsWorkunits.WUResubmit>): Promise<WsWorkunits.WUResubmitResponse> {
|
|
1095
|
+
return this.connection.WUResubmit(deepMixinT<WsWorkunits.WUResubmit>({}, request, {
|
|
1096
|
+
Wuids: { Item: [this.Wuid] }
|
|
1097
|
+
}));
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
protected WUDetailsMeta(request: Partial<WsWorkunits.WUDetailsMeta>): Promise<WsWorkunits.WUDetailsMetaResponse> {
|
|
1101
|
+
return this.connection.WUDetailsMeta(request);
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
protected WUDetails(request: RecursivePartial<WsWorkunits.WUDetails>): Promise<WsWorkunits.WUDetailsResponse> {
|
|
1105
|
+
return this.connection.WUDetails(deepMixinT<WsWorkunits.WUDetails>({
|
|
1106
|
+
ScopeFilter: {
|
|
1107
|
+
MaxDepth: 9999
|
|
1108
|
+
},
|
|
1109
|
+
ScopeOptions: {
|
|
1110
|
+
IncludeMatchedScopesInResults: true,
|
|
1111
|
+
IncludeScope: true,
|
|
1112
|
+
IncludeId: false,
|
|
1113
|
+
IncludeScopeType: false
|
|
1114
|
+
},
|
|
1115
|
+
PropertyOptions: {
|
|
1116
|
+
IncludeName: true,
|
|
1117
|
+
IncludeRawValue: false,
|
|
1118
|
+
IncludeFormatted: true,
|
|
1119
|
+
IncludeMeasure: true,
|
|
1120
|
+
IncludeCreator: false,
|
|
1121
|
+
IncludeCreatorType: false
|
|
1122
|
+
}
|
|
1123
|
+
}, request, { WUID: this.Wuid })).then((response) => {
|
|
1124
|
+
return deepMixinT<WsWorkunits.WUDetailsResponse>({
|
|
1125
|
+
Scopes: {
|
|
1126
|
+
Scope: []
|
|
1127
|
+
}
|
|
1128
|
+
}, response);
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
protected WUAction(actionType: WsWorkunits.ECLWUActions): Promise<WsWorkunits.WUActionResponse> {
|
|
1133
|
+
return this.connection.WUAction({
|
|
1134
|
+
Wuids: { Item: [this.Wuid] },
|
|
1135
|
+
WUActionType: actionType
|
|
1136
|
+
}).then((response) => {
|
|
1137
|
+
return this.refresh().then(() => {
|
|
1138
|
+
this._monitor();
|
|
1139
|
+
return response;
|
|
1140
|
+
});
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
publish(name?: string) {
|
|
1145
|
+
return this.connection.WUPublishWorkunit({
|
|
1146
|
+
Wuid: this.Wuid,
|
|
1147
|
+
Cluster: this.Cluster,
|
|
1148
|
+
JobName: name || this.Jobname,
|
|
1149
|
+
AllowForeignFiles: true,
|
|
1150
|
+
Activate: WsWorkunits.WUQueryActivationMode.ActivateQuery,
|
|
1151
|
+
Wait: 5000
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
publishEx(request: Partial<WsWorkunits.WUPublishWorkunit>) {
|
|
1156
|
+
const service = new WorkunitsServiceEx({ baseUrl: "" });
|
|
1157
|
+
const publishRequest = {
|
|
1158
|
+
Wuid: this.Wuid,
|
|
1159
|
+
Cluster: this.Cluster,
|
|
1160
|
+
JobName: this.Jobname,
|
|
1161
|
+
AllowForeignFiles: true,
|
|
1162
|
+
Activate: 1,
|
|
1163
|
+
Wait: 5000,
|
|
1164
|
+
...request
|
|
1165
|
+
};
|
|
1166
|
+
return service.WUPublishWorkunitEx(publishRequest);
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
protected WUCDebug(command: string, opts: any = {}): Promise<XMLNode | null> {
|
|
1170
|
+
let optsStr = "";
|
|
1171
|
+
for (const key in opts) {
|
|
1172
|
+
if (opts.hasOwnProperty(key)) {
|
|
1173
|
+
optsStr += ` ${key}='${opts[key]}'`;
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
return this.connection.WUCDebugEx({
|
|
1177
|
+
Wuid: this.Wuid,
|
|
1178
|
+
Command: `<debug:${command} uid='${this.Wuid}'${optsStr}/>`
|
|
1179
|
+
}).then((response) => {
|
|
1180
|
+
return response;
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
debug(command: string, opts?: object): Promise<XMLNode> {
|
|
1185
|
+
if (!this.isDebugging()) {
|
|
1186
|
+
return Promise.resolve(new XMLNode(command));
|
|
1187
|
+
}
|
|
1188
|
+
return this.WUCDebug(command, opts).then((response: XMLNode) => {
|
|
1189
|
+
const retVal: XMLNode[] = response.children(command);
|
|
1190
|
+
if (retVal.length) {
|
|
1191
|
+
return retVal[0];
|
|
1192
|
+
}
|
|
1193
|
+
return new XMLNode(command);
|
|
1194
|
+
}).catch((_) => {
|
|
1195
|
+
logger.error(_);
|
|
1196
|
+
return Promise.resolve(new XMLNode(command));
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
debugStatus(): Promise<XMLNode> {
|
|
1201
|
+
if (!this.isDebugging()) {
|
|
1202
|
+
return Promise.resolve<any>({
|
|
1203
|
+
DebugState: { state: "unknown" }
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1206
|
+
return this.debug("status").then((response) => {
|
|
1207
|
+
const debugState = { ...this.DebugState, ...response.$ };
|
|
1208
|
+
this.set({
|
|
1209
|
+
DebugState: debugState
|
|
1210
|
+
});
|
|
1211
|
+
return response;
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
debugContinue(mode = ""): Promise<XMLNode> {
|
|
1216
|
+
return this.debug("continue", {
|
|
1217
|
+
mode
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
debugStep(mode: string): Promise<XMLNode> {
|
|
1222
|
+
return this.debug("step", {
|
|
1223
|
+
mode
|
|
1224
|
+
});
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
debugPause(): Promise<XMLNode> {
|
|
1228
|
+
return this.debug("interrupt");
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
debugQuit(): Promise<XMLNode> {
|
|
1232
|
+
return this.debug("quit");
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
debugDeleteAllBreakpoints(): Promise<XMLNode> {
|
|
1236
|
+
return this.debug("delete", {
|
|
1237
|
+
idx: 0
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
protected debugBreakpointResponseParser(rootNode: StringAnyMap) {
|
|
1242
|
+
return rootNode.children().map((childNode: XMLNode) => {
|
|
1243
|
+
if (childNode.name === "break") {
|
|
1244
|
+
return childNode.$;
|
|
1245
|
+
}
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
debugBreakpointAdd(id: string, mode: string, action: string): Promise<XMLNode> {
|
|
1250
|
+
return this.debug("breakpoint", {
|
|
1251
|
+
id,
|
|
1252
|
+
mode,
|
|
1253
|
+
action
|
|
1254
|
+
}).then((rootNode) => {
|
|
1255
|
+
return this.debugBreakpointResponseParser(rootNode);
|
|
1256
|
+
});
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
debugBreakpointList(): Promise<any[]> {
|
|
1260
|
+
return this.debug("list").then((rootNode) => {
|
|
1261
|
+
return this.debugBreakpointResponseParser(rootNode);
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
debugGraph(): Promise<XGMMLGraph> {
|
|
1266
|
+
if (this._debugAllGraph && this.DebugState["_prevGraphSequenceNum"] === this.DebugState["graphSequenceNum"]) {
|
|
1267
|
+
return Promise.resolve(this._debugAllGraph);
|
|
1268
|
+
}
|
|
1269
|
+
return this.debug("graph", { name: "all" }).then((response) => {
|
|
1270
|
+
this.DebugState["_prevGraphSequenceNum"] = this.DebugState["graphSequenceNum"];
|
|
1271
|
+
this._debugAllGraph = createXGMMLGraph(this.Wuid, response);
|
|
1272
|
+
return this._debugAllGraph;
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
debugBreakpointValid(path: string): Promise<IECLDefintion[]> {
|
|
1277
|
+
return this.debugGraph().then((graph) => {
|
|
1278
|
+
return breakpointLocations(graph, path);
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
debugPrint(edgeID: string, startRow: number = 0, numRows: number = 10): Promise<StringAnyMap[]> {
|
|
1283
|
+
return this.debug("print", {
|
|
1284
|
+
edgeID,
|
|
1285
|
+
startRow,
|
|
1286
|
+
numRows
|
|
1287
|
+
}).then((response: XMLNode) => {
|
|
1288
|
+
return response.children().map((rowNode) => {
|
|
1289
|
+
const retVal: StringAnyMap = {};
|
|
1290
|
+
rowNode.children().forEach((cellNode) => {
|
|
1291
|
+
retVal[cellNode.name] = cellNode.content;
|
|
1292
|
+
});
|
|
1293
|
+
return retVal;
|
|
1294
|
+
});
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
export interface IECLDefintion {
|
|
1300
|
+
id: string;
|
|
1301
|
+
file: string;
|
|
1302
|
+
line: number;
|
|
1303
|
+
column: number;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
const ATTR_DEFINITION = "definition";
|
|
1307
|
+
|
|
1308
|
+
function hasECLDefinition(vertex: XGMMLVertex): boolean {
|
|
1309
|
+
return vertex._![ATTR_DEFINITION] !== undefined;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
function getECLDefinition(vertex: XGMMLVertex): IECLDefintion {
|
|
1313
|
+
const match = /([a-z]:\\(?:[-\w\.\d]+\\)*(?:[-\w\.\d]+)?|(?:\/[\w\.\-]+)+)\((\d*),(\d*)\)/.exec(vertex._![ATTR_DEFINITION]);
|
|
1314
|
+
if (match) {
|
|
1315
|
+
const [, _file, _row, _col] = match;
|
|
1316
|
+
_file.replace(/\/\.\//g, "/");
|
|
1317
|
+
return {
|
|
1318
|
+
id: vertex._!["id"],
|
|
1319
|
+
file: _file,
|
|
1320
|
+
line: +_row,
|
|
1321
|
+
column: +_col
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1324
|
+
throw new Error(`Bad definition: ${vertex._![ATTR_DEFINITION]}`);
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
function breakpointLocations(graph: XGMMLGraph, path?: string): IECLDefintion[] {
|
|
1328
|
+
const retVal: IECLDefintion[] = [];
|
|
1329
|
+
for (const vertex of graph.vertices) {
|
|
1330
|
+
if (hasECLDefinition(vertex)) {
|
|
1331
|
+
const definition = getECLDefinition(vertex);
|
|
1332
|
+
if (definition && !path || path === definition.file) {
|
|
1333
|
+
retVal.push(definition);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
return retVal.sort((l, r) => {
|
|
1338
|
+
return l.line - r.line;
|
|
1339
|
+
});
|
|
1340
|
+
}
|