59 class Core implements \Erebot\Interfaces\Core
87 \Erebot\Interfaces\Config\Main $config,
88 \Erebot\Intl\TranslatorInterface $translator
91 $this->timers = array();
92 $this->running =
false;
93 $this->mainCfg = $config;
94 $this->translator = $translator;
99 if (function_exists(
'pcntl_signal')) {
109 foreach ($signals as $signal) {
110 pcntl_signal($signal, array($this,
'handleSignal'),
true);
113 pcntl_signal(SIGHUP, array($this,
'handleSIGHUP'),
true);
130 throw new \Exception(
"Cloning forbidden!");
136 return $this->connections;
155 $logger = \Plop\Plop::getInstance();
156 $logger->info($this->gettext(
'Erebot is starting'));
160 $this->running = time();
162 $this->createConnections($factory, $this->mainCfg);
165 while ($this->running) {
166 pcntl_signal_dispatch();
168 $read = $write = $except = array();
169 $actives = array(
'connections' => array(),
'timers' => array());
171 if ($this->connections === null) {
176 foreach ($this->connections as $index => $connection) {
177 $socket = $connection->getSocket();
179 if ($connection instanceof \Erebot\Interfaces\SendingConnection &&
180 $connection->getIO()->inWriteQueue()) {
184 if ($connection instanceof \Erebot\Interfaces\ReceivingConnection) {
189 $actives[
'connections'][$index] = $socket;
193 foreach ($this->timers as $index => $timer) {
194 $stream = $timer->getStream();
197 $actives[
'timers'][$index] = $stream;
201 if (count($read) + count($write) + count($except) == 0) {
203 $this->gettext(
'No more connections to handle, leaving...')
205 return $this->stop();
213 $nb = @stream_select($read, $write, $except, null);
214 }
catch (\Erebot\ErrorReportingException $e) {
215 if ($this->running) {
216 $logger->exception($this->gettext(
'Got exception'), $e);
231 if (count($except)) {
236 foreach ($read as $socket) {
239 $index = array_search(
241 $actives[
'connections'],
244 if ($index !==
false) {
247 $this->connections[$index]->read();
248 }
catch (\Erebot\ConnectionFailureException $e) {
251 'Connection failed, removing it '.
255 $this->removeConnection(
256 $this->connections[$index]
263 $index = array_search($socket, $actives[
'timers'],
true);
264 if ($index !==
false) {
265 $timer = $this->timers[$index];
268 if (!is_object($timer)) {
269 unset($this->timers[$index]);
272 $restart = $timer->activate();
276 if (!isset($this->timers[$index])) {
281 if ($restart ===
true || $timer->getRepetition()) {
284 unset($this->timers[$index]);
295 if (is_array($this->connections)) {
296 foreach ($this->connections as $connection) {
297 if ($connection instanceof \Erebot\Interfaces\ReceivingConnection) {
298 $connection->process();
304 foreach ($write as $socket) {
305 $index = array_search($socket, $actives[
'connections']);
306 if ($index !==
false && isset($this->connections[$index]) &&
307 $this->connections[$index] instanceof \Erebot\Interfaces\SendingConnection) {
308 $this->connections[$index]->write();
317 return $this->realStart($factory);
318 }
catch (\Erebot\StopException $e) {
325 public function stop()
327 $logger = \Plop\Plop::getInstance();
329 if (!$this->running) {
333 foreach ($this->connections as $connection) {
334 if ($connection instanceof \Erebot\Interfaces\EventDispatcher) {
335 $eventsProducer = $connection->getEventsProducer();
336 $connection->dispatch($eventsProducer->makeEvent(
'!ExitEvent'));
340 $logger->info($this->gettext(
'Erebot has stopped'));
347 $this->running =
false;
350 $this->mainCfg = null;
351 throw new \Erebot\StopException();
363 $consts = get_defined_constants(
true);
365 foreach ($consts[
'pcntl'] as $name => $value) {
366 if (!strncmp($name,
'SIG', 3) &&
367 strncmp($name,
'SIG_', 4) &&
374 $logger = \Plop\Plop::getInstance();
377 'Received signal #%(signum)d (%(signame)s)'
381 'signame' => $signame,
386 if (function_exists(
'memory_get_peak_usage')) {
387 $logger->debug($this->gettext(
'Memory usage:'));
389 $limit = trim(ini_get(
'memory_limit'));
390 $limit = \Erebot\Utils::parseHumanSize($limit.
"B");
392 (
string) $this->gettext(
"Allocated:") =>
393 \Erebot\Utils::humanSize(memory_get_peak_usage(
true)),
394 (
string) $this->gettext(
"Used:") =>
395 \Erebot\Utils::humanSize(memory_get_peak_usage(
false)),
396 (
string) $this->gettext(
"Limit:") =>
397 \Erebot\Utils::humanSize($limit),
400 foreach ($stats as $key => $value) {
402 '%(key)-16s%(value)10s',
414 public function getTimers()
416 return $this->timers;
419 public function addTimer(\Erebot\TimerInterface $timer)
421 $key = array_search($timer, $this->timers);
422 if ($key !==
false) {
423 throw new \Erebot\InvalidValueException(
'Timer already registered');
427 $this->timers[] = $timer;
430 public function removeTimer(\Erebot\TimerInterface $timer)
432 $key = array_search($timer, $this->timers);
433 if ($key ===
false) {
434 throw new \Erebot\NotFoundException(
'Timer not found');
437 unset($this->timers[$key]);
440 public function addConnection(\Erebot\Interfaces\Connection $connection)
442 $key = array_search($connection, $this->connections);
443 if ($key !==
false) {
444 throw new \Erebot\InvalidValueException(
445 'Already handling this connection'
449 $this->connections[] = $connection;
452 public function removeConnection(\Erebot\Interfaces\Connection $connection)
457 if (!isset($this->connections)) {
461 $key = array_search($connection, $this->connections);
462 if ($key ===
false) {
463 throw new \Erebot\NotFoundException(
'No such connection');
466 unset($this->connections[$key]);
469 public function gettext($message)
471 return $this->translator->gettext($message);
474 public function getRunningTime()
476 if (!$this->running) {
479 return time() - $this->running;
491 return $this->reload();
505 public function reload(\Erebot\Interfaces\Config\Main $config = null)
507 $logger = \Plop\Plop::getInstance();
509 $msg = $this->gettext(
'Reloading the configuration');
512 if (!count($this->connections)) {
513 $logger->info($this->gettext(
'No active connections... Aborting.'));
517 if ($config === null) {
518 $configFile = $this->mainCfg->getConfigFile();
519 if ($configFile === null) {
520 $msg = $this->gettext(
'No configuration file to reload');
526 $config = new \Erebot\Config\Main(
528 \Erebot\Interfaces\Config\Main::LOAD_FROM_FILE
532 $connectionCls = get_class($this->connections[0]);
533 $this->createConnections($connectionCls, $config);
534 $msg = $this->gettext(
'Successfully reloaded the configuration');
549 \Erebot\Interfaces\Config\Main $config
551 $logger = \Plop\Plop::getInstance();
556 $currentConnections = array();
557 foreach ($this->connections as $connection) {
558 $connCfg = $connection->getConfig(null);
560 $netCfg = $connCfg->getNetworkCfg();
561 $currentConnections[$netCfg->getName()] = $connection;
563 $newConnections[] = $connection;
568 $networks = $config->getNetworks();
569 foreach ($networks as $network) {
570 $netName = $network->getName();
571 if (isset($currentConnections[$netName])) {
573 $uris = $currentConnections[$netName]
575 ->getConnectionURI();
576 $uri = new \Erebot\URI($uris[count($uris) - 1]);
577 $serverCfg = $network->getServerCfg((
string) $uri);
581 'Reusing existing connection ' .
582 'for network "%(network)s"'
584 array(
'network' => $netName)
588 $copy = clone $currentConnections[$netName];
589 $copy->reload($serverCfg);
590 $newConnections[] = $copy;
591 unset($currentConnections[$netName]);
593 }
catch (\Erebot\NotFoundException $e) {
598 if (!in_array(
'\\Erebot\\Module\\AutoConnect', $network->getModules(
true))) {
602 $servers = $network->getServers();
603 foreach ($servers as $server) {
604 $uris = $server->getConnectionURI();
605 $serverUri = new \Erebot\URI($uris[count($uris) - 1]);
607 $connection = $factory->newConnection($this, $server);
611 if (isset($currentConnections[$netName])) {
612 $currentConnections[$netName]->disconnect();
613 unset($currentConnections[$netName]);
617 $this->gettext(
'Trying to connect to "%(uri)s"...'),
618 array(
'uri' => $serverUri)
620 $connection->connect();
621 $newConnections[] = $connection;
624 $this->gettext(
'Successfully connected to "%(uri)s"...'),
625 array(
'uri' => $serverUri)
629 }
catch (\Erebot\ConnectionFailureException $e) {
635 $this->gettext(
'Could not connect to "%(uri)s"'),
637 array(
'uri' => $serverUri)
644 foreach ($currentConnections as $connection) {
645 $connection->disconnect();
648 $this->connections = $newConnections;
649 $this->mainCfg = $config;
Provides core functionalities for Erebot.
$translator
Translator object for messages the bot may display.
createConnections(\Erebot\Interfaces\ConnectionFactory $factory,\Erebot\Interfaces\Config\Main $config)
$running
Indicates whether the bot is currently running or not.
realStart(\Erebot\Interfaces\ConnectionFactory $factory)
$connections
Connections to handle.
reload(\Erebot\Interfaces\Config\Main $config=null)
$mainCfg
Main configuration for the bot.
$timers
Timers to trigger.
__construct(\Erebot\Interfaces\Config\Main $config,\Erebot\Intl\TranslatorInterface $translator)