/**
  * 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);
 }
Ejemplo n.º 2
0
 /**
  * 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);
 }