70 public function mount( $prefix, $instance ) {
71 if ( !preg_match( self::VALID_MOUNT_REGEX, $prefix ) ) {
72 throw new UnexpectedValueException(
"Invalid service mount point '$prefix'." );
73 } elseif ( isset( $this->instances[$prefix] ) ) {
74 throw new UnexpectedValueException(
"A service is already mounted on '$prefix'." );
77 if ( !isset( $instance[
'class'] ) || !isset( $instance[
'config'] ) ) {
78 throw new UnexpectedValueException(
"Missing 'class' or 'config' ('$prefix')." );
81 $this->instances[$prefix] = $instance;
164 foreach ( $reqs as $index => &$req ) {
165 if ( isset( $req[0] ) ) {
166 $req[
'method'] = $req[0];
169 if ( isset( $req[1] ) ) {
170 $req[
'url'] = $req[1];
178 $armoredIndexMap = [];
182 $replaceReqsByService = [];
185 foreach ( $reqs as $origIndex => $req ) {
187 $index = $curUniqueId++;
188 $armoredIndexMap[$origIndex] = $index;
189 $origPending[$index] = 1;
190 if ( preg_match(
'#^(http|ftp)s?://#', $req[
'url'] ) ) {
192 $executeReqs[$index] = $req;
197 throw new UnexpectedValueException(
"Path '{$req['url']}' has no service." );
200 $req[
'url'] = substr( $req[
'url'], strlen( $prefix ) );
201 $replaceReqsByService[$prefix][$index] = $req;
206 $idFunc =
static function () use ( &$curUniqueId ) {
207 return $curUniqueId++;
212 if ( ++$rounds > 5 ) {
213 throw new Exception(
"Too many replacement rounds detected. Aborting." );
217 $checkReqIndexesByPrefix = [];
222 $newReplaceReqsByService = [];
223 foreach ( $replaceReqsByService as $prefix => $servReqs ) {
224 $service = $this->getInstance( $prefix );
225 foreach ( $service->onRequests( $servReqs, $idFunc ) as $index => $req ) {
227 if ( isset( $servReqs[$index] ) || isset( $origPending[$index] ) ) {
231 $newReplaceReqsByService[$prefix][$index] = $req;
233 if ( isset( $req[
'response'] ) ) {
235 unset( $executeReqs[$index] );
236 unset( $origPending[$index] );
237 $doneReqs[$index] = $req;
240 $executeReqs[$index] = $req;
242 $checkReqIndexesByPrefix[$prefix][$index] = 1;
249 foreach ( $executeReqs as $index => &$req ) {
251 if ( preg_match(
'#^//#', $req[
'url'] ) ) {
260 isset( $req[
'reqTimeout'] ) &&
261 ( !isset( $opts[
'reqTimeout'] ) ||
262 $req[
'reqTimeout'] < $opts[
'reqTimeout'] )
264 $opts[
'reqTimeout'] = $req[
'reqTimeout'];
269 foreach ( $this->http->runMulti( $executeReqs, $opts ) as $index => $ranReq ) {
270 $doneReqs[$index] = $ranReq;
271 unset( $origPending[$index] );
279 $newReplaceReqsByService = [];
280 foreach ( $checkReqIndexesByPrefix as $prefix => $servReqIndexes ) {
281 $service = $this->getInstance( $prefix );
283 $servReqs = array_intersect_key( $doneReqs, $servReqIndexes );
284 foreach ( $service->onResponses( $servReqs, $idFunc ) as $index => $req ) {
286 if ( isset( $servReqs[$index] ) || isset( $origPending[$index] ) ) {
290 $newReplaceReqsByService[$prefix][$index] = $req;
292 if ( isset( $req[
'response'] ) ) {
294 unset( $origPending[$index] );
295 $doneReqs[$index] = $req;
298 $executeReqs[$index] = $req;
303 $replaceReqsByService = $newReplaceReqsByService;
304 }
while ( count( $origPending ) );
309 foreach ( $reqs as $origIndex => $req ) {
310 $index = $armoredIndexMap[$origIndex];
311 if ( !isset( $doneReqs[$index] ) ) {
312 throw new UnexpectedValueException(
"Response for request '$index' is NULL." );
314 $responses[$origIndex] = $doneReqs[$index][
'response'];