diff options
Diffstat (limited to 'src/client/northstar/operations')
| -rw-r--r-- | src/client/northstar/operations/BaseOperation.ts | 174 | ||||
| -rw-r--r-- | src/client/northstar/operations/HistogramOperation.ts | 111 |
2 files changed, 285 insertions, 0 deletions
diff --git a/src/client/northstar/operations/BaseOperation.ts b/src/client/northstar/operations/BaseOperation.ts new file mode 100644 index 000000000..4c0303a48 --- /dev/null +++ b/src/client/northstar/operations/BaseOperation.ts @@ -0,0 +1,174 @@ +import { FilterModel } from '../core/filter/FilterModel' +import { ErrorResult, Exception, OperationParameters, OperationReference, Result, ResultParameters } from '../model/idea/idea'; +import { action, computed, observable } from "mobx"; +import { Gateway } from '../manager/Gateway'; + +export abstract class BaseOperation { + private _interactionTimeoutId: number = 0; + private static _currentOperations: Map<number, PollPromise> = new Map<number, PollPromise>(); + //public InteractionTimeout: EventDelegate<InteractionTimeoutEventArgs> = new EventDelegate<InteractionTimeoutEventArgs>(); + + @observable public Error: string = ""; + @observable public OverridingFilters: FilterModel[] = []; + @observable public Result: Result | undefined; + @observable public ComputationStarted: boolean = false; + public OperationReference: OperationReference | undefined = undefined; + + private static _nextId = 0; + public RequestSalt: string = ""; + public Id: number; + + constructor() { + this.Id = BaseOperation._nextId++; + } + + @computed + public get FilterString(): string { + + // if (this.OverridingFilters.length > 0) { + // return "(" + this.OverridingFilters.filter(fm => fm != null).map(fm => fm.ToPythonString()).join(" || ") + ")"; + // } + // let rdg = MainManager.Instance.MainViewModel.FilterReverseDependencyGraph; + // let sliceModel = this.TypedViewModel.IncomingSliceModel; + // if (sliceModel != null && sliceModel.Source != null && instanceOfIBaseFilterProvider(sliceModel.Source) && rdg.has(sliceModel.Source)) { + // let filterModels = sliceModel.Source.FilterModels.map(f => f); + // return FilterModel.GetFilterModelsRecursive(rdg.get(sliceModel.Source), new Set<GraphNode<BaseOperationViewModel, FilterLinkViewModel>>(), filterModels, false); + // } + + // if (rdg.has(this.TypedViewModel)) { + // let filterModels = []; + // return FilterModel.GetFilterModelsRecursive(rdg.get(this.TypedViewModel), new Set<GraphNode<BaseOperationViewModel, FilterLinkViewModel>>(), filterModels, true) + // } + return ""; + } + + + @action + public SetResult(result: Result): void { + this.Result = result; + } + + public async Update(): Promise<void> { + + try { + if (BaseOperation._currentOperations.has(this.Id)) { + BaseOperation._currentOperations.get(this.Id)!.Cancel(); + if (this.OperationReference) { + Gateway.Instance.PauseOperation(this.OperationReference.toJSON()); + } + } + + let operationParameters = this.CreateOperationParameters(); + this.Result = undefined; + this.Error = ""; + let salt = Math.random().toString(); + this.RequestSalt = salt; + + if (!operationParameters) { + this.ComputationStarted = false; + return; + } + + this.ComputationStarted = true; + //let start = performance.now(); + let promise = Gateway.Instance.StartOperation(operationParameters.toJSON()); + promise.catch(err => { + action(() => { + this.Error = err; + console.error(err); + }); + }); + let operationReference = await promise; + + + if (operationReference) { + this.OperationReference = operationReference; + + let resultParameters = new ResultParameters(); + resultParameters.operationReference = operationReference; + + let pollPromise = new PollPromise(salt, operationReference); + BaseOperation._currentOperations.set(this.Id, pollPromise); + + pollPromise.Start(async () => { + let result = await Gateway.Instance.GetResult(resultParameters.toJSON()); + if (result instanceof ErrorResult) { + throw new Error((result as ErrorResult).message); + } + if (this.RequestSalt == pollPromise.RequestSalt) { + if (result && (!this.Result || this.Result.progress != result.progress)) { + /*if (operationViewModel.Result !== null && operationViewModel.Result !== undefined) { + let t1 = performance.now(); + console.log((t1 - start) + " milliseconds."); + start = performance.now(); + }*/ + this.SetResult(result); + } + + if (!result || result.progress! < 1) { + return true; + } + } + return false; + }, 100).catch((err: Error) => action(() => { + this.Error = err.message; + console.error(err.message); + })() + ); + } + } + catch (err) { + console.error(err as Exception); + // ErrorDialog.Instance.HandleError(err, operationViewModel); + } + } + + public CreateOperationParameters(): OperationParameters | undefined { return undefined; } + + private interactionTimeout() { + // clearTimeout(this._interactionTimeoutId); + // this.InteractionTimeout.Fire(new InteractionTimeoutEventArgs(this.TypedViewModel, InteractionTimeoutType.Timeout)); + } +} + +export class PollPromise { + public RequestSalt: string; + public OperationReference: OperationReference; + + private _notCanceled: boolean = true; + private _poll: undefined | (() => Promise<boolean>); + private _delay: number = 0; + + public constructor(requestKey: string, operationReference: OperationReference) { + this.RequestSalt = requestKey; + this.OperationReference = operationReference; + } + + public Cancel(): void { + this._notCanceled = false; + } + + public Start(poll: () => Promise<boolean>, delay: number): Promise<void> { + this._poll = poll; + this._delay = delay; + return this.pollRecursive(); + } + + private pollRecursive = (): Promise<void> => { + return Promise.resolve().then(this._poll).then((flag) => { + this._notCanceled && flag && new Promise((res) => (setTimeout(res, this._delay))) + .then(this.pollRecursive); + }); + } +} + + +export class InteractionTimeoutEventArgs { + constructor(public Sender: object, public Type: InteractionTimeoutType) { + } +} + +export enum InteractionTimeoutType { + Reset = 0, + Timeout = 1 +} diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts new file mode 100644 index 000000000..a4f5cac70 --- /dev/null +++ b/src/client/northstar/operations/HistogramOperation.ts @@ -0,0 +1,111 @@ +import { reaction, computed, action } from "mobx"; +import { Attribute, DataType, QuantitativeBinRange, HistogramOperationParameters, AggregateParameters, AggregateFunction, AverageAggregateParameters } from "../model/idea/idea"; +import { ArrayUtil } from "../utils/ArrayUtil"; +import { CalculatedAttributeManager } from "../core/attribute/CalculatedAttributeModel"; +import { ModelHelpers } from "../model/ModelHelpers"; +import { SETTINGS_X_BINS, SETTINGS_Y_BINS, SETTINGS_SAMPLE_SIZE } from "../model/binRanges/VisualBinRangeHelper"; +import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel"; +import { Main } from "../../views/Main"; +import { BaseOperation } from "./BaseOperation"; + + +export class HistogramOperation extends BaseOperation { + public X: AttributeTransformationModel; + public Y: AttributeTransformationModel; + public V: AttributeTransformationModel; + constructor(x: AttributeTransformationModel, y: AttributeTransformationModel, v: AttributeTransformationModel) { + super(); + this.X = x; + this.Y = y; + this.V = v; + reaction(() => this.createOperationParamsCache, () => this.Update()); + } + + @computed.struct + public get BrushString() { + return []; + // let brushes = []; + // this.TypedViewModel.BrusherModels.map(brushLinkModel => { + // if (instanceOfIBaseFilterProvider(brushLinkModel.From) && brushLinkModel.From.FilterModels.some && brushLinkModel.From instanceof BaseOperationViewModel) { + // let brushFilterModels = []; + // let gnode = MainManager.Instance.MainViewModel.FilterDependencyGraph.has(brushLinkModel.From) ? + // MainManager.Instance.MainViewModel.FilterDependencyGraph.get(brushLinkModel.From) : + // new GraphNode<BaseOperationViewModel, FilterLinkViewModel>(brushLinkModel.From); + // let brush = FilterModel.GetFilterModelsRecursive(gnode, new Set<GraphNode<BaseOperationViewModel, FilterLinkViewModel>>(), brushFilterModels, false); + // brushes.push(brush); + // } + // }); + // return brushes; + } + + + @computed.struct + public get SelectionString() { + return ""; + // let filterModels = new Array<FilterModel>(); + // let rdg = MainManager.Instance.MainViewModel.FilterReverseDependencyGraph; + // let graphNode: GraphNode<BaseOperationViewModel, FilterLinkViewModel>; + // if (rdg.has(this.TypedViewModel)) { + // graphNode = MainManager.Instance.MainViewModel.FilterReverseDependencyGraph.get(this.TypedViewModel); + // } + // else { + // graphNode = new GraphNode<BaseOperationViewModel, FilterLinkViewModel>(this.TypedViewModel); + // } + // return FilterModel.GetFilterModelsRecursive(graphNode, new Set<GraphNode<BaseOperationViewModel, FilterLinkViewModel>>(), filterModels, false); + } + + GetAggregateParameters(histoX: AttributeTransformationModel, histoY: AttributeTransformationModel, histoValue: AttributeTransformationModel) { + let allAttributes = new Array<AttributeTransformationModel>(histoX, histoY, histoValue); + allAttributes = ArrayUtil.Distinct(allAttributes.filter(a => a.AggregateFunction !== AggregateFunction.None)); + + let numericDataTypes = [DataType.Int, DataType.Double, DataType.Float]; + let perBinAggregateParameters: AggregateParameters[] = ModelHelpers.GetAggregateParametersWithMargins(allAttributes); + let globalAggregateParameters: AggregateParameters[] = []; + [histoX, histoY] + .filter(a => a.AggregateFunction === AggregateFunction.None && ArrayUtil.Contains(numericDataTypes, a.AttributeModel.DataType)) + .forEach(a => { + let avg = new AverageAggregateParameters(); + avg.attributeParameters = ModelHelpers.GetAttributeParameters(a.AttributeModel); + globalAggregateParameters.push(avg); + }); + return [perBinAggregateParameters, globalAggregateParameters]; + } + + @computed + get createOperationParamsCache() { + return this.CreateOperationParameters(); + } + + public QRange: QuantitativeBinRange | undefined; + + public CreateOperationParameters(): HistogramOperationParameters | undefined { + if (this.X && this.Y && this.V) { + let [perBinAggregateParameters, globalAggregateParameters] = this.GetAggregateParameters(this.X, this.Y, this.V); + return new HistogramOperationParameters({ + enableBrushComputation: true, + adapterName: Main.Instance.ActiveSchema!.displayName, + filter: this.FilterString, + brushes: this.BrushString, + binningParameters: [ModelHelpers.GetBinningParameters(this.X, SETTINGS_X_BINS, this.QRange ? this.QRange.minValue : undefined, this.QRange ? this.QRange.maxValue : undefined), + ModelHelpers.GetBinningParameters(this.Y, SETTINGS_Y_BINS)], + sampleStreamBlockSize: SETTINGS_SAMPLE_SIZE, + perBinAggregateParameters: perBinAggregateParameters, + globalAggregateParameters: globalAggregateParameters, + sortPerBinAggregateParameter: undefined, + attributeCalculatedParameters: CalculatedAttributeManager + .AllCalculatedAttributes.map(a => ModelHelpers.GetAttributeParametersFromAttributeModel(a)), + degreeOfParallism: 1, // Settings.Instance.DegreeOfParallelism, + isCachable: false + }); + } + } + + + @action + public async Update(): Promise<void> { + // this.TypedViewModel.BrushColors = this.TypedViewModel.BrusherModels.map(e => e.Color); + return super.Update(); + } +} + + |
