SeekquarrySeekquarry - Yioop Repo - Seekquarry

/ src / executables / Launcher.php⤓
<?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();