-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAbstractKernel.hh
More file actions
193 lines (158 loc) · 4.5 KB
/
Copy pathAbstractKernel.hh
File metadata and controls
193 lines (158 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
<?hh // strict
/**
* @copyright 2010-2015, The Titon Project
* @license http://opensource.org/licenses/bsd-license.php
* @link http://titon.io
*/
namespace Titon\Kernel;
use Titon\Event\EmitsEvents;
use Titon\Event\Subject;
use Titon\Kernel\Event\ShutdownEvent;
use Titon\Kernel\Event\StartupEvent;
use Titon\Kernel\Event\TerminateEvent;
use Titon\Kernel\Middleware\Pipeline;
/**
* The AbstractKernel is the base kernel implementation that handles the middleware pipeline process.
* All child kernels must implement the `handle()` method to customize the input and output handling process.
*
* @package Titon\Kernel
*/
abstract class AbstractKernel<Ta as Application, Ti as Input, To as Output> implements Kernel<Ta, Ti, To>, Subject {
use EmitsEvents;
/**
* The current application.
*
* @var \Titon\Kernel\Application
*/
protected Ta $app;
/**
* The CLI exit code to terminate with.
*
* @var int
*/
protected int $exitCode = 0;
/**
* The contextual input object.
*
* @var \Titon\Kernel\Input
*/
protected ?Ti $input;
/**
* The contextual output object.
*
* @var \Titon\Kernel\Output
*/
protected ?To $output;
/**
* Pipeline to manage middleware.
*
* @var \Titon\Kernel\Middleware\Pipeline
*/
protected Pipeline<Ti, To> $pipeline;
/**
* The time the execution started.
*
* @var float
*/
protected float $startTime;
/**
* Instantiate a new application and pipeline.
*
* @param \Titon\Kernel\Application $app
* @param \Titon\Kernel\Middleware\Pipeline $pipeline
*/
public function __construct(Ta $app, ?Pipeline<Ti, To> $pipeline = null) {
if ($pipeline === null) {
$pipeline = new Pipeline();
}
$this->app = $app;
$this->pipeline = $pipeline;
$this->startTime = microtime(true);
}
/**
* {@inheritdoc}
*/
public function getApplication(): Ta {
return $this->app;
}
/**
* Return the total time it took to execute up to this point.
*
* @return float
*/
public function getExecutionTime(): float {
return microtime(true) - $this->getStartTime();
}
/**
* {@inheritdoc}
*/
public function getInput(): ?Ti {
return $this->input;
}
/**
* {@inheritdoc}
*/
public function getOutput(): ?To {
return $this->output;
}
/**
* Return the execution start time.
*
* @return float
*/
public function getStartTime(): float {
return $this->startTime;
}
/**
* {@inheritdoc}
*/
public function pipe(Middleware<Ti, To> $middleware): this {
$this->pipeline->through($middleware);
return $this;
}
/**
* {@inheritdoc}
*/
final public function run(Ti $input, To $output): To {
$this->input = $input;
$this->output = $output;
// Emit startup events
$this->startup();
// Since the kernel itself is middleware, add the kernel as the last item in the pipeline.
// This allows the `handle()` method to be ran after all other middleware.
$this->pipe($this);
// Handle the middleware pipeline stack
$this->output = $output = $this->pipeline->handle($input, $output);
// Emit shutdown events
$this->shutdown();
return $output;
}
/**
* {@inheritdoc}
*/
public function terminate(): void {
$input = $this->getInput();
$output = $this->getOutput();
invariant($input !== null && $output !== null, 'Input and Output must not be null.');
$this->emit(new TerminateEvent($this, $input, $output));
exit($this->exitCode);
}
/**
* Triggered after the pipeline is handled but before the output is sent.
*/
protected function shutdown(): void {
$input = $this->getInput();
$output = $this->getOutput();
invariant($input !== null && $output !== null, 'Input and Output must not be null.');
$this->emit(new ShutdownEvent($this, $input, $output));
}
/**
* Triggered before the pipeline is handled.
*/
protected function startup(): void {
$input = $this->getInput();
$output = $this->getOutput();
invariant($input !== null && $output !== null, 'Input and Output must not be null.');
$this->emit(new StartupEvent($this, $input, $output));
}
}