MonitorContext.php 3.7 KB

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