EndpointCache.php 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. <?php
  2. namespace AsyncAws\Core\EndpointDiscovery;
  3. use AsyncAws\Core\Exception\LogicException;
  4. /**
  5. * @author Jérémy Derussé <jeremy@derusse.com>
  6. *
  7. * @internal
  8. */
  9. class EndpointCache
  10. {
  11. private $endpoints = [];
  12. private $expired = [];
  13. public function addEndpoints(?string $region, array $endpoints): void
  14. {
  15. $now = time();
  16. if (null === $region) {
  17. $region = '';
  18. }
  19. if (!isset($this->endpoints[$region])) {
  20. $this->endpoints[$region] = [];
  21. }
  22. /** @var EndpointInterface $endpoint */
  23. foreach ($endpoints as $endpoint) {
  24. $this->endpoints[$region][$this->sanitizeEndpoint($endpoint->getAddress())] = $now + ($endpoint->getCachePeriodInMinutes() * 60);
  25. }
  26. arsort($this->endpoints[$region]);
  27. }
  28. public function removeEndpoint(string $endpoint): void
  29. {
  30. $endpoint = $this->sanitizeEndpoint($endpoint);
  31. foreach ($this->endpoints as &$endpoints) {
  32. unset($endpoints[$endpoint]);
  33. }
  34. unset($endpoints);
  35. foreach ($this->expired as &$endpoints) {
  36. unset($endpoints[$endpoint]);
  37. }
  38. unset($endpoints);
  39. }
  40. public function getActiveEndpoint(?string $region): ?string
  41. {
  42. if (null === $region) {
  43. $region = '';
  44. }
  45. $now = time();
  46. foreach ($this->endpoints[$region] ?? [] as $endpoint => $expiresAt) {
  47. if ($expiresAt < $now) {
  48. $this->expired[$region] = \array_slice($this->expired[$region] ?? [], -100); // keep only the last 100 items
  49. unset($this->endpoints[$region][$endpoint]);
  50. $this->expired[$region][$endpoint] = $expiresAt;
  51. continue;
  52. }
  53. return $endpoint;
  54. }
  55. return null;
  56. }
  57. public function getExpiredEndpoint(?string $region): ?string
  58. {
  59. if (null === $region) {
  60. $region = '';
  61. }
  62. if (empty($this->expired[$region])) {
  63. return null;
  64. }
  65. return array_key_last($this->expired[$region]);
  66. }
  67. private function sanitizeEndpoint(string $address): string
  68. {
  69. $parsed = parse_url($address);
  70. // parse_url() will correctly parse full URIs with schemes
  71. if (isset($parsed['host'])) {
  72. return rtrim(sprintf(
  73. '%s://%s/%s',
  74. $parsed['scheme'] ?? 'https',
  75. $parsed['host'],
  76. ltrim($parsed['path'] ?? '/', '/')
  77. ), '/');
  78. }
  79. // parse_url() will put host & path in 'path' if scheme is not provided
  80. if (isset($parsed['path'])) {
  81. $split = explode('/', $parsed['path'], 2);
  82. $parsed['host'] = $split[0];
  83. if (isset($split[1])) {
  84. $parsed['path'] = $split[1];
  85. } else {
  86. $parsed['path'] = '';
  87. }
  88. return rtrim(sprintf(
  89. '%s://%s/%s',
  90. $parsed['scheme'] ?? 'https',
  91. $parsed['host'],
  92. ltrim($parsed['path'], '/')
  93. ), '/');
  94. }
  95. throw new LogicException(sprintf('The supplied endpoint "%s" is invalid.', $address));
  96. }
  97. }