Improved logging

pull/4769/head
Roman Roelofsen 8 years ago
parent 62c5823d74
commit 3e33cb3dc7
  1. 9
      frontend/app/components/work-packages/work-package-cache.service.ts
  2. 262
      frontend/app/helpers/reactive-fassade.ts
  3. 7
      frontend/app/states.ts

@ -84,13 +84,16 @@ export class WorkPackageCacheService {
// .filter(wp => wp !== undefined); // .filter(wp => wp !== undefined);
const state = states.workPackages.get(workPackageId.toString()); const state = states.workPackages.get(workPackageId.toString());
if (forceUpdate || state.isPristine()) { if (forceUpdate) {
// state.clear(); state.clear();
// this.apiWorkPackages.loadWorkPackageById(workPackageId, forceUpdate).then(wp => { // this.apiWorkPackages.loadWorkPackageById(workPackageId, forceUpdate).then(wp => {
// state.put(wp); // state.put(wp);
// }); // });
state.putFromPromise(this.apiWorkPackages.loadWorkPackageById(workPackageId, forceUpdate));
} }
state.putFromPromiseIfPristine(
this.apiWorkPackages.loadWorkPackageById(workPackageId, forceUpdate));
return state; return state;
} }

@ -3,126 +3,120 @@ import Observable = Rx.Observable;
import IScope = angular.IScope; import IScope = angular.IScope;
import IPromise = Rx.IPromise; import IPromise = Rx.IPromise;
let logFn: (msg: string) => any = null;
export function setStateLogFunction(fn: (msg: string) => any) {
logFn = fn;
}
export abstract class StoreElement { export abstract class StoreElement {
public pathInStore: string = null; public pathInStore: string = null;
public logFn: (msg: any) => any = null;
log(msg: string) { log(msg: string) {
if (this.pathInStore === null || logFn === null) { if (this.pathInStore && this.logFn) {
return; this.logFn("[" + this.pathInStore + "] " + msg);
} }
logFn("[" + this.pathInStore + "] " + msg);
} }
} }
type LoaderFn = () => IPromise<any>; // type LoaderFn = () => IPromise<any>;
//
export class LoadingState<T> extends StoreElement { // export class LoadingState<T> extends StoreElement {
//
private counter = 0; // private counter = 0;
//
private subject = new Rx.ReplaySubject<[number, T]>(1); // private subject = new Rx.ReplaySubject<[number, T]>(1);
//
private observable: Observable<[number, T]>; // private observable: Observable<[number, T]>;
//
private lastLoadRequestedTimestamp: number = 0; // private lastLoadRequestedTimestamp: number = 0;
//
public minimumTimeoutInMs: number; // public minimumTimeoutInMs: number;
//
private loaderFn: LoaderFn = (): any => { // private loaderFn: LoaderFn = (): any => {
throw "loaderFn not defined"; // throw "loaderFn not defined";
}; // };
//
constructor(minimumTimeoutInMs: number = 5000) { // constructor(minimumTimeoutInMs: number = 5000) {
super(); // super();
this.minimumTimeoutInMs = minimumTimeoutInMs; // this.minimumTimeoutInMs = minimumTimeoutInMs;
this.observable = this.subject // this.observable = this.subject
.filter(val => val[1] !== null); // .filter(val => val[1] !== null);
} // }
//
public clear() { // public clear() {
this.log("clear"); // this.log("clear");
this.lastLoadRequestedTimestamp = 0; // this.lastLoadRequestedTimestamp = 0;
this.setState(this.counter++, null); // this.setState(this.counter++, null);
} // }
//
public setLoaderFn(loaderFn: LoaderFn) { // public setLoaderFn(loaderFn: LoaderFn) {
this.log("setLoaderFn"); // this.log("setLoaderFn");
this.loaderFn = loaderFn; // this.loaderFn = loaderFn;
} // }
//
// Force // // Force
//
public forceLoadAndGet(scope: IScope): IPromise<T> { // public forceLoadAndGet(scope: IScope): IPromise<T> {
const currentCounter = this.counter++; // const currentCounter = this.counter++;
this.lastLoadRequestedTimestamp = Date.now(); // this.lastLoadRequestedTimestamp = Date.now();
//
this.log("loader called"); // this.log("loader called");
return this.loaderFn().then(val => { // return this.loaderFn().then(val => {
runInScopeDigest(scope, () => { // runInScopeDigest(scope, () => {
this.setState(currentCounter, val); // this.setState(currentCounter, val);
}); // });
return val; // return val;
}); // });
} // }
//
public forceLoadAndObserve(scope: IScope): Observable<T> { // public forceLoadAndObserve(scope: IScope): Observable<T> {
const currentCounter = this.counter; // const currentCounter = this.counter;
this.forceLoadAndGet(null); // this.forceLoadAndGet(null);
return this.scopedObservable(scope) // return this.scopedObservable(scope)
.skipWhile((val) => { // .skipWhile((val) => {
return val[0] < currentCounter; // return val[0] < currentCounter;
}) // })
.map(val => val[1]); // .map(val => val[1]);
} // }
//
// Maybe // // Maybe
//
public maybeLoadAndGet(scope: IScope): IPromise<T> { // public maybeLoadAndGet(scope: IScope): IPromise<T> {
if (this.isTimeoutPassed()) { // if (this.isTimeoutPassed()) {
return this.forceLoadAndGet(scope); // return this.forceLoadAndGet(scope);
} else { // } else {
return this.get(); // return this.get();
} // }
} // }
//
public maybeLoadAndObserve(scope: IScope): Observable<T> { // public maybeLoadAndObserve(scope: IScope): Observable<T> {
this.maybeLoadAndGet(null); // this.maybeLoadAndGet(null);
return this.observe(scope); // return this.observe(scope);
} // }
//
// Passive // // Passive
//
public get(): IPromise<T> { // public get(): IPromise<T> {
return this.observable.take(1).map(val => val[1]).toPromise(); // return this.observable.take(1).map(val => val[1]).toPromise();
} // }
//
public observe(scope: IScope): Observable<T> { // public observe(scope: IScope): Observable<T> {
return this.scopedObservable(scope).map(val => val[1]); // return this.scopedObservable(scope).map(val => val[1]);
} // }
//
// -------------------------------------------------------------- // // --------------------------------------------------------------
//
private setState(counter: number, val: T) { // private setState(counter: number, val: T) {
this.subject.onNext([counter, val]); // this.subject.onNext([counter, val]);
} // }
//
private isTimeoutPassed(): boolean { // private isTimeoutPassed(): boolean {
return (Date.now() - this.lastLoadRequestedTimestamp) > this.minimumTimeoutInMs; // return (Date.now() - this.lastLoadRequestedTimestamp) > this.minimumTimeoutInMs;
} // }
//
private scopedObservable(scope: IScope): Observable<[number, T]> { // private scopedObservable(scope: IScope): Observable<[number, T]> {
return scope ? scopedObservable(scope, this.observable) : this.observable; // return scope ? scopedObservable(scope, this.observable) : this.observable;
} // }
} // }
interface PromiseLike<T> { interface PromiseLike<T> {
then(callback: (value: T) => any): any; then(callback: (value: T) => any): any;
@ -130,7 +124,7 @@ interface PromiseLike<T> {
export class State<T> extends StoreElement { export class State<T> extends StoreElement {
private hasValue = false; private timestampOfLastValue = -1;
private putFromPromiseCalled = false; private putFromPromiseCalled = false;
@ -148,25 +142,36 @@ export class State<T> extends StoreElement {
* a value is awaited from a promise (via putFromPromise). * a value is awaited from a promise (via putFromPromise).
*/ */
public isPristine(): boolean { public isPristine(): boolean {
return !this.hasValue && !this.putFromPromiseCalled; return this.timestampOfLastValue === -1 && !this.putFromPromiseCalled;
} }
public clear() { public clear(): this {
this.log("State#clear()");
this.setState(null); this.setState(null);
return this;
} }
public put(value: T) { public put(value: T): this {
this.log("put"); this.log("State#put(...)");
this.setState(value); this.setState(value);
return this;
} }
public putFromPromise(promise: PromiseLike<T>) { public putFromPromise(promise: PromiseLike<T>): this {
this.log("putFromPromise");
this.clear(); this.clear();
this.putFromPromiseCalled = true; this.putFromPromiseCalled = true;
promise.then((value: T) => { promise.then((value: T) => {
this.log("State#putFromPromise(...)");
this.setState(value); this.setState(value);
}); });
return this;
}
public putFromPromiseIfPristine(promise: PromiseLike<T>): this {
if (this.isPristine()) {
this.putFromPromise(promise);
}
return this;
} }
public get(): IPromise<T> { public get(): IPromise<T> {
@ -178,7 +183,7 @@ export class State<T> extends StoreElement {
} }
private setState(val: T) { private setState(val: T) {
this.hasValue = val !== null && val !== undefined; this.timestampOfLastValue = val !== null && val !== undefined ? Date.now() : -1;
this.subject.onNext(val); this.subject.onNext(val);
} }
@ -197,7 +202,7 @@ export class MultiState<T> extends StoreElement {
} }
put(id: string, value: T): State<T> { put(id: string, value: T): State<T> {
this.log("put " + id); this.log("MultiState#put(" + id + ")");
const state = this.get(id); const state = this.get(id);
state.put(value); state.put(value);
return state; return state;
@ -212,20 +217,27 @@ export class MultiState<T> extends StoreElement {
} }
function traverse(elem: any, path: string) { function traverse(elem: any, path: string, logFn: (msg: any) => any) {
const values = (_ as any).toPairs(elem);
for (let [key, value] of values) { for (const key in elem) {
if (!elem.hasOwnProperty(key)) {
continue;
}
const value = elem[key];
let location = path.length > 0 ? path + "." + key : key; let location = path.length > 0 ? path + "." + key : key;
if (value instanceof StoreElement) { if (value instanceof StoreElement) {
value.pathInStore = location; value.pathInStore = location;
value.logFn = logFn;
} else { } else {
traverse(value, location); traverse(value, location, logFn);
} }
} }
} }
export function initStates(states: any) { export function initStates(states: any, logFn?: (msg: any) => any) {
return traverse(states, ""); return traverse(states, "", logFn);
} }

@ -1,11 +1,12 @@
import {MultiState, initStates, setStateLogFunction} from "./helpers/reactive-fassade"; import {MultiState, initStates} from "./helpers/reactive-fassade";
import {WorkPackageResource} from "./components/api/api-v3/hal-resources/work-package-resource.service"; import {WorkPackageResource} from "./components/api/api-v3/hal-resources/work-package-resource.service";
export const states = { export const states = {
workPackages: new MultiState<WorkPackageResource>() workPackages: new MultiState<WorkPackageResource>()
}; };
// initStates(states); initStates(states, (msg: any) => console.trace(msg));
// setStateLogFunction(log => console.trace(log));

Loading…
Cancel
Save