# Tutorial: a TCP connection, step by step

The example project `apps/hello-tcp` opens a TCP connection to a Redis server, sends it `PING` and shows the answer (`+PONG`). The same code
works on a computer (a socket) and in the browser (jumphp.net's TCP bridge). Redo it yourself in 8 steps.

## 1. Create the application

```bash
bin/jumphp gui:new mon-tcp "Mon TCP"        # apps/mon-tcp : une application graphique (formulaires, pas de HTML)
bin/jumphp install mon-tcp
```

## 2. Draw the window

Open `apps/mon-tcp/forms/MainForm.form.yaml` (in the IDE: the visual editor, Design tab): two fields (`host`, `port`), a `ping` button
(`events: {click: onPingClick}`), two labels (`status`, `result`). Copy the one from `apps/hello-tcp/forms/MainForm.form.yaml`.

## 3. Write the code behind

`apps/mon-tcp/src/Form/MainForm.php`: a class `final class MainForm extends JumPHP\Gui\Form`. One `@property` line per widget (the editor does it for you).

```php
public function onPingClick(mixed $sender = null): void
{
    $connection = $this->engine->tcp()->connect(trim($this->host->text), (int)$this->port->text);   // ne bloque jamais
    $connection->on('open',  fn () => $connection->write("PING\r\n"));                                  // connecté : on parle
    $connection->on('data',  function (string $bytes) use ($connection) {                               // la réponse
        $this->result->text = 'Réponse : ' . trim($bytes);
        $connection->close();
    });
    $connection->on('error', fn (string $message) => $this->result->text = $message);                   // le pourquoi d'un échec
}
```

The rules to remember: **never** call `stream_socket_client` or `fsockopen` (they do not exist in the browser); **never wait**: the answers arrive
as events between two frames. The events: `open`, `data` (bytes), `close` (the reason, or `null`), `error` (a message).

## 4. A test that plays the scene

`apps/mon-tcp/tests/MainFormTest.php` (see `apps/hello-tcp/tests/MainFormTest.php`): the test opens a real local TCP server (a fake Redis that answers `+PONG`), clicks the
button, advances the frames and checks the displayed text.

```bash
bin/jumphp test mon-tcp          # php -l, phpstan, phpunit (le test ci-dessus), puis 600 images de la scène
bin/jumphp shot mon-tcp          # une capture : ouvrez le PNG (apps/mon-tcp/var/screenshots/shot.png)
```

## 5. Try it on your computer

```bash
bin/jumphp run mon-tcp           # une vraie fenêtre ; entrez l'adresse d'un Redis et cliquez « Send PING »
```

## 6. Try it in the browser

```bash
bin/jumphp build mon-tcp && bin/jumphp serve mon-tcp      # http://localhost:8080
```

In the browser, a page cannot open a socket: the connection goes through jumphp.net's **TCP bridge**. It only lets through applications **approved by the
administrator**, for a precise version of the code, to any port (except outgoing mail 25 / 465 / 587) of public addresses. Without approval, the
`error` event says why (« This application has no TCP right… »). This is the expected behaviour: go on to step 7.

## 7. Publish and request TCP access

1. Push the project to Git and publish it on jumphp.net (see « Avec votre Claude » or the IDE: Mettre sur jumphp.net).
2. Studio → the project → **Accès TCP** → « Demander l'accès TCP » (with a message for the administrator if you like).
3. The administrator sees the request in their bell and **approves** it (or refuses): the approval is valid for the published commit. A new commit needs a new approval.

## 8. Check

Open the project page on jumphp.net, enter the address of a public Redis (or your own, port 6379) and click: `The server answered: +PONG`. The administrator sees the connection
live (Administration → Pont TCP: application, target, duration, bytes) and can cut it.

To go further: `docs/tcp.md` (the rights, the safeguards, the bridge on an independent server), `docs/tuto-ssh.md` (the same through an SSH server), UDP
(`$this->engine->udp()`) and pings (`$this->engine->icmp()`) in the same document.
