1 module dinu.loader.output;
2 
3 
4 import dinu;
5 
6 
7 shared class CommandResult {
8 	long result;
9 	size_t occurrences;
10 	this(){
11 		result = long.max;
12 	}
13 }
14 
15 
16 shared CommandResult[int] running;
17 
18 
19 class OutputLoader: ChoiceLoader {
20 
21 	int[string] loaded;
22 
23 	override void run(){
24 		auto log = options.configPath ~ ".log";
25 		while(!log.exists && active && runProgram)
26 			core.thread.Thread.sleep(10.msecs);
27 		loaded = loaded.init;
28 		auto file = new BufferedFile(log);
29 		file.seekEnd(0);
30 		size_t idx = 10000;
31 		task(&loadBackwards, idx-1000).executeInNewThread;
32 		task(&loadBackwardsExec, idx-1000).executeInNewThread;
33 		while(active && runProgram){
34 			if(!file.eof){
35 				auto line = cast(string)file.readLine;
36 				if(!line.length)
37 					continue;
38 				matchLine(line, idx++);
39 				matchLineExec(line, true);
40 			}else
41 				core.thread.Thread.sleep(5.msecs);
42 		}
43 	}
44 
45 	void loadBackwards(size_t idx){
46 		auto p = pipeProcess(["tac", options.configPath ~ ".log"], Redirect.stdout);
47 		foreach(line; p.stdout.byLine){
48 			matchLine(to!string(line), idx--);
49 			if(idx<10000-2000)
50 				core.thread.Thread.sleep(4.msecs);
51 			if(idx==0 || !active)
52 				break;
53 		}
54 		scope(exit)
55 			p.pid.kill;
56 	}
57 
58 	void loadBackwardsExec(size_t idx){
59 		auto p = pipeProcess(["tac", options.configPath ~ ".exec"], Redirect.stdout);
60 		foreach(line; p.stdout.byLine){
61 			matchLineExec(to!string(line), false);
62 			if(idx<10000-2000)
63 				core.thread.Thread.sleep(4.msecs);
64 			if(idx==0 || !active)
65 				break;
66 		}
67 		scope(exit)
68 			p.pid.kill;
69 	}
70 
71 	void matchLine(string line, size_t idx){
72 		try{
73 			foreach(match; line.matchAll(`([0-9]+) (\S+)(?: (.*))?`)){
74 				auto pid = to!int(match.captures[1]);
75 				if((match.captures[2] == "stdout" || match.captures[2] == "stderr") && match.captures[3].length){
76 					add(new immutable CommandOutput(pid, match.captures[3], idx, match.captures[2]=="stderr"));
77 				}
78 			}
79 		}catch(Exception e){
80 			writeln(e);
81 		}
82 	}
83 
84 	void matchLineExec(string line, bool forward){
85 		try{
86 			foreach(match; line.matchAll(`([0-9]+) (\S+)(?: (.*))?`)){
87 				auto pid = to!int(match.captures[1]);
88 				if(match.captures[2] == "exec"){
89 					auto cmd = match.captures[3].bangSplit;
90 					/+
91 					if(!cmd[2].length)
92 						continue;
93 					+/
94 					if(pid !in running)
95 						running[pid] = new shared CommandResult;
96 					if(!exists("/proc/%s".format(pid)) && running[pid].result == long.max)
97 						running[pid].result = 0;
98 					if(cmd[1] ~ cmd[2] in loaded){
99 						auto l = loaded[cmd[1].idup ~ cmd[2].idup];
100 						running[l].occurrences.atomicOp!"+="(1);
101 						continue;
102 					}
103 					auto history = new immutable CommandHistory(pid, to!Type(cmd[0]), cmd[1].dup, cmd[2].dup);
104 					loaded[cmd[1].idup ~ cmd[2].idup] = pid;
105 					running[pid].occurrences = 0;
106 					add(history);
107 				}else if(match.captures[2] == "exit"){
108 					if(pid !in running)
109 						running[pid] = new shared CommandResult;
110 					running[pid].result = to!int(match.captures[3]);
111 				}
112 			}
113 		}catch(Exception e){
114 			writeln(e);
115 		}
116 	}
117 }