/** * Retrieve the sevice URI for the device hosting this repository. * * See @{method:newConduitClient} for a general discussion of interacting * with repository services. This method provides lower-level resolution of * services, returning raw URIs. * * @param PhabricatorUser Viewing user. * @param bool `true` to throw if a remote URI would be returned. * @param list<string> List of allowable protocols. * @return string|null URI, or `null` for local repositories. */ public function getAlmanacServiceURI(PhabricatorUser $viewer, $never_proxy, array $protocols) { $service_phid = $this->getAlmanacServicePHID(); if (!$service_phid) { // No service, so this is a local repository. return null; } $service = id(new AlmanacServiceQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPHIDs(array($service_phid))->needBindings(true)->executeOne(); if (!$service) { throw new Exception(pht('The Almanac service for this repository is invalid or could not ' . 'be loaded.')); } $service_type = $service->getServiceType(); if (!$service_type instanceof AlmanacClusterRepositoryServiceType) { throw new Exception(pht('The Almanac service for this repository does not have the correct ' . 'service type.')); } $bindings = $service->getBindings(); if (!$bindings) { throw new Exception(pht('The Almanac service for this repository is not bound to any ' . 'interfaces.')); } $local_device = AlmanacKeys::getDeviceID(); if ($never_proxy && !$local_device) { throw new Exception(pht('Unable to handle proxied service request. This device is not ' . 'registered, so it can not identify local services. Register ' . 'this device before sending requests here.')); } $protocol_map = array_fuse($protocols); $uris = array(); foreach ($bindings as $binding) { $iface = $binding->getInterface(); // If we're never proxying this and it's locally satisfiable, return // `null` to tell the caller to handle it locally. If we're allowed to // proxy, we skip this check and may proxy the request to ourselves. // (That proxied request will end up here with proxying forbidden, // return `null`, and then the request will actually run.) if ($local_device && $never_proxy) { if ($iface->getDevice()->getName() == $local_device) { return null; } } $protocol = $binding->getAlmanacPropertyValue('protocol'); if ($protocol === null) { $protocol = 'https'; } if (empty($protocol_map[$protocol])) { continue; } $uris[] = $protocol . '://' . $iface->renderDisplayAddress() . '/'; } if (!$uris) { throw new Exception(pht('The Almanac service for this repository is not bound to any ' . 'interfaces which support the required protocols (%s).', implode(', ', $protocols))); } if ($never_proxy) { throw new Exception(pht('Refusing to proxy a repository request from a cluster host. ' . 'Cluster hosts must correctly route their intracluster requests.')); } shuffle($uris); return head($uris); }
/** * Retrieve the sevice URI for the device hosting this repository. * * See @{method:newConduitClient} for a general discussion of interacting * with repository services. This method provides lower-level resolution of * services, returning raw URIs. * * @param PhabricatorUser Viewing user. * @param bool `true` to throw if a remote URI would be returned. * @param list<string> List of allowable protocols. * @return string|null URI, or `null` for local repositories. */ public function getAlmanacServiceURI(PhabricatorUser $viewer, $never_proxy, array $protocols) { $service = $this->loadAlmanacService(); if (!$service) { return null; } $bindings = $service->getActiveBindings(); if (!$bindings) { throw new Exception(pht('The Almanac service for this repository is not bound to any ' . 'interfaces.')); } $local_device = AlmanacKeys::getDeviceID(); if ($never_proxy && !$local_device) { throw new Exception(pht('Unable to handle proxied service request. This device is not ' . 'registered, so it can not identify local services. Register ' . 'this device before sending requests here.')); } $protocol_map = array_fuse($protocols); $uris = array(); foreach ($bindings as $binding) { $iface = $binding->getInterface(); // If we're never proxying this and it's locally satisfiable, return // `null` to tell the caller to handle it locally. If we're allowed to // proxy, we skip this check and may proxy the request to ourselves. // (That proxied request will end up here with proxying forbidden, // return `null`, and then the request will actually run.) if ($local_device && $never_proxy) { if ($iface->getDevice()->getName() == $local_device) { return null; } } $uri = $this->getClusterRepositoryURIFromBinding($binding); $protocol = $uri->getProtocol(); if (empty($protocol_map[$protocol])) { continue; } $uris[] = $uri; } if (!$uris) { throw new Exception(pht('The Almanac service for this repository is not bound to any ' . 'interfaces which support the required protocols (%s).', implode(', ', $protocols))); } if ($never_proxy) { throw new Exception(pht('Refusing to proxy a repository request from a cluster host. ' . 'Cluster hosts must correctly route their intracluster requests.')); } shuffle($uris); return head($uris); }