Inloggen
NL
apps/caramail-chat / src / Form / LoginForm.php · commit 6eebcdb
<?phpnamespace App\Form;use App\Chat\TempId;use App\Gui\Awt;use App\Gui\AwtButton;use App\Gui\AwtRadio;use App\Gui\AwtText;use App\Gui\Etched;use App\Gui\TabBar;use App\Net\WsLink;use JumPHP\Gui\Form;use JumPHP\Gui\Label;use JumPHP\Util\Lang;/** * Who you are (nickname, age, sex, city) and the server: what the applet got from the web page (its tempid). The * profile travels to the server as the tempid (TempId). The last values are kept in the options. * * @property TabBar $tabs * @property Etched $card * @property AwtText $nickname * @property AwtText $age * @property AwtRadio $woman * @property AwtRadio $man * @property AwtText $city * @property AwtText $server * @property AwtText $key * @property AwtText $adminKey * @property \JumPHP\Gui\Widget $roleRow * @property \App\Gui\AwtRadio $roleNormal * @property \App\Gui\AwtRadio $roleModo * @property \App\Gui\AwtRadio $roleAdmin * @property Label $status * @property AwtButton $enter */final class LoginForm extends Form{    private float $fontScale = 0;    protected function loaded(array $params = []): void    {        Awt::theme($this);        $this->fontScale = 0;        // the language of the page (?lang= of the playground or of the site, else the browser's) wins when it changed since        // the last visit: someone who reads jumphp.net in English gets the chat in English; a language chosen in the        // Options stays as long as the page's does not change        $o = $this->engine->options;        $page = substr(strtolower((string)\JumPHP\Kernel\Platform::setting('JUMPHP_LANG', '')), 0, 2);        if (isset(ChatForm::LANGUAGES[$page]) && $page !== (string)$o->get('lang_page', '')) {            $o->set('lang_page', $page);            $o->set('lang', $page);        }        $chosen = (string)$o->get('lang', '');        if (isset(ChatForm::LANGUAGES[$chosen])) {            $this->engine->lang->setLang($chosen);        }        $this->tabs->add('login', 'CaraChat');        $o = $this->engine->options;        $this->nickname->text = (string)($params['nickname'] ?? $o->get('nickname', ''));        $this->age->text = (string)($params['age'] ?? $o->get('age', ''));        $this->city->text = (string)($params['city'] ?? $o->get('city', ''));        $woman = (int)($params['sex'] ?? $o->get('sex', 1)) === 0;        $this->woman->checked = $woman;        $this->man->checked = !$woman;        $this->server->text = (string)($params['server'] ?? $o->get('server', self::defaultServer()));        $this->key->text = '';        $this->adminKey->text = '';        $this->roleRow->visible = false;        $this->probe(trim($this->server->text) ?: self::defaultServer());        $this->status->text = (string)($params['message'] ?? '');        $this->setFocus($this->nickname);        // from a partner's site (its connection form, JumPHP embed): its fields, and straight into the chat, as the        // applet started from the web page of Caramail        $this->site = (string)($params['site'] ?? '');        if (isset($params['sex']) && $params['sex'] !== '') {            $sex = (int)$params['sex'];            $this->woman->checked = $sex === 0;            $this->man->checked = $sex !== 0;        }        $this->autoEnter = $this->site !== '' && trim((string)($params['nickname'] ?? '')) !== '';    }    private string $site = '';    private bool $autoEnter = false;    /** The chat server: the one of jumphp.net (a WebSocket on 443), or CARACHAT_SERVER. */    public static function defaultServer(): string    {        return (string)(getenv('CARACHAT_SERVER') ?: ChatForm::DEFAULT_SERVER);    }    public function onEnterClick(mixed $sender = null): void    {        $nickname = trim($this->nickname->text);        $server = trim($this->server->text) ?: self::defaultServer();        if ($nickname === '' || preg_match('/[\t:]/', $nickname)) {            $this->status->text = Lang::t('A nickname, please');            $this->setFocus($this->nickname);            return;        }        $age = max(0, min(120, (int)$this->age->text));        $sex = $this->woman->checked ? 0 : 1;     // the applet's categories: 0 pink (women), 1 blue (men)        $city = trim($this->city->text);        $o = $this->engine->options;        foreach (['nickname' => $nickname, 'age' => $age ?: '', 'sex' => $sex, 'city' => $city, 'server' => $server] as $k => $v) {            $o->set($k, $v);        }        // the administrator's key wins over the moderator's; from the owner's address, the role chosen        $key = trim($this->adminKey->text) !== '' ? trim($this->adminKey->text) : trim($this->key->text);        $role = !$this->roleRow->visible ? null : ($this->roleAdmin->checked ? 2 : ($this->roleModo->checked ? 1 : 0));        $this->probeLink?->close();        $this->probeLink = null;        $this->scenes()->switchTo(ChatForm::class, [            'server' => $server,            'tempid' => TempId::make($nickname, $age, $sex, $city, $key, TempId::origin($this->site), $role),            'admin' => $role !== null ? $role > 0 : $key !== '',        ], false);    }    private ?WsLink $probeLink = null;    private string $probeBuffer = '';    /**     * Not of 2002: a short connection to ask the server whether this is the owner's address (700 TAB 1); the form then     * offers normal / moderator / administrator. In the browser only (the owner's), never in the tests.     */    private function probe(string $server): void    {        if (!\JumPHP\Kernel\Platform::isWasm() || !WsLink::isUrl($server)) {            return;        }        $link = new WsLink($server);        $this->probeLink = $link;        $this->probeBuffer = '';        $link->on('data', function (string $bytes) use ($link): void {            $this->probeBuffer .= $bytes;            while (($end = strpos($this->probeBuffer, "\n")) !== false) {                $line = substr($this->probeBuffer, 0, $end);                $this->probeBuffer = (string)substr($this->probeBuffer, $end + 1);                $f = explode("\t", rtrim($line, "\r"));                if ($f[0] === '100') {                    $link->write("700\t\n");                } elseif ($f[0] === '700') {                    $this->roleRow->visible = ($f[1] ?? '0') === '1';                    $this->invalidate();                    $link->close();                    $this->probeLink = null;                }            }        });    }    protected function tick(float $dt): void    {        Awt::keepCrisp($this, $this->fontScale);        $this->probeLink?->poll();        // a phone: the card at the top of the screen, its fields above the on-screen keyboard (centred, the last ones        // would be under it)        $justify = $this->breakpoint() === 'xs' ? 'start' : 'center';        if ($this->root !== null && ($this->root->props['justify'] ?? '') !== $justify) {            $this->root->props['justify'] = $justify;            $this->invalidate();        }        if ($this->autoEnter) {            $this->autoEnter = false;            $this->onEnterClick();        }    }}