MonitorContext.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. <?php
  2. /*
  3. * This file is part of the Predis package.
  4. *
  5. * (c) Daniele Alessandri <suppakilla@gmail.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Predis;
  11. /**
  12. * Client-side abstraction of a Redis MONITOR context.
  13. *
  14. * @author Daniele Alessandri <suppakilla@gmail.com>
  15. */
  16. class MonitorContext implements \Iterator
  17. {
  18. private $client;
  19. private $isValid;
  20. private $position;
  21. /**
  22. * @param Client Client instance used by the context.
  23. */
  24. public function __construct(Client $client)
  25. {
  26. $this->checkCapabilities($client);
  27. $this->client = $client;
  28. $this->openContext();
  29. }
  30. /**
  31. * Automatically closes the context when PHP's garbage collector kicks in.
  32. */
  33. public function __destruct()
  34. {
  35. $this->closeContext();
  36. }
  37. /**
  38. * Checks if the passed client instance satisfies the required conditions
  39. * needed to initialize a monitor context.
  40. *
  41. * @param Client Client instance used by the context.
  42. */
  43. private function checkCapabilities(Client $client)
  44. {
  45. if (Helpers::isCluster($client->getConnection())) {
  46. throw new NotSupportedException('Cannot initialize a monitor context over a cluster of connections');
  47. }
  48. if ($client->getProfile()->supportsCommand('monitor') === false) {
  49. throw new NotSupportedException('The current profile does not support the MONITOR command');
  50. }
  51. }
  52. /**
  53. * Initializes the context and sends the MONITOR command to the server.
  54. *
  55. * @param Client Client instance used by the context.
  56. */
  57. protected function openContext()
  58. {
  59. $this->isValid = true;
  60. $monitor = $this->client->createCommand('monitor');
  61. $this->client->executeCommand($monitor);
  62. }
  63. /**
  64. * Closes the context. Internally this is done by disconnecting from server
  65. * since there is no way to terminate the stream initialized by MONITOR.
  66. */
  67. public function closeContext()
  68. {
  69. $this->client->disconnect();
  70. $this->isValid = false;
  71. }
  72. /**
  73. * {@inheritdoc}
  74. */
  75. public function rewind()
  76. {
  77. // NOOP
  78. }
  79. /**
  80. * Returns the last message payload retrieved from the server.
  81. *
  82. * @return Object
  83. */
  84. public function current()
  85. {
  86. return $this->getValue();
  87. }
  88. /**
  89. * {@inheritdoc}
  90. */
  91. public function key()
  92. {
  93. return $this->position;
  94. }
  95. /**
  96. * {@inheritdoc}
  97. */
  98. public function next()
  99. {
  100. $this->position++;
  101. }
  102. /**
  103. * Checks if the the context is still in a valid state to continue.
  104. *
  105. * @return Boolean
  106. */
  107. public function valid()
  108. {
  109. return $this->isValid;
  110. }
  111. /**
  112. * Waits for a new message from the server generated by MONITOR and
  113. * returns it when available.
  114. *
  115. * @return Object
  116. */
  117. private function getValue()
  118. {
  119. $database = 0;
  120. $client = null;
  121. $event = $this->client->getConnection()->read();
  122. $callback = function($matches) use (&$database, &$client) {
  123. if (2 === $count = count($matches)) {
  124. // Redis <= 2.4
  125. $database = (int) $matches[1];
  126. }
  127. if (4 === $count) {
  128. // Redis >= 2.6
  129. $database = (int) $matches[2];
  130. $client = $matches[3];
  131. }
  132. return ' ';
  133. };
  134. $event = preg_replace_callback('/ \(db (\d+)\) | \[(\d+) (.*?)\] /', $callback, $event, 1);
  135. @list($timestamp, $command, $arguments) = explode(' ', $event, 3);
  136. return (object) array(
  137. 'timestamp' => (float) $timestamp,
  138. 'database' => $database,
  139. 'client' => $client,
  140. 'command' => substr($command, 1, -1),
  141. 'arguments' => $arguments,
  142. );
  143. }
  144. }