samer@3
|
1 :- module(recorder,
|
samer@3
|
2 [ recorder/2
|
samer@3
|
3 , save_events/1
|
samer@3
|
4 , load_events/1
|
samer@4
|
5 , get_events/1
|
samer@3
|
6 , player/2
|
samer@3
|
7 , player/3
|
samer@3
|
8 ]).
|
samer@0
|
9 /** <module> event recording
|
samer@0
|
10
|
samer@0
|
11 This module provides a way to capture and record events processed by
|
samer@0
|
12 the reactive programming framework of reactive.pl.
|
samer@0
|
13 */
|
samer@3
|
14 :- meta_predicate recorder(1,?), player(1,?), player(2,2,?).
|
samer@0
|
15 :- dynamic start_time/1, event/2.
|
samer@0
|
16
|
samer@0
|
17 :- use_module(library(fileutils)).
|
samer@12
|
18 :- use_module(library(utils),[min/3]).
|
samer@0
|
19 :- use_module(reactive).
|
samer@0
|
20
|
samer@0
|
21
|
samer@0
|
22 %% recorder( +Client:ptail, -Proc:process) is det.
|
samer@0
|
23 %
|
samer@0
|
24 % This predicate represents a reactive process that behaves as Client,
|
samer@0
|
25 % but records all events in the Prolog dynamic database. The type signature
|
samer@0
|
26 % implies that the term recorder(Client) is of type =|ptail|=. All previously
|
samer@0
|
27 % recorded events are deleted first. The time at which this predicate was
|
samer@0
|
28 % called is also recorded in the database.
|
samer@0
|
29
|
samer@0
|
30 recorder(Client,Proc) :-
|
samer@0
|
31 get_time(Now),
|
samer@0
|
32 retractall(event(_,_)),
|
samer@0
|
33 retractall(start_time(_)),
|
samer@0
|
34 assert(start_time(Now)),
|
samer@1
|
35 format('recording events for ~w.\n',[Client]),
|
samer@0
|
36 call(Client,C1),
|
samer@0
|
37 recorder_cont(C1,Proc).
|
samer@0
|
38
|
samer@0
|
39 recorder_on_event(E,C1,Proc) :-
|
samer@0
|
40 assert(E),
|
samer@0
|
41 step_event(E,C1,C2),
|
samer@0
|
42 recorder_cont(C2,Proc).
|
samer@0
|
43
|
samer@0
|
44 recorder_on_timeout(T,C1,Proc) :-
|
samer@0
|
45 step_timeout(T,C1,C2),
|
samer@0
|
46 recorder_cont(C2,Proc).
|
samer@0
|
47
|
samer@0
|
48 recorder_cont(C1,Proc) :-
|
samer@0
|
49 get_timeout(C1,T1),
|
samer@0
|
50 ( T1=inf
|
samer@0
|
51 -> req_message(E^recorder_on_event(E,C1), Proc)
|
samer@0
|
52 ; req_message_or_timeout(T1,
|
samer@0
|
53 recorder_on_timeout(T1,C1),
|
samer@0
|
54 E^recorder_on_event(E,C1), Proc)
|
samer@0
|
55 ).
|
samer@0
|
56
|
samer@3
|
57 %% player( +Client:ptail, +Trans:pred(A,A), -Proc:process) is det.
|
samer@0
|
58 %% player( +Client:ptail, -Proc:process) is det.
|
samer@0
|
59 %
|
samer@0
|
60 % This predicate represents a reactive process that behaves as Client,
|
samer@0
|
61 % but plays back events in the Prolog dynamic database. The events are
|
samer@0
|
62 % time shifted by the difference between the recorded start time and the
|
samer@0
|
63 % time at which player/2 is called. The type signature
|
samer@0
|
64 % implies that the term recorder(Client) is of type =|ptail|=.
|
samer@3
|
65 %
|
samer@3
|
66 % player/3 allows an event transformer pred(+EventIn:A,-EventOut:A) to be
|
samer@3
|
67 % specified. player/2 is equivalent to using=/2 as the transformer.
|
samer@0
|
68
|
samer@0
|
69 player(Client,Proc) :-
|
samer@0
|
70 get_time(Now),
|
samer@0
|
71 start_time(T0), DT is Now-T0,
|
samer@0
|
72 setof(event(T,Msg),T1^(event(T1,Msg),T is DT+T1),Events),
|
samer@0
|
73 call(Client,C1),
|
samer@0
|
74 player_cont(Events,C1,Proc).
|
samer@0
|
75
|
samer@3
|
76 player(Client,Trans,Proc) :-
|
samer@3
|
77 get_time(Now),
|
samer@3
|
78 start_time(T0), DT is Now-T0,
|
samer@3
|
79 setof(event(T,Msg),T1^Msg1^(event(T1,Msg1),T is DT+T1, call(Trans,Msg1,Msg)),Events),
|
samer@3
|
80 call(Client,C1),
|
samer@3
|
81 player_cont(Events,C1,Proc).
|
samer@3
|
82
|
samer@0
|
83 player_on_event(Events,C1,Proc) :-
|
samer@0
|
84 player_cont(Events,C1,Proc).
|
samer@0
|
85
|
samer@0
|
86 player_on_timeout(T,ET,Events,C1,Proc) :-
|
samer@0
|
87 ( T<ET
|
samer@0
|
88 -> step_timeout(T,C1,C2),
|
samer@0
|
89 player_cont(Events,C2,Proc)
|
samer@0
|
90 ; Events=[E1|EX],
|
samer@0
|
91 step_event(E1,C1,C2),
|
samer@0
|
92 player_cont(EX,C2,Proc)
|
samer@0
|
93 ).
|
samer@0
|
94
|
samer@0
|
95 player_cont([],C1,C1) :- !,
|
samer@0
|
96 writeln('Playback finished - continuing in interactive mode').
|
samer@0
|
97
|
samer@0
|
98 player_cont(Events,C1,Proc) :-
|
samer@0
|
99 Events=[event(ET,_)|_],
|
samer@0
|
100 get_timeout(C1,T1),
|
samer@0
|
101 min(ET,T1,TO),
|
samer@0
|
102
|
samer@0
|
103 req_message_or_timeout(TO,
|
samer@0
|
104 player_on_timeout(TO,ET,Events,C1),
|
samer@0
|
105 _^player_on_event(Events,C1), Proc).
|
samer@0
|
106
|
samer@0
|
107
|
samer@0
|
108 %% save_events(+FileName:atom) is det.
|
samer@0
|
109 % Save events in the event database to the named file (as Prolog clauses).
|
samer@0
|
110 save_events(File) :-
|
samer@0
|
111 with_output_to_file(File,(listing(start_time),listing(event))).
|
samer@0
|
112
|
samer@0
|
113
|
samer@0
|
114 %% load_events(+FileName:atom) is det.
|
samer@0
|
115 % Load events from the named file to the event database, after removing
|
samer@0
|
116 % any events currently in there.
|
samer@0
|
117 load_events(File) :-
|
samer@0
|
118 retractall(event(_,_)),
|
samer@0
|
119 retractall(start_time(_)),
|
samer@0
|
120 consult(File).
|
samer@0
|
121
|
samer@4
|
122
|
samer@4
|
123 %% get_events(-Events:list(event)) is det.
|
samer@4
|
124 % Gets the currently loaded events as a list. Event times are relative
|
samer@4
|
125 % to start time.
|
samer@4
|
126 get_events(Events) :-
|
samer@4
|
127 start_time(T0),
|
samer@4
|
128 setof(event(T,Msg),T1^(event(T1,Msg),T is T1-T0),Events).
|