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;
90 if ( !preg_match( self::VALID_MOUNT_REGEX, $prefix ) ) {
91 throw new UnexpectedValueException(
"Invalid service mount point '$prefix'." );
92 } elseif ( !isset( $this->instances[$prefix] ) ) {
93 throw new UnexpectedValueException(
"No service is mounted on '$prefix'." );
95 unset( $this->instances[$prefix] );
105 $cmpFunc =
function ( $a, $b ) {
106 $al = substr_count( $a,
'/' );
107 $bl = substr_count( $b,
'/' );
111 return ( $al < $bl ) ? 1 : -1;
115 foreach ( $this->instances
as $prefix => $unused ) {
116 if ( strpos(
$path, $prefix ) === 0 ) {
145 return $this->
runMulti( [ $req ] )[0];
167 foreach ( $reqs
as $index => &
$req ) {
168 if ( isset(
$req[0] ) ) {
172 if ( isset(
$req[1] ) ) {
181 $armoredIndexMap = [];
185 $replaceReqsByService = [];
188 foreach ( $reqs
as $origIndex =>
$req ) {
190 $index = $curUniqueId++;
191 $armoredIndexMap[$origIndex] = $index;
192 $origPending[$index] = 1;
193 if ( preg_match(
'#^(http|ftp)s?://#',
$req[
'url'] ) ) {
195 $executeReqs[$index] =
$req;
200 throw new UnexpectedValueException(
"Path '{$req['url']}' has no service." );
203 $req[
'url'] = substr(
$req[
'url'], strlen( $prefix ) );
204 $replaceReqsByService[$prefix][$index] =
$req;
209 $idFunc =
function ()
use ( &$curUniqueId ) {
210 return $curUniqueId++;
215 if ( ++$rounds > 5 ) {
216 throw new Exception(
"Too many replacement rounds detected. Aborting." );
220 $checkReqIndexesByPrefix = [];
225 $newReplaceReqsByService = [];
226 foreach ( $replaceReqsByService
as $prefix => $servReqs ) {
228 foreach ( $service->onRequests( $servReqs, $idFunc )
as $index =>
$req ) {
230 if ( isset( $servReqs[$index] ) || isset( $origPending[$index] ) ) {
234 $newReplaceReqsByService[$prefix][$index] =
$req;
236 if ( isset(
$req[
'response'] ) ) {
238 unset( $executeReqs[$index] );
239 unset( $origPending[$index] );
240 $doneReqs[$index] =
$req;
243 $executeReqs[$index] =
$req;
245 $checkReqIndexesByPrefix[$prefix][$index] = 1;
249 foreach ( $this->
http->runMulti( $executeReqs )
as $index => $ranReq ) {
250 $doneReqs[$index] = $ranReq;
251 unset( $origPending[$index] );
259 $newReplaceReqsByService = [];
260 foreach ( $checkReqIndexesByPrefix
as $prefix => $servReqIndexes ) {
263 $servReqs = array_intersect_key( $doneReqs, $servReqIndexes );
264 foreach ( $service->onResponses( $servReqs, $idFunc )
as $index =>
$req ) {
266 if ( isset( $servReqs[$index] ) || isset( $origPending[$index] ) ) {
270 $newReplaceReqsByService[$prefix][$index] =
$req;
272 if ( isset(
$req[
'response'] ) ) {
274 unset( $origPending[$index] );
275 $doneReqs[$index] =
$req;
278 $executeReqs[$index] =
$req;
283 $replaceReqsByService = $newReplaceReqsByService;
284 }
while (
count( $origPending ) );
289 foreach ( $reqs
as $origIndex =>
$req ) {
290 $index = $armoredIndexMap[$origIndex];
291 if ( !isset( $doneReqs[$index] ) ) {
292 throw new UnexpectedValueException(
"Response for request '$index' is NULL." );
294 $responses[$origIndex] = $doneReqs[$index][
'response'];
305 if ( !isset( $this->instances[$prefix] ) ) {
306 throw new RuntimeException(
"No service registered at prefix '{$prefix}'." );
310 $config = $this->instances[$prefix][
'config'];
311 $class = $this->instances[$prefix][
'class'];
312 $service =
new $class( $config );
314 throw new UnexpectedValueException(
"Registered service has the wrong class." );
316 $this->instances[$prefix] = $service;
319 return $this->instances[$prefix];