UK
games/xencenter-xenadmin-xcp-jumphp / src / Model / LocalNetwork.php · commit fb1b7c9
<?phpnamespace App\Model;use JumPHP\Kernel\Engine;use JumPHP\Kernel\Platform;use JumPHP\Net\RuntimeLink;use JumPHP\Runtime\RuntimeGuide;/** * A server of the user's local network (192.168.x.x, xcp.lan...) from a browser: the JumPHP server's bridge refuses private addresses, * only the JumPHP runtime on this computer reaches them. So such an address needs the local network ON: the runtime `ready` (installed, * started, this app allowed) and the badge's switch on "Local" (not "Server"). Otherwise the app says so before trying, instead of the * bridge's cryptic refusal. The desktop reaches everything with its sockets: never a problem there. * * The decision is pure (`problem()`, `isOn()`): tests give the state; `$wasm` forces the browser case (Platform::isWasm() is a constant). */final class LocalNetwork{    /** Tests: true / false forces the browser / the desktop case; null = Platform::isWasm(). */    public static ?bool $wasm = null;    public const STEP_INSTALL = 'install';    public const STEP_ALLOW = 'allow';    public const STEP_SWITCH = 'switch';    public static function wasm(): bool    {        return self::$wasm ?? Platform::isWasm();    }    /** The local network is in use: the runtime is ready and the user has not switched the badge to the server's proxy. */    public static function isOn(string $state, bool $usesServer, string $netMode = 'auto'): bool    {        return $netMode !== 'server' && $state === RuntimeLink::READY && !$usesServer;    }    /** What is missing: install (and start) the runtime, allow this app, or switch the badge to Local. */    public static function step(string $state, bool $usesServer): string    {        return match (true) {            $state === RuntimeLink::READY => self::STEP_SWITCH,            in_array($state, [RuntimeLink::RUNNING, RuntimeLink::REFUSED], true) => self::STEP_ALLOW,            default => self::STEP_INSTALL,        };    }    /**     * Why this server cannot be reached as things are, or null when it can (a public address, the demo pool, the desktop, or the local     * network on). The text tells the user what to do.     */    public static function problem(string $host, string $method, bool $wasm, string $state, bool $usesServer, string $netMode = 'auto', bool $dialog = true): ?string    {        if (!$wasm || $method === 'demo' || !Address::isLocal($host) || self::isOn($state, $usesServer, $netMode)) {            return null;        }        $head = "'$host' is an address of your local network. In a browser it can only be reached through the JumPHP runtime on this computer "            . '(required): the JumPHP server cannot reach private addresses.';        if ($netMode === 'server') {            return $head . ' This build of the app always uses the server: use the desktop version for a local server.';        }        $how = $dialog ? 'the button below shows how' : 'click the red badge at the top right: it shows how';        return $head . ' ' . match (self::step($state, $usesServer)) {            self::STEP_SWITCH => 'The runtime is ready but the badge at the top right is switched to "Server": switch it to "Local"' . ($dialog ? ' (or click the button below).' : '.'),            self::STEP_ALLOW => 'The runtime runs: allow this app (the orange badge at the top right' . ($dialog ? ', or the button below' : '') . '), then the badge shows "Local network active".',            default => "1. Install and start the JumPHP runtime ($how). 2." . ' Allow this app when it asks. '                . '3. Check that the badge at the top right says "Local network active", switched to "Local".',        };    }    /** The same, with the engine's runtime and settings. */    public static function check(string $host, string $method, bool $dialog = true): ?string    {        if (!self::wasm()) {            return null;        }        $engine = Engine::get();        $runtime = $engine->runtime();        return self::problem($host, $method, true, $runtime->state(), self::usesServer($runtime), $engine->config->netMode(), $dialog);    }    public static function usesServer(RuntimeLink $runtime): bool    {        return method_exists($runtime, 'usesServer') && (bool)$runtime->usesServer();    }    /**     * What the dialog's button does: switch the badge back to Local, ask the runtime to allow this app, or open the runtime's guide.     * Returns the step it took.     */    public static function fix(): string    {        $engine = Engine::get();        $runtime = $engine->runtime();        $step = self::step($runtime->state(), self::usesServer($runtime));        if ($step === self::STEP_SWITCH) {            if (method_exists($runtime, 'setUseServer')) {                $runtime->setUseServer(false);            }            $engine->options->set('net_use_server', false);        } elseif ($step === self::STEP_ALLOW) {            $runtime->pair($engine->config->id(), $engine->config->title());        } else {            $engine->scenes->push(RuntimeGuide::class);        }        return $step;    }    /** Whether new connections leave from the user's network now (for the texts). */    public static function inUse(): bool    {        $engine = Engine::get();        $runtime = $engine->runtime();        return self::isOn($runtime->state(), self::usesServer($runtime), $engine->config->netMode());    }    /** The text of the button that fixes it. */    public static function buttonText(string $state): string    {        return match (self::step($state, false)) {            self::STEP_SWITCH => 'Switch to the local network',            self::STEP_ALLOW => 'Allow this app on my network',            default => 'Install the JumPHP runtime…',        };    }}