Example #1
0
 /**
  * Run the watcher.
  *
  * Listenable events:
  *     • new, when a file is new, i.e. found by the finder;
  *     • modify, when a file has been modified;
  *     • move, when a file has moved, i.e. no longer found by the finder.
  *
  * @return  void
  */
 public function run()
 {
     $iterator = $this->getIterator();
     $previous = iterator_to_array($iterator);
     $current = $previous;
     while (true) {
         foreach ($current as $name => $c) {
             if (!isset($previous[$name])) {
                 $this->_on->fire('new', new Core\Event\Bucket(['file' => $c]));
                 continue;
             }
             if (null === $c->getHash()) {
                 unset($current[$name]);
                 continue;
             }
             if ($previous[$name]->getHash() != $c->getHash()) {
                 $this->_on->fire('modify', new Core\Event\Bucket(['file' => $c]));
             }
             unset($previous[$name]);
         }
         foreach ($previous as $p) {
             $this->_on->fire('move', new Core\Event\Bucket(['file' => $p]));
         }
         usleep($this->getLatency() * 1000000);
         $previous = $current;
         $current = iterator_to_array($iterator);
     }
     return;
 }
Example #2
0
 /**
  * Run the server.
  *
  * @return  void
  */
 public function run()
 {
     $this->_server->considerRemoteAddress(true);
     $this->_server->connectAndWait();
     while (true) {
         $buffer = $this->_server->read(1024);
         if (empty($buffer)) {
             continue;
         }
         // Skip header.
         $handle = substr($buffer, 12);
         $domain = null;
         // QNAME.
         for ($i = 0, $m = strlen($handle); $i < $m; ++$i) {
             if (0 === ($length = ord($handle[$i]))) {
                 break;
             }
             if (null !== $domain) {
                 $domain .= '.';
             }
             $domain .= substr($handle, $i + 1, $length);
             $i += $length;
         }
         // QTYPE.
         $i += 2;
         $qtype = (int) (string) ord($handle[$i]) + (int) (string) ord($handle[$i + 1]);
         $type = array_search($qtype, static::$_types) ?: $qtype;
         // QCLASS.
         $i += 2;
         $qclass = (int) (string) ord($handle[$i]);
         $class = array_search($qclass, static::$_classes) ?: $qclass;
         $ips = $this->_on->fire('query', new Core\Event\Bucket(['domain' => $domain, 'type' => $type, 'class' => $class]));
         $ip = null;
         if (false === $ips[0]) {
             $this->_server->writeAll($buffer[0] . $buffer[1] . pack('C', 1 << 7 | 1) . pack('C', 0 | 3) . pack('n', 0) . pack('n', 0) . pack('n', 0) . pack('n', 0));
             continue;
         }
         foreach (explode('.', $ips[0]) as $foo) {
             $ip .= pack('C', $foo);
         }
         $this->_server->writeAll($buffer[0] . $buffer[1] . pack('C', 1 << 7 | 1) . pack('C', 0) . $buffer[4] . $buffer[5] . pack('n', 1) . pack('n', 0) . pack('n', 0) . $handle . pack('CC', 192, 12) . pack('n', $qtype) . pack('n', $qclass) . pack('N', 60) . pack('n', 4) . $ip);
     }
     $this->_server->disconnect();
     return;
 }
Example #3
0
 /**
  * Attach a callable to a listenable component.
  *
  * @param   string  $listenerId    Listener ID.
  * @param   mixed   $callable      Callable.
  * @return  \Hoa\Core\Event\Listenable
  * @throws  \Hoa\Core\Exception
  */
 public function on($listenerId, $callable)
 {
     $this->_on->attach($listenerId, $callable);
     return $this;
 }
