diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bfc336dd..658ae46ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,19 +2,71 @@ ## [1.0.8-rc20] - unstable +Chat SignalR fonctionnel de bout en bout (connexion, salons multiples, +envoi/réception de messages), enregistreur audio et localisation dans +PostIt, intégration Live.Avalonia démarrée, et reverse-proxy nginx +apprêté pour WebSocket. + ### Added -* [PostIt][WIP] Chat user interface +* [PostIt] Interface de chat : page `ChatPage` (connexion au hub, + saisie du nom de salon, liste des messages et des membres présents), + entrée depuis la page d'accueil. +* [PostIt] Envoi de messages dans un salon joint : DTO `ChatMessage` + (Name/Room/Message) pour l'événement `ReceiveMessage`, saisie avec + envoi sur `Enter`, commande inactive tant qu'aucune salle n'est en + focus (le hub refuse l'envoi hors salon, `LabNoJoinNoSend`). +* [PostIt] Modèle multi-salles côté client : `JoinedRooms`, + `SelectedRoom` (salle en focus), messages et utilisateurs indexés par + salle (`FocusedMessages`/`FocusedUsers`), ComboBox de choix de la + salle active ; un `Join` sur une salle déjà jointe ne fait que + changer le focus. +* [PostIt] Enregistreur audio (`AudioRecorder`, interface + `IPCMProcessor`) et ressources de localisation + (`Resources.{resx,en-EN,pt-PT}`). +* [PostIt][WIP] Début d'intégration Live.Avalonia (preview XAML à + chaud ; encore KO). +* [contrib] Bloc `location /chathub` dans `template.vhost` : upgrade + WebSocket (`Upgrade`/`Connection`), `proxy_read_timeout 3600s` et + `proxy_buffering off` — sans quoi la connexion SignalR tombait au + premier silence ou l'upgrade échouait derrière nginx. -* [PostIt][WIP] Live.Avalonia start of integration +### Changed + +* [PostIt] `StatusNotice` déplacé de `Models` vers `ViewModels` et + enrichi d'une commande d'action optionnelle (`CheckCommand` + + `CheckCommandLabel`, interface `IWithLabel`) : le bandeau de statut + propose désormais l'action contextuelle (Connecter / Déconnecter / + Reconnecter / Vérifier la connexion). +* [PostIt] `ChatViewModel` suit le cycle de vie complet de la + connexion : handlers `Reconnecting` / `Reconnected` / `Closed` de + `WithAutomaticReconnect`, pour refléter l'état réel au lieu d'un + `IsConnected` optimiste. +* [Yavsc.Api] `AddSignalR().AddJsonProtocol(IncludeFields = true)` : + `ChatRoomInfo` n'expose que des champs publics, que System.Text.Json + ne sérialise pas par défaut — le client recevait des objets vides + (`Name` null, `Users` vide) et la liste des salons joints n'était + jamais alimentée. +* [Yavsc.Server] `IConnexionManager.OnConnected` prend le `userName` + en paramètre (résolu depuis les claims dans `ChatHub`) au lieu de le + relire depuis un dictionnaire jamais alimenté. +* [PostIt.Android] `network_security_config.xml` déplacé sous + `Resources/xml/` (chemin canonique Android). ### Fixed -nothing - -### Changed - -nothçing +* [Yavsc.Server] `KeyNotFoundException` dans + `HubConnectionManager.OnConnected` à chaque connexion SignalR : + `ChatUserNames` (et `ChatCxIds`) n'étaient jamais alimentés — relique + d'un `SetUserName` disparu lors d'une refactorisation. L'exception + dans `OnConnectedAsync` faisait fermer la connexion par le hub, et + PostIt affichait « Déconnecté (The server closed the connection…) » + immédiatement après la connexion. +* [PostIt] URL du hub SignalR : retrait du préfixe `/api/v1` de + `ApiUrl` avant d'apposer `Constants.ChatHubPath` (le hub est mappé à + la racine du service, pas sous le préfixe versionné). +* [PostIt] La `StatusBar` de la page chat référençait `Grid.Row="4"` + sur une grille à 3 rangées (rangée hors limites, bandeau invisible). ## [1.0.8-rc19] - unstable diff --git a/contrib/Makefile b/contrib/Makefile index deb55bcc6..5ccf773a1 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -14,7 +14,7 @@ reinstall: copy-binaries @echo "💯 backend started" reinstall-prod: - make reinstall APP_INSTALL_ENV= APP_INSTALL_PREFIX= APP_INSTALL_ENV=production + make reinstall APP_INSTALL_PREFIX= APP_INSTALL_ENV=production generated/$(APP_INSTALL_PREFIX)yavscOrg.service: generated/$(APP_INSTALL_PREFIX)yavscBlogs.service: diff --git a/contrib/template.vhost b/contrib/template.vhost index ea2c2cb6d..b4c9c139e 100644 --- a/contrib/template.vhost +++ b/contrib/template.vhost @@ -57,5 +57,25 @@ server { proxy_read_timeout 100s; proxy_buffering off; } + + # SignalR (ChatHub) : WebSocket exige Upgrade/Connection et un timeout + # long, sinon la connexion tombe au premier silence ou l'upgrade échoue. + # Connection est fixé à "upgrade" (pas de map $connection_upgrade, qui + # exigerait une directive map {} globale hors de ce vhost) : SignalR + # négocie toujours un upgrade sur ce chemin, et la négociation initiale + # (POST /negotiate, sans en-tête Upgrade) n'est pas affectée par cet + # en-tête côté Kestrel. + location /chathub { + proxy_pass $BACKEND_SCHEME://$HTTP_HOST:$BACKEND_PORT; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 3600s; + proxy_buffering off; + } include server-status.conf; -} \ No newline at end of file +} diff --git a/src/PostIt/PostIt.Android/Properties/AndroidManifest.xml b/src/PostIt/PostIt.Android/Properties/AndroidManifest.xml index 46f0bc9bb..256555df1 100644 --- a/src/PostIt/PostIt.Android/Properties/AndroidManifest.xml +++ b/src/PostIt/PostIt.Android/Properties/AndroidManifest.xml @@ -4,6 +4,7 @@ + android:networkSecurityConfig="@xml/network_security_config" + android:hardwareAccelerated="true"> diff --git a/src/PostIt/PostIt.Android/Resources/network_security_config.xml b/src/PostIt/PostIt.Android/Resources/xml/network_security_config.xml similarity index 100% rename from src/PostIt/PostIt.Android/Resources/network_security_config.xml rename to src/PostIt/PostIt.Android/Resources/xml/network_security_config.xml diff --git a/src/PostIt/PostIt.Tests/EstimateEditionPageViewModelTests.cs b/src/PostIt/PostIt.Tests/EstimateEditionPageViewModelTests.cs index 17efd391b..31c82387d 100644 --- a/src/PostIt/PostIt.Tests/EstimateEditionPageViewModelTests.cs +++ b/src/PostIt/PostIt.Tests/EstimateEditionPageViewModelTests.cs @@ -1,4 +1,5 @@ using System.Net.Http; +using PostIt.Models; using PostIt.ViewModels; using Yavsc; using Yavsc.Api.Client; diff --git a/src/PostIt/PostIt.Tests/StatusBarTests.cs b/src/PostIt/PostIt.Tests/StatusBarTests.cs index 4053dbaf3..15889e0b0 100644 --- a/src/PostIt/PostIt.Tests/StatusBarTests.cs +++ b/src/PostIt/PostIt.Tests/StatusBarTests.cs @@ -2,6 +2,7 @@ using Avalonia.Controls; using Avalonia.Headless.XUnit; using Avalonia.VisualTree; using PostIt.Controls; +using PostIt.Models; using PostIt.ViewModels; namespace PostIt.Tests; @@ -21,7 +22,9 @@ public class StatusBarTests [AvaloniaFact] public void Status_message_is_rendered_by_a_SelectableTextBlock() { - var bar = new StatusBar { DataContext = StatusNotice.Error("Échec de la suppression : boom") }; + var bar = new StatusBar { + DataContext = + StatusNotice.Error("Échec de la suppression : boom") }; var window = new Window { Content = bar }; window.Show(); @@ -32,4 +35,4 @@ public class StatusBarTests Assert.NotNull(message); Assert.Equal("Échec de la suppression : boom", message!.Text); } -} \ No newline at end of file +} diff --git a/src/PostIt/PostIt/Controls/StatusBar.axaml b/src/PostIt/PostIt/Controls/StatusBar.axaml index 2f46fee33..755ff7d3e 100644 --- a/src/PostIt/PostIt/Controls/StatusBar.axaml +++ b/src/PostIt/PostIt/Controls/StatusBar.axaml @@ -10,16 +10,19 @@ Padding="8"> - + FontWeight="Bold" + Foreground="{Binding Foreground}" + VerticalAlignment="Top"/> + Foreground="{Binding Foreground}" + TextWrapping="Wrap" + VerticalAlignment="Center"/> +