Commit | Line | Data |
---|---|---|
b4454468 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
4 | | Copyright CiviCRM LLC. All rights reserved. | | |
5 | | | | |
6 | | This work is published under the GNU AGPLv3 license with some | | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
9 | +--------------------------------------------------------------------+ | |
10 | */ | |
11 | ||
12 | namespace Civi\Pipe; | |
13 | ||
14 | /** | |
15 | * Synchronous line-oriented communication session. | |
16 | * | |
17 | * @code | |
18 | * $session = new class { | |
19 | * use LineSessionTrait; | |
20 | * protected function onRequest(string $requestLine): ?string { | |
eaa0d7ac | 21 | * return 'Thanks'; |
b4454468 TO |
22 | * } |
23 | * protected function onException(string $requestLine, \Throwable $t): ?string { | |
eaa0d7ac | 24 | * return 'Oops'; |
b4454468 TO |
25 | * } |
26 | * } | |
27 | * $session->setIO(STDIN, STDOUT)->run(); | |
28 | * @endCode | |
29 | */ | |
30 | trait LineSessionTrait { | |
31 | ||
32 | /** | |
33 | * The onConnect() method is called when a new session is opened. | |
34 | * | |
88d93265 TO |
35 | * @param string $negotiationFlags |
36 | * List of pipe initialization flags. See Civi::pipe() for description of flags. | |
b4454468 TO |
37 | * @return string|null |
38 | * Header/welcome line, or NULL if none. | |
88d93265 | 39 | * @see Civi::pipe |
b4454468 | 40 | */ |
88d93265 | 41 | protected function onConnect(string $negotiationFlags): ?string { |
b4454468 TO |
42 | return NULL; |
43 | } | |
44 | ||
45 | /** | |
46 | * The onRequest() method is called after receiving one line of text. | |
47 | * | |
48 | * @param string $requestLine | |
49 | * The received line of text. | |
50 | * @return string|null | |
51 | * The line to send back, or NULL if none. | |
52 | */ | |
53 | abstract protected function onRequest(string $requestLine): ?string; | |
54 | ||
55 | /** | |
56 | * The onRequest() method is called after receiving one line of text. | |
57 | * | |
58 | * @param string $requestLine | |
59 | * The received line of text - which led to the unhandled exception. | |
60 | * @param \Throwable $t | |
61 | * The unhandled exception. | |
62 | * @return string|null | |
63 | * The line to send back, or NULL if none. | |
64 | */ | |
65 | abstract protected function onException(string $requestLine, \Throwable $t): ?string; | |
66 | ||
67 | /** | |
68 | * @var resource | |
69 | * Ex: STDIN | |
70 | */ | |
71 | protected $input; | |
72 | ||
73 | /** | |
74 | * @var resource | |
75 | * Ex: STDOUT | |
76 | */ | |
77 | protected $output; | |
78 | ||
79 | /** | |
80 | * Line-delimiter. | |
81 | * | |
82 | * @var string | |
83 | */ | |
84 | protected $delimiter = "\n"; | |
85 | ||
86 | /** | |
87 | * Maximum size of the buffer for reading lines. | |
88 | * | |
89 | * Clients may need to set this if they submit large requests. | |
90 | * | |
91 | * @var int | |
92 | */ | |
9aa53a5d | 93 | protected $bufferSize = 524288; |
b4454468 TO |
94 | |
95 | /** | |
96 | * A value to display immediately before the response lines. | |
97 | * | |
98 | * Clients may set this is if they want to detect and skip buggy noise. | |
99 | * | |
100 | * @var string|null | |
101 | * Ex: chr(1).chr(1) | |
102 | */ | |
103 | protected $responsePrefix = NULL; | |
104 | ||
105 | /** | |
106 | * @param resource|null $input | |
107 | * @param resource|null $output | |
108 | */ | |
109 | public function __construct($input = NULL, $output = NULL) { | |
110 | $this->input = $input; | |
111 | $this->output = $output; | |
112 | } | |
113 | ||
114 | /** | |
115 | * Run the main loop. Poll for commands on $input and write responses to $output. | |
88d93265 TO |
116 | * |
117 | * @param string $negotiationFlags | |
118 | * List of pipe initialization flags. See Civi::pipe() for description of flags. | |
b4454468 | 119 | */ |
88d93265 TO |
120 | public function run(string $negotiationFlags = '') { |
121 | $this->write($this->onConnect($negotiationFlags)); | |
b4454468 | 122 | |
9aa53a5d | 123 | while (FALSE !== ($line = stream_get_line($this->input, $this->bufferSize, $this->delimiter))) { |
b4454468 TO |
124 | $line = rtrim($line, $this->delimiter); |
125 | if (empty($line)) { | |
126 | continue; | |
127 | } | |
128 | ||
129 | try { | |
130 | $response = $this->onRequest($line); | |
131 | } | |
132 | catch (\Throwable $t) { | |
133 | $response = $this->onException($line, $t); | |
134 | } | |
135 | $this->write($response); | |
136 | } | |
137 | } | |
138 | ||
139 | /** | |
140 | * @return int | |
141 | */ | |
9aa53a5d TO |
142 | public function getBufferSize(): int { |
143 | return $this->bufferSize; | |
b4454468 TO |
144 | } |
145 | ||
146 | /** | |
9aa53a5d | 147 | * @param int $bufferSize |
b4454468 TO |
148 | * @return $this |
149 | */ | |
9aa53a5d TO |
150 | public function setBufferSize(int $bufferSize) { |
151 | $this->bufferSize = $bufferSize; | |
b4454468 TO |
152 | return $this; |
153 | } | |
154 | ||
155 | /** | |
156 | * @return string|null | |
157 | */ | |
158 | public function getResponsePrefix(): ?string { | |
159 | return $this->responsePrefix; | |
160 | } | |
161 | ||
162 | /** | |
163 | * @param string|null $responsePrefix | |
164 | * @return $this | |
165 | */ | |
166 | public function setResponsePrefix(?string $responsePrefix) { | |
167 | $this->responsePrefix = $responsePrefix; | |
168 | return $this; | |
169 | } | |
170 | ||
171 | /** | |
172 | * @param resource $input | |
173 | * @param resource $output | |
174 | * @return $this | |
175 | */ | |
176 | public function setIO($input, $output) { | |
177 | $this->input = $input; | |
178 | $this->output = $output; | |
179 | return $this; | |
180 | } | |
181 | ||
182 | protected function write(?string $response): void { | |
183 | if ($response === NULL) { | |
184 | return; | |
185 | } | |
186 | if ($this->responsePrefix !== NULL) { | |
187 | fwrite($this->output, $this->responsePrefix); | |
188 | } | |
189 | fwrite($this->output, $response); | |
190 | fwrite($this->output, $this->delimiter); | |
191 | } | |
192 | ||
193 | } |