Example #4
0
 /**
  * Run a node.
  *
  * @param   \Hoa\Socket\Node  $node    Node.
  * @return  void
  * @throws  \Hoa\Irc\Exception
  */
 protected function _run(Socket\Node $node)
 {
     if (false === $node->hasJoined()) {
         $node->setJoined(true);
         $this->_on->fire('open', new Core\Event\Bucket());
         return;
     }
     try {
         $line = $node->getConnection()->readLine();
         preg_match('#^(?::(?<prefix>[^\\s]+)\\s+)?(?<command>[^\\s]+)\\s+(?<middle>[^:]+)?(:\\s*(?<trailing>.+))?$#', $line, $matches);
         if (!isset($matches['command'])) {
             $matches['command'] = null;
         }
         switch ($matches['command']) {
             case 366:
                 // RPL_ENDOFNAMES
                 list($nickname, $channel) = explode(' ', $matches['middle'], 2);
                 $node->setChannel($channel);
                 $listener = 'join';
                 $bucket = ['nickname' => $nickname, 'channel' => trim($channel)];
                 break;
             case 433:
                 // ERR_NICKNAMEINUSE
                 throw new Exception('Nickname %s is already in use.', 0, $node->getUsername());
             case 'PRIVMSG':
                 $middle = trim($matches['middle']);
                 $message = $matches['trailing'];
                 $username = $node->getUsername();
                 if ($username === $middle) {
                     $listener = 'private-message';
                 } elseif (false !== strpos($message, $username)) {
                     $node->setChannel($middle);
                     $listener = 'mention';
                 } else {
                     $node->setChannel($middle);
                     $listener = 'message';
                 }
                 $bucket = ['from' => $this->parseNick($matches['prefix']), 'message' => $message];
                 break;
             case 'PING':
                 $daemons = explode(' ', $matches['trailing']);
                 $listener = 'ping';
                 $bucket = ['daemons' => $daemons];
                 if (isset($daemons[1])) {
                     $this->pong($daemons[0], $daemons[1]);
                 } else {
                     $this->pong($daemons[0]);
                 }
                 break;
             case 'KICK':
                 list($channel, ) = explode(' ', $matches['middle'], 2);
                 $node->setChannel($channel);
                 $listener = 'kick';
                 $bucket = ['from' => $this->parseNick($matches['prefix']), 'channel' => trim($channel)];
                 break;
             case 'INVITE':
                 list($channel, ) = explode(' ', $matches['middle'], 2);
                 $node->setChannel($channel);
                 $listener = 'invite';
                 $bucket = ['from' => $this->parseNick($matches['prefix']), 'channel' => trim($channel), 'invitation_channel' => trim($matches['trailing'])];
                 break;
             default:
                 $listener = 'other-message';
                 $bucket = ['line' => $line, 'parsed_line' => $matches];
         }
         $this->_on->fire($listener, new Core\Event\Bucket($bucket));
     } catch (Core\Exception\Idle $e) {
         $this->_on->fire('error', new Core\Event\Bucket(['exception' => $e]));
     }
     return;
 }
Example #5
0
 /**
  * Notification callback.
  *
  * @param   int     $ncode          Notification code. Please, see
  *                                  STREAM_NOTIFY_* constants.
  * @param   int     $severity       Severity. Please, see
  *                                  STREAM_NOTIFY_SEVERITY_* constants.
  * @param   string  $message        Message.
  * @param   int     $code           Message code.
  * @param   int     $transferred    If applicable, the number of transferred
  *                                  bytes.
  * @param   int     $max            If applicable, the number of max bytes.
  * @return  void
  */
 public function _notify($ncode, $severity, $message, $code, $transferred, $max)
 {
     static $_map = [STREAM_NOTIFY_AUTH_REQUIRED => 'authrequire', STREAM_NOTIFY_AUTH_RESULT => 'authresult', STREAM_NOTIFY_COMPLETED => 'complete', STREAM_NOTIFY_CONNECT => 'connect', STREAM_NOTIFY_FAILURE => 'failure', STREAM_NOTIFY_MIME_TYPE_IS => 'mimetype', STREAM_NOTIFY_PROGRESS => 'progress', STREAM_NOTIFY_REDIRECTED => 'redirect', STREAM_NOTIFY_RESOLVE => 'resolve', STREAM_NOTIFY_FILE_SIZE_IS => 'size'];
     $this->_on->fire($_map[$ncode], new Core\Event\Bucket(['code' => $code, 'severity' => $severity, 'message' => $message, 'code' => $code, 'transferred' => $transferred, 'max' => $max]));
     return;
 }
