Merge pull request #23710 from eileenmcnaughton/civi_import
[civicrm-core.git] / Civi / Pipe / LineSessionTrait.php
CommitLineData
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
12namespace 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 */
30trait 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}