<?php
/**
* SeekQuarry/Yioop --
* Open Source Pure PHP Search Engine, Crawler, and Indexer
*
* Copyright (C) 2009 - 2026 Chris Pollett chris@pollett.org
*
* LICENSE:
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* END LICENSE
*
* @author Chris Pollett chris@pollett.org
* @license https://www.gnu.org/licenses/ GPL3
* @link https://www.seekquarry.com/
* @copyright 2009 - 2026
* @filesource
*/
namespace seekquarry\yioop\executables;
use seekquarry\yioop\configs as C;
use seekquarry\yioop\library as L;
use seekquarry\yioop\library\CrawlDaemon;
if (php_sapi_name() != 'cli' ||
defined("seekquarry\\yioop\\configs\\IS_OWN_WEB_SERVER")) {
echo "BAD REQUEST";
exit();
}
/** Load in global configuration settings */
require_once __DIR__ . '/../configs/Config.php';
if (!C\PROFILE) {
echo "Please configure the search engine instance by visiting" .
"its web interface on localhost.\n";
exit();
}
/**
* Launcher starts the programs that Yioop's own web server is asked to
* start, such as a fetcher that has stopped and must be started again.
* A program the web server started itself would hold a copy of every file
* and connection the server had open at that moment. A busy server can
* hold most of what the system lets one program open, so such a fetcher
* could not open the files and connections of its first batch, and kept
* one end of each visitor's connection open after the server closed it.
* index.php starts the Launcher before the web server takes connections,
* so it holds almost nothing, and the programs it starts hold almost
* nothing too. The web server writes each start it wants as a file in
* CrawlDaemon::LAUNCH_REQUEST_FOLDER; CrawlDaemon::execInOwnProcess does
* that when it finds a Launcher running. The Launcher works the same on
* Linux, macOS and Windows.
*/
class Launcher
{
/**
* start runs the Launcher. It reads the command line through
* CrawlDaemon::init, as every Yioop program run in the background
* does, gives up the root account where the web server will (that is
* possible on Linux and macOS only, and nothing is needed on Windows),
* and then enters loop.
*/
public function start()
{
global $argv;
CrawlDaemon::init($argv, "Launcher");
/* The Launcher's few lines go to index.log, among the lines of
the web server it starts programs for, not to a log of its
own. */
L\crawlLog("Launcher started", "index", true);
if (!empty(C\WWW_USER) && function_exists("posix_geteuid") &&
posix_geteuid() === 0) {
/* The web server runs as WWW_USER, so what it asks to be
started runs as that user too. */
$user_info = posix_getpwnam(C\WWW_USER);
if (!empty($user_info['uid'])) {
posix_setgid($user_info['gid']);
posix_setuid($user_info['uid']);
}
}
L\makePath(CrawlDaemon::LAUNCH_REQUEST_FOLDER);
$this->loop();
}
/**
* loop looks for start requests every C\ONE_SECOND until the Launcher
* is asked to stop, and starts each program a request names, oldest
* first. A request is deleted before its program is started, so a
* request that fails is not tried forever.
*/
public function loop()
{
L\crawlLog("Launcher waiting for programs to start");
while (CrawlDaemon::processHandler()) {
$requests = glob(CrawlDaemon::LAUNCH_REQUEST_FOLDER . "/*" .
CrawlDaemon::LAUNCH_REQUEST_ENDING) ?: [];
sort($requests);
foreach ($requests as $request_name) {
$request = json_decode((string)@file_get_contents(
$request_name), true);
@unlink($request_name);
if (!is_array($request) ||
!CrawlDaemon::isLaunchableCommand(
$request['command'] ?? "")) {
L\crawlLog("Launcher passing over $request_name, " .
"which does not name a Yioop program");
continue;
}
L\crawlLog("Launcher starting " . $request['command']);
CrawlDaemon::execInOwnProcess($request['command'],
$request['output'] ?? (strstr(PHP_OS, "WIN") ?
"NUL" : "/dev/null"));
}
sleep(C\ONE_SECOND);
}
L\crawlLog("Launcher stopped");
}
}
/*
* Instantiate and run the Launcher program
*/
$launcher = new Launcher();
$launcher->start();