Example #6
0
 /**
  * Run the shared worker.
  * It creates a zombie with \Hoa\Zombie.
  *
  * @return  void
  * @throws  \Hoa\Worker\Backend\Exception
  */
 public function run()
 {
     $server = new Socket\Server($this->_socket);
     $server->connectAndWait();
     Zombie::fork();
     $_eom = pack('C', 0);
     while (true) {
         foreach ($server->select() as $node) {
             $request = unpack('nr', $server->read(2));
             $length = unpack('Nl', $server->read(4));
             $message = unserialize($server->read($length['l']));
             $eom = unpack('Ce', $server->read(1));
             if ($eom['e'] != $_eom) {
                 $server->disconnect();
                 continue;
             }
             switch ($request['r']) {
                 case static::TYPE_MESSAGE:
                     $this->_on->fire('message', new Core\Event\Bucket(['message' => $message]));
                     ++$this->_messages;
                     $this->_lastMessage = time();
                     break;
                 case static::TYPE_STOP:
                     if ($this->_password === $message) {
                         $server->disconnect();
                         break 3;
                     }
                     break;
                 case static::TYPE_INFORMATION:
                     $message = ['id' => $this->_wid, 'socket' => $this->_socket, 'start' => $this->_startTime, 'pid' => getmypid(), 'memory' => memory_get_usage(true), 'memory_allocated' => memory_get_usage(), 'memory_peak' => memory_get_peak_usage(true), 'memory_allocated_peak' => memory_get_usage(), 'messages' => $this->_messages, 'last_message' => $this->_lastMessage, 'filename' => $_SERVER['SCRIPT_FILENAME']];
                     $server->writeAll(static::pack(static::TYPE_MESSAGE, $message));
                     break;
             }
             $server->disconnect();
         }
     }
     $server->disconnect();
     if (null !== $this->_wid) {
         Worker\Run::unregister($this->_wid);
     }
     return;
 }
 /**
  * Run a node.
  *
  * @param   \Hoa\Socket\Node  $node    Node.
  * @return  void
  */
 protected function _run(Socket\Node $node)
 {
     try {
         if (FAILED === $node->getHandshake()) {
             $this->doHandshake();
             $this->_on->fire('open', new Core\Event\Bucket());
             return;
         }
         try {
             $frame = $node->getProtocolImplementation()->readFrame();
         } catch (Exception\CloseError $e) {
             $this->close($e->getErrorCode(), $e->getMessage());
             return;
         }
         if (false === $frame) {
             return;
         }
         if ($this instanceof Server && isset($frame['mask']) && 0x0 === $frame['mask']) {
             $this->close(self::CLOSE_MESSAGE_ERROR, 'All messages from the client must be masked.');
             return;
         }
         $fromText = false;
         $fromBinary = false;
         switch ($frame['opcode']) {
             case self::OPCODE_BINARY_FRAME:
                 $fromBinary = true;
             case self::OPCODE_TEXT_FRAME:
                 if (0x1 === $frame['fin']) {
                     if (0 < $node->getNumberOfFragments()) {
                         $this->close(self::CLOSE_PROTOCOL_ERROR);
                         break;
                     }
                     if (true === $fromBinary) {
                         $fromBinary = false;
                         $this->_on->fire('binary-message', new Core\Event\Bucket(['message' => $frame['message']]));
                         break;
                     }
                     if (false === (bool) preg_match('//u', $frame['message'])) {
                         $this->close(self::CLOSE_MESSAGE_ERROR);
                         break;
                     }
                     $this->_on->fire('message', new Core\Event\Bucket(['message' => $frame['message']]));
                     break;
                 } else {
                     $node->setComplete(false);
                 }
                 $fromText = true;
             case self::OPCODE_CONTINUATION_FRAME:
                 if (false === $fromText) {
                     if (0 === $node->getNumberOfFragments()) {
                         $this->close(self::CLOSE_PROTOCOL_ERROR);
                         break;
                     }
                 } else {
                     $fromText = false;
                     if (true === $fromBinary) {
                         $node->setBinary(true);
                         $fromBinary = false;
                     }
                 }
                 $node->appendMessageFragment($frame['message']);
                 if (0x1 === $frame['fin']) {
                     $message = $node->getFragmentedMessage();
                     $isBinary = $node->isBinary();
                     $node->clearFragmentation();
                     if (true === $isBinary) {
                         $this->_on->fire('binary-message', new Core\Event\Bucket(['message' => $message]));
                         break;
                     }
                     if (false === (bool) preg_match('//u', $message)) {
                         $this->close(self::CLOSE_MESSAGE_ERROR);
                         break;
                     }
                     $this->_on->fire('message', new Core\Event\Bucket(['message' => $message]));
                 } else {
                     $node->setComplete(false);
                 }
                 break;
             case self::OPCODE_PING:
                 $message =& $frame['message'];
                 if (0x0 === $frame['fin'] || 0x7d < $frame['length']) {
                     $this->close(self::CLOSE_PROTOCOL_ERROR);
                     break;
                 }
                 $node->getProtocolImplementation()->writeFrame($message, self::OPCODE_PONG, true);
                 $this->_on->fire('ping', new Core\Event\Bucket(['message' => $message]));
                 break;
             case self::OPCODE_PONG:
                 if (0 === $frame['fin']) {
                     $this->close(self::CLOSE_PROTOCOL_ERROR);
                     break;
                 }
                 break;
             case self::OPCODE_CONNECTION_CLOSE:
                 $length =& $frame['length'];
                 if (1 === $length || 0x7d < $length) {
                     $this->close(self::CLOSE_PROTOCOL_ERROR);
                     break;
                 }
                 $code = self::CLOSE_NORMAL;
                 $reason = null;
                 if (0 < $length) {
                     $message =& $frame['message'];
                     $_code = unpack('nc', substr($message, 0, 2));
                     $code =& $_code['c'];
                     if (1000 > $code || 1004 <= $code && $code <= 1006 || 1012 <= $code && $code <= 1016 || 5000 <= $code) {
                         $this->close(self::CLOSE_PROTOCOL_ERROR);
                         break;
                     }
                     if (2 < $length) {
                         $reason = substr($message, 2);
                         if (false === (bool) preg_match('//u', $reason)) {
                             $this->close(self::CLOSE_MESSAGE_ERROR);
                             break;
                         }
                     }
                 }
                 $this->close(self::CLOSE_NORMAL);
                 $this->_on->fire('close', new Core\Event\Bucket(['code' => $code, 'reason' => $reason]));
                 break;
             default:
                 $this->close(self::CLOSE_PROTOCOL_ERROR);
         }
     } catch (Core\Exception\Idle $e) {
         try {
             $this->close(self::CLOSE_SERVER_ERROR);
             $exception = $e;
         } catch (Core\Exception\Idle $ee) {
             $this->getConnection()->disconnect();
             $exception = new Core\Exception\Group('An exception has been thrown. We have tried to close ' . 'the connection but another exception has been thrown.', 42);
             $exception[] = $e;
             $exception[] = $ee;
         }
         $this->_on->fire('error', new Core\Event\Bucket(['exception' => $exception]));
     }
     return;
 }