##// END OF EJS Templates
working on Observable
cin -
r14:53e756f117f7 propose cancellat...
parent child
Show More
@@ -0,0 +1,21
1 import * as TraceSource from './TraceSource'
2
3 class TraceEvent {
4 readonly source: TraceSource;
5
6 readonly level: Number;
7
8 readonly arg: any;
9
10 constructor(source: TraceSource, level: Number, arg: any) {
11 this.source = source;
12 this.level = level;
13 this.arg = arg;
14 }
15 }
16
17 namespace TraceEvent {
18
19 }
20
21 export = TraceEvent No newline at end of file
@@ -0,0 +1,29
1 import { IObservable } from "../../interfaces";
2 import * as TraceEvent from '../TraceEvent';
3 import { ICancellation } from "../../interfaces";
4 import { Cancellation } from "../../Cancellation";
5 import * as TraceSource from "../TraceSource";
6
7 class ConsoleWriter {
8 async write(source: IObservable<TraceEvent>, ct: ICancellation = Cancellation.none) {
9 let next;
10 while(next = await source.next(ct)) {
11 this._writeEvent(next);
12 }
13 }
14
15 private _writeEvent(next: TraceEvent) {
16 if (next.level >= TraceSource.LogLevel) {
17 console.log(next.source.toString(), next.arg);
18 } else if(next.level >= TraceSource.WarnLevel) {
19 console.warn(next.source.toString(), next.arg);
20 } else {
21 console.error(next.source.toString(), next.arg);
22 }
23 }
24 }
25
26 namespace ConsoleWriter {
27 }
28
29 export = ConsoleWriter; No newline at end of file
@@ -1,23 +1,29
1 import { IObservable, IObserver, IDestroyable, ICancellation } from '../interfaces';
1 import { IObservable, IDestroyable, ICancellation } from '../interfaces';
2 2 import { Cancellation } from '../Cancellation'
3 import * as TraceSource from '../log/TraceSource'
4 3 import { argumentNotNull } from '../safe';
5 4
6 const trace = TraceSource.get('@implab/core/components/Observable');
7
8 5
9 class Observable<T> implements IObservable<T> {
10 private _once = new Array<IObserver<T>>();
11
12 private readonly _observers = new Array<IObserver<T>>();
6 interface Handler<T> {
7 (x:T) : void
8 }
13 9
14 constructor(func: (notify: IObserver<T>) => void) {
15 argumentNotNull(func, "func");
16
17 func(this._notify.bind(this));
10 interface Initializer<T> {
11 (notify: Handler<T>) : (() => void) | void;
18 12 }
19 13
20 on(observer: IObserver<T>): IDestroyable {
14
15 class Observable<T> implements IObservable<T>, IDestroyable {
16 private _once = new Array<Handler<T>>();
17
18 private readonly _observers = new Array<Handler<T>>();
19
20 private readonly _cleanup : (() => void) | void;
21
22 constructor(func?: Initializer<T>) {
23 this._cleanup = func && func(this._notify.bind(this));
24 }
25
26 on(observer: Handler<T>, error?: Handler<any>, complete?: () => void): IDestroyable {
21 27 argumentNotNull(observer, "observer");
22 28
23 29 this._observers.push(observer);
@@ -30,7 +36,7 class Observable<T> implements IObservab
30 36 }
31 37 }
32 38
33 wait(ct: ICancellation = Cancellation.none): Promise<T> {
39 next(ct: ICancellation = Cancellation.none): Promise<T> {
34 40 return new Promise<T>((resolve, reject) => {
35 41 this._once.push(resolve);
36 42 if (ct.isSupported()) {
@@ -42,24 +48,28 class Observable<T> implements IObservab
42 48 });
43 49 }
44 50
45 onObserverException(e: any) {
46 trace.error("Unhandled exception in the observer: {0}", e);
51 destroy() {
52 if(this._cleanup)
53 this._cleanup.call(null);
47 54 }
48 55
49 private _removeOnce(d: IObserver<T>) {
56 protected onObserverException(e: any) {
57 }
58
59 private _removeOnce(d: Handler<T>) {
50 60 let i = this._once.indexOf(d);
51 61 if (i >= 0)
52 62 this._once.splice(i);
53 63 }
54 64
55 private _removeObserver(d: IObserver<T>) {
65 private _removeObserver(d: Handler<T>) {
56 66 let i = this._observers.indexOf(d);
57 67 if (i >= 0)
58 68 this._observers.splice(i);
59 69 }
60 70
61 private _notify(evt: T) {
62 let guard = (observer: IObserver<T>) => {
71 protected _notify(evt: T) {
72 let guard = (observer: Handler<T>) => {
63 73 try {
64 74 observer(evt);
65 75 } catch (e) {
@@ -79,7 +89,6 class Observable<T> implements IObservab
79 89 }
80 90
81 91 namespace Observable {
82 export const traceSource = trace;
83 92 }
84 93
85 94 export = Observable; No newline at end of file
@@ -1,5 +1,3
1 import { watchFile } from "fs";
2
3 1 export interface IDestroyable {
4 2 destroy();
5 3 }
@@ -72,12 +70,7 export interface ICancellable {
72 70 cancel(reason?: any): void;
73 71 }
74 72
75 export interface IObserver<T> {
76 (x:T): void;
77 }
78
79 73 export interface IObservable<T> {
80 on(observer: IObserver<T>): IDestroyable;
81
82 wait(ct?: ICancellation) : Promise<T>;
74 on(next: (x:T) => void, error?: (e:any) => void, complete?:() => void): IDestroyable;
75 next(ct?: ICancellation) : Promise<T>;
83 76 } No newline at end of file
@@ -1,17 +1,8
1 1 import * as format from '../text/format'
2 2 import { argumentNotNull } from '../safe';
3
4 interface TraceEventHandler {
5 (sender: TraceSource, level: number, arg: any): void;
6 }
7
8 interface TraceSourceHandler {
9 (source: TraceSource): void;
10 }
11
12 interface Destroyable {
13 destroy();
14 }
3 import * as Observable from '../components/Observable'
4 import { IDestroyable } from '../interfaces';
5 import * as TraceEvent from './TraceEvent'
15 6
16 7 class Registry {
17 8 static readonly instance = new Registry();
@@ -46,7 +37,7 class Registry {
46 37 this._listeners[i].call(null, source);
47 38 }
48 39
49 on(handler: TraceSourceHandler): Destroyable {
40 on(handler: (source: TraceSource) => void): IDestroyable {
50 41 argumentNotNull(handler, "handler");
51 42 var me = this;
52 43
@@ -65,45 +56,18 class Registry {
65 56 }
66 57 }
67 58
68 class TraceSource {
69
59 class TraceSource extends Observable<TraceEvent> {
70 60 readonly id: any
71 61
72 // using array will provide faster iteration the with object
73 private _handlers: Array<TraceEventHandler> = new Array<TraceEventHandler>();
74
75 62 level: number
76 63
77 64 constructor(id: any) {
65 super();
78 66 this.id = id || new Object();
79 67 }
80 68
81 on(handler: TraceEventHandler): Destroyable {
82 argumentNotNull(handler, "handler");
83 var me = this;
84 me._handlers.push(handler);
85
86 return {
87 destroy() {
88 me.remove(handler);
89 }
90 }
91 }
92
93 remove(handler: TraceEventHandler): void {
94 let i = this._handlers.indexOf(handler);
95 if (i >= 0)
96 this._handlers.splice(i, 1);
97 }
98
99 69 protected emit(level: number, arg: any) {
100 this._handlers.forEach(h => {
101 try {
102 h(this, level, arg);
103 } catch (e) {
104 // suppress error in log handlers
105 }
106 });
70 this._notify(new TraceEvent(this, level, arg));
107 71 }
108 72
109 73 isDebugEnabled() {
@@ -178,7 +142,7 class TraceSource {
178 142 *
179 143 * @param handler the handler which will be called for each trace source
180 144 */
181 static on(handler: TraceSourceHandler) {
145 static on(handler: (source: TraceSource) => void) {
182 146 return Registry.instance.on(handler);
183 147 }
184 148
@@ -1,10 +1,8
1 1 import * as tape from 'tape';
2 2 import * as ActivatableMixin from '@implab/core/components/ActivatableMixin';
3 3 import { AsyncComponent } from '@implab/core/components/AsyncComponent';
4 import { IActivationController } from '@implab/core/components/IActivationController';
5 import { IActivatable } from '@implab/core/components/IActivatable';
6 import { ICancellation } from '@implab/core/ICancellation';
7 import { EmptyCancellation } from '@implab/core/EmptyCancellation';
4 import { IActivationController, IActivatable, ICancellation } from '@implab/core/interfaces';
5 import { Cancellation } from '@implab/core/Cancellation';
8 6
9 7 class SimpleActivatable extends ActivatableMixin(AsyncComponent) {
10 8
@@ -33,20 +31,20 class MockActivationController implement
33 31 await component.activate();
34 32 }
35 33
36 async activating(component: IActivatable, ct: ICancellation = EmptyCancellation.default) {
34 async activating(component: IActivatable, ct: ICancellation = Cancellation.none) {
37 35 if (component != this._active)
38 36 await this.deactivate();
39 37 }
40 38
41 async activated(component: IActivatable, ct: ICancellation = EmptyCancellation.default) {
39 async activated(component: IActivatable, ct: ICancellation = Cancellation.none) {
42 40 this._active = component;
43 41 }
44 42
45 async deactivating(component: IActivatable, ct: ICancellation = EmptyCancellation.default) {
43 async deactivating(component: IActivatable, ct: ICancellation = Cancellation.none) {
46 44
47 45 }
48 46
49 async deactivated(component: IActivatable, ct: ICancellation = EmptyCancellation.default) {
47 async deactivated(component: IActivatable, ct: ICancellation = Cancellation.none) {
50 48 if (this._active == component)
51 49 this._active = null;
52 50 }
@@ -1,5 +1,6
1 1 import * as TraceSource from '@implab/core/log/TraceSource'
2 2 import * as tape from 'tape';
3 import * as ConsoleWriter from '@implab/core/log/writers/ConsoleWriter';
3 4
4 5 const sourceId = 'test/TraceSourceTests';
5 6
@@ -8,10 +9,10 tape('trace message', t => {
8 9
9 10 trace.level = TraceSource.DebugLevel;
10 11
11 let h = trace.on((sender,level,msg) => {
12 t.equal(sender, trace, "sender should be the current trace source");
13 t.equal(TraceSource.DebugLevel, level, "level should be debug level");
14 t.equal(msg, "Hello, World!", "The message should be a formatted message");
12 let h = trace.on((ev) => {
13 t.equal(ev.source, trace, "sender should be the current trace source");
14 t.equal(ev.level, TraceSource.DebugLevel, "level should be debug level");
15 t.equal(ev.arg, "Hello, World!", "The message should be a formatted message");
15 16
16 17 t.end();
17 18 });
@@ -30,10 +31,10 tape('trace event', t => {
30 31 name: "custom event"
31 32 };
32 33
33 let h = trace.on((sender,level,msg) => {
34 t.equal(sender, trace, "sender should be the current trace source");
35 t.equal(TraceSource.DebugLevel, level, "level should be debug level");
36 t.equal(msg, event, "The message should be the specified object");
34 let h = trace.on((ev) => {
35 t.equal(ev.source, trace, "sender should be the current trace source");
36 t.equal(ev.level, TraceSource.DebugLevel, "level should be debug level");
37 t.equal(ev.arg, event, "The message should be the specified object");
37 38
38 39 t.end();
39 40 });
@@ -41,4 +42,21 tape('trace event', t => {
41 42 trace.traceEvent(TraceSource.DebugLevel, event);
42 43
43 44 h.destroy();
45 });
46
47 tape('console writer', async t => {
48 let writer = new ConsoleWriter();
49
50 let trace = TraceSource.get(sourceId);
51 trace.level = TraceSource.DebugLevel;
52
53 let p = writer.write(trace);
54
55 trace.log("Hello, {0}!", 'World');
56 trace.warn("Look at me!");
57 trace.error("DIE!");
58
59 console.log("DONE");
60
61 t.end();
44 62 }); No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now