Implementiere Benutzerverbindungskontrolle und verbessere Nachrichtenverwaltung
- Füge die Methode `removeUserDisconnected` in der ChatRoom-Klasse hinzu, um Benutzer bei Verbindungsabbrüchen zu entfernen und entsprechende Nachrichten zu senden. - Aktualisiere die ChatUser-Klasse, um einen Token-Getter bereitzustellen und die Verbindungsprüfung zu optimieren. - Ändere die Server-Klasse, um die Benutzerverwaltung bei Raumwechseln zu verbessern und Debug-Informationen hinzuzufügen. - Optimiere die Socket-Optionen für eine schnellere Fehlererkennung und verbessere die Handhabung von Anfragen.
This commit is contained in:
197
deploy/README.md
Normal file
197
deploy/README.md
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
# YourChat Deployment Scripts
|
||||||
|
|
||||||
|
Diese Scripts ermöglichen das einfache Deployment von YourChat auf Ubuntu 22.04 Servern.
|
||||||
|
|
||||||
|
## Voraussetzungen
|
||||||
|
|
||||||
|
- Ubuntu 22.04 LTS Server
|
||||||
|
- Sudo-Rechte
|
||||||
|
- Internetverbindung für Paket-Downloads
|
||||||
|
|
||||||
|
## Scripts Übersicht
|
||||||
|
|
||||||
|
### 1. `deploy.sh` - Vollständiges Deployment
|
||||||
|
**Verwendung:** `./deploy/deploy.sh`
|
||||||
|
|
||||||
|
Führt alle Deploy-Schritte automatisch aus:
|
||||||
|
- Installation der Abhängigkeiten
|
||||||
|
- Bauen der Anwendung
|
||||||
|
- Installation als Systemdienst
|
||||||
|
- Konfigurations-Setup
|
||||||
|
|
||||||
|
### 2. `install_dependencies.sh` - Abhängigkeiten installieren
|
||||||
|
**Verwendung:** `./deploy/install_dependencies.sh`
|
||||||
|
|
||||||
|
Installiert alle benötigten Pakete:
|
||||||
|
- GCC-13 (als Standard-Compiler)
|
||||||
|
- CMake, Build-Tools
|
||||||
|
- OpenSSL, jsoncpp, pqxx
|
||||||
|
- PostgreSQL (optional)
|
||||||
|
|
||||||
|
### 3. `build.sh` - Anwendung bauen
|
||||||
|
**Verwendung:** `./deploy/build.sh`
|
||||||
|
|
||||||
|
Baut die Anwendung mit aktiviertem Debug-Flag:
|
||||||
|
- Erstellt `build/` Verzeichnis
|
||||||
|
- Konfiguriert CMake mit `YC_DEBUG=ON`
|
||||||
|
- Kompiliert mit allen verfügbaren CPU-Kernen
|
||||||
|
|
||||||
|
### 4. `install.sh` - Anwendung installieren
|
||||||
|
**Verwendung:** `./deploy/install.sh`
|
||||||
|
|
||||||
|
Installiert die Anwendung als Systemdienst:
|
||||||
|
- Erstellt `/opt/yourchat/` Verzeichnis
|
||||||
|
- Kopiert Binaries und Konfiguration
|
||||||
|
- Erstellt systemd Service
|
||||||
|
- Erstellt `yourchat` Benutzer
|
||||||
|
- Aktiviert Service
|
||||||
|
|
||||||
|
### 5. `update_config.sh` - Konfiguration aktualisieren
|
||||||
|
**Verwendung:** `./deploy/update_config.sh`
|
||||||
|
|
||||||
|
Aktualisiert die Konfiguration sicher:
|
||||||
|
- Überschreibt **keine** bestehenden Einträge
|
||||||
|
- Ergänzt nur fehlende Konfigurationsoptionen
|
||||||
|
- Erstellt automatisch Backups
|
||||||
|
- Zeigt Änderungen an
|
||||||
|
|
||||||
|
### 6. `update.sh` - Anwendung aktualisieren
|
||||||
|
**Verwendung:** `./deploy/update.sh`
|
||||||
|
|
||||||
|
Für zukünftige Updates:
|
||||||
|
- Stoppt Service
|
||||||
|
- Baut neue Version
|
||||||
|
- Aktualisiert Binaries
|
||||||
|
- Aktualisiert Konfiguration
|
||||||
|
- Startet Service neu
|
||||||
|
|
||||||
|
## Schnellstart
|
||||||
|
|
||||||
|
1. **Repository klonen/übertragen:**
|
||||||
|
```bash
|
||||||
|
# Auf dem Ubuntu Server
|
||||||
|
git clone <your-repo-url>
|
||||||
|
cd YourChat
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Vollständiges Deployment:**
|
||||||
|
```bash
|
||||||
|
chmod +x deploy/*.sh
|
||||||
|
./deploy/deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Service starten:**
|
||||||
|
```bash
|
||||||
|
sudo systemctl start yourchat
|
||||||
|
sudo systemctl status yourchat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Konfiguration
|
||||||
|
|
||||||
|
Die Konfiguration wird unter `/opt/yourchat/config/chatconfig.json` installiert.
|
||||||
|
|
||||||
|
**Wichtige Einstellungen:**
|
||||||
|
- `server.port`: Port für den Chat-Server (Standard: 1235)
|
||||||
|
- `database.*`: Datenbankverbindung
|
||||||
|
- `rooms`: Vordefinierte Chat-Räume
|
||||||
|
|
||||||
|
**Konfiguration bearbeiten:**
|
||||||
|
```bash
|
||||||
|
sudo nano /opt/yourchat/config/chatconfig.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Service-Verwaltung
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Service starten
|
||||||
|
sudo systemctl start yourchat
|
||||||
|
|
||||||
|
# Service stoppen
|
||||||
|
sudo systemctl stop yourchat
|
||||||
|
|
||||||
|
# Service neu starten
|
||||||
|
sudo systemctl restart yourchat
|
||||||
|
|
||||||
|
# Status prüfen
|
||||||
|
sudo systemctl status yourchat
|
||||||
|
|
||||||
|
# Logs anzeigen
|
||||||
|
sudo journalctl -u yourchat -f
|
||||||
|
|
||||||
|
# Service deaktivieren (startet nicht automatisch)
|
||||||
|
sudo systemctl disable yourchat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Firewall
|
||||||
|
|
||||||
|
Falls eine Firewall aktiv ist, den Port freigeben:
|
||||||
|
```bash
|
||||||
|
sudo ufw allow 1235/tcp
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Service startet nicht
|
||||||
|
```bash
|
||||||
|
# Logs prüfen
|
||||||
|
sudo journalctl -u yourchat -n 50
|
||||||
|
|
||||||
|
# Konfiguration prüfen
|
||||||
|
sudo cat /opt/yourchat/config/chatconfig.json | python3 -m json.tool
|
||||||
|
```
|
||||||
|
|
||||||
|
### Port bereits belegt
|
||||||
|
```bash
|
||||||
|
# Prüfen welcher Prozess den Port verwendet
|
||||||
|
sudo netstat -tlnp | grep 1235
|
||||||
|
|
||||||
|
# Port in Konfiguration ändern
|
||||||
|
sudo nano /opt/yourchat/config/chatconfig.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Berechtigungsprobleme
|
||||||
|
```bash
|
||||||
|
# Berechtigungen korrigieren
|
||||||
|
sudo chown -R yourchat:yourchat /opt/yourchat
|
||||||
|
sudo chmod 755 /opt/yourchat
|
||||||
|
sudo chmod 644 /opt/yourchat/config/chatconfig.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backup & Wiederherstellung
|
||||||
|
|
||||||
|
### Backup erstellen
|
||||||
|
```bash
|
||||||
|
# Konfiguration
|
||||||
|
sudo cp /opt/yourchat/config/chatconfig.json /backup/chatconfig.json.backup
|
||||||
|
|
||||||
|
# Datenbank (falls lokal)
|
||||||
|
sudo pg_dump yourchat > /backup/database.backup
|
||||||
|
```
|
||||||
|
|
||||||
|
### Wiederherstellung
|
||||||
|
```bash
|
||||||
|
# Konfiguration
|
||||||
|
sudo cp /backup/chatconfig.json.backup /opt/yourchat/config/chatconfig.json
|
||||||
|
sudo chown yourchat:yourchat /opt/yourchat/config/chatconfig.json
|
||||||
|
|
||||||
|
# Service neu starten
|
||||||
|
sudo systemctl restart yourchat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Updates
|
||||||
|
|
||||||
|
Für zukünftige Updates:
|
||||||
|
```bash
|
||||||
|
# Code aktualisieren
|
||||||
|
git pull
|
||||||
|
|
||||||
|
# Anwendung updaten
|
||||||
|
./deploy/update.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sicherheit
|
||||||
|
|
||||||
|
- Die Anwendung läuft als dedizierter `yourchat` Benutzer
|
||||||
|
- Konfigurationsdateien haben restriktive Berechtigungen
|
||||||
|
- Service startet nicht automatisch nach Reboot (kann mit `systemctl enable` aktiviert werden)
|
||||||
|
- Logs werden über systemd journal verwaltet
|
||||||
36
deploy/build.sh
Executable file
36
deploy/build.sh
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# YourChat Build Script
|
||||||
|
# Baut die Anwendung mit Debug-Flag
|
||||||
|
|
||||||
|
set -e # Beende bei Fehlern
|
||||||
|
|
||||||
|
echo "=== YourChat - Build Script ==="
|
||||||
|
|
||||||
|
# Prüfe ob wir im richtigen Verzeichnis sind
|
||||||
|
if [ ! -f "CMakeLists.txt" ]; then
|
||||||
|
echo "Fehler: CMakeLists.txt nicht gefunden. Bitte im YourChat-Root-Verzeichnis ausführen."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build-Verzeichnis erstellen
|
||||||
|
echo "=== Build-Verzeichnis erstellen ==="
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
|
||||||
|
# CMake konfigurieren mit Debug-Flag
|
||||||
|
echo "=== CMake konfigurieren ==="
|
||||||
|
cmake .. -DYC_DEBUG=ON
|
||||||
|
|
||||||
|
# Anwendung bauen
|
||||||
|
echo "=== Anwendung bauen ==="
|
||||||
|
make -j$(nproc)
|
||||||
|
|
||||||
|
echo "=== Build abgeschlossen ==="
|
||||||
|
echo "Ausführbare Dateien:"
|
||||||
|
ls -la yourchat ws_probe
|
||||||
|
|
||||||
|
# Zurück zum Root-Verzeichnis
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo "=== Build erfolgreich abgeschlossen! ==="
|
||||||
67
deploy/deploy.sh
Executable file
67
deploy/deploy.sh
Executable file
@@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# YourChat Haupt-Deploy Script
|
||||||
|
# Führt alle Deploy-Schritte automatisch aus
|
||||||
|
|
||||||
|
set -e # Beende bei Fehlern
|
||||||
|
|
||||||
|
echo "=== YourChat - Vollständiges Deployment Script ==="
|
||||||
|
echo "Dieses Script führt alle Deploy-Schritte automatisch aus."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Prüfe ob wir im richtigen Verzeichnis sind
|
||||||
|
if [ ! -f "CMakeLists.txt" ]; then
|
||||||
|
echo "Fehler: CMakeLists.txt nicht gefunden. Bitte im YourChat-Root-Verzeichnis ausführen."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Prüfe ob deploy-Verzeichnis existiert
|
||||||
|
if [ ! -d "deploy" ]; then
|
||||||
|
echo "Fehler: deploy-Verzeichnis nicht gefunden."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== Schritt 1: Abhängigkeiten installieren ==="
|
||||||
|
echo "Führe install_dependencies.sh aus..."
|
||||||
|
./deploy/install_dependencies.sh
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Schritt 2: Anwendung bauen ==="
|
||||||
|
echo "Führe build.sh aus..."
|
||||||
|
./deploy/build.sh
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Schritt 3: Anwendung installieren ==="
|
||||||
|
echo "Führe install.sh aus..."
|
||||||
|
./deploy/install.sh
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Schritt 4: Konfiguration aktualisieren ==="
|
||||||
|
echo "Führe update_config.sh aus..."
|
||||||
|
./deploy/update_config.sh
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Deployment abgeschlossen! ==="
|
||||||
|
echo ""
|
||||||
|
echo "=== Nächste Schritte: ==="
|
||||||
|
echo "1. Konfiguration anpassen (falls nötig):"
|
||||||
|
echo " sudo nano /opt/yourchat/config/chatconfig.json"
|
||||||
|
echo ""
|
||||||
|
echo "2. Service starten:"
|
||||||
|
echo " sudo systemctl start yourchat"
|
||||||
|
echo ""
|
||||||
|
echo "3. Status prüfen:"
|
||||||
|
echo " sudo systemctl status yourchat"
|
||||||
|
echo ""
|
||||||
|
echo "4. Logs anzeigen:"
|
||||||
|
echo " sudo journalctl -u yourchat -f"
|
||||||
|
echo ""
|
||||||
|
echo "5. Firewall konfigurieren (falls nötig):"
|
||||||
|
echo " sudo ufw allow 1235/tcp"
|
||||||
|
echo ""
|
||||||
|
echo "=== Nützliche Befehle: ==="
|
||||||
|
echo "- Service stoppen: sudo systemctl stop yourchat"
|
||||||
|
echo "- Service neu starten: sudo systemctl restart yourchat"
|
||||||
|
echo "- Service deaktivieren: sudo systemctl disable yourchat"
|
||||||
|
echo "- Logs anzeigen: sudo journalctl -u yourchat -f"
|
||||||
|
echo "- Konfiguration bearbeiten: sudo nano /opt/yourchat/config/chatconfig.json"
|
||||||
86
deploy/install.sh
Executable file
86
deploy/install.sh
Executable file
@@ -0,0 +1,86 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# YourChat Installations Script
|
||||||
|
# Installiert die Anwendung als Systemdienst
|
||||||
|
|
||||||
|
set -e # Beende bei Fehlern
|
||||||
|
|
||||||
|
echo "=== YourChat - Installation Script ==="
|
||||||
|
|
||||||
|
# Prüfe ob Build existiert
|
||||||
|
if [ ! -f "build/yourchat" ]; then
|
||||||
|
echo "Fehler: Build nicht gefunden. Bitte zuerst ./deploy/build.sh ausführen."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Installationsverzeichnis erstellen
|
||||||
|
echo "=== Installationsverzeichnis erstellen ==="
|
||||||
|
sudo mkdir -p /opt/yourchat
|
||||||
|
sudo mkdir -p /opt/yourchat/config
|
||||||
|
sudo mkdir -p /opt/yourchat/logs
|
||||||
|
|
||||||
|
# Anwendung installieren
|
||||||
|
echo "=== Anwendung installieren ==="
|
||||||
|
sudo cp build/yourchat /opt/yourchat/
|
||||||
|
sudo cp build/ws_probe /opt/yourchat/
|
||||||
|
sudo chmod +x /opt/yourchat/yourchat
|
||||||
|
sudo chmod +x /opt/yourchat/ws_probe
|
||||||
|
|
||||||
|
# Konfiguration installieren (nur wenn nicht vorhanden)
|
||||||
|
echo "=== Konfiguration installieren ==="
|
||||||
|
if [ ! -f "/opt/yourchat/config/chatconfig.json" ]; then
|
||||||
|
sudo cp config/chatconfig.json /opt/yourchat/config/
|
||||||
|
echo "Konfigurationsdatei installiert."
|
||||||
|
else
|
||||||
|
echo "Konfigurationsdatei existiert bereits - wird nicht überschrieben."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Systemd Service erstellen
|
||||||
|
echo "=== Systemd Service erstellen ==="
|
||||||
|
sudo tee /etc/systemd/system/yourchat.service > /dev/null <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=YourChat Server
|
||||||
|
After=network.target postgresql.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=yourchat
|
||||||
|
Group=yourchat
|
||||||
|
WorkingDirectory=/opt/yourchat
|
||||||
|
ExecStart=/opt/yourchat/yourchat
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Benutzer erstellen
|
||||||
|
echo "=== Benutzer erstellen ==="
|
||||||
|
if ! id "yourchat" &>/dev/null; then
|
||||||
|
sudo useradd -r -s /bin/false -d /opt/yourchat yourchat
|
||||||
|
echo "Benutzer 'yourchat' erstellt."
|
||||||
|
else
|
||||||
|
echo "Benutzer 'yourchat' existiert bereits."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Berechtigungen setzen
|
||||||
|
echo "=== Berechtigungen setzen ==="
|
||||||
|
sudo chown -R yourchat:yourchat /opt/yourchat
|
||||||
|
sudo chmod 755 /opt/yourchat
|
||||||
|
sudo chmod 644 /opt/yourchat/config/chatconfig.json
|
||||||
|
|
||||||
|
# Systemd Service aktivieren
|
||||||
|
echo "=== Systemd Service aktivieren ==="
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable yourchat.service
|
||||||
|
|
||||||
|
echo "=== Installation abgeschlossen! ==="
|
||||||
|
echo ""
|
||||||
|
echo "Nächste Schritte:"
|
||||||
|
echo "1. Konfiguration anpassen: sudo nano /opt/yourchat/config/chatconfig.json"
|
||||||
|
echo "2. Service starten: sudo systemctl start yourchat"
|
||||||
|
echo "3. Status prüfen: sudo systemctl status yourchat"
|
||||||
|
echo "4. Logs anzeigen: sudo journalctl -u yourchat -f"
|
||||||
49
deploy/install_dependencies.sh
Executable file
49
deploy/install_dependencies.sh
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# YourChat Deployment Script - Abhängigkeiten installieren
|
||||||
|
# Für Ubuntu 22.04 LTS
|
||||||
|
|
||||||
|
set -e # Beende bei Fehlern
|
||||||
|
|
||||||
|
echo "=== YourChat - Installation der Abhängigkeiten ==="
|
||||||
|
echo "System wird aktualisiert..."
|
||||||
|
|
||||||
|
# System aktualisieren
|
||||||
|
sudo apt update
|
||||||
|
sudo apt upgrade -y
|
||||||
|
|
||||||
|
echo "=== GCC-13 Repository hinzufügen ==="
|
||||||
|
# GCC-13 Repository hinzufügen
|
||||||
|
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||||
|
sudo apt update
|
||||||
|
|
||||||
|
echo "=== Grundlegende Build-Tools installieren ==="
|
||||||
|
# Grundlegende Build-Tools
|
||||||
|
sudo apt install -y build-essential cmake pkg-config
|
||||||
|
|
||||||
|
echo "=== GCC-13 installieren ==="
|
||||||
|
# GCC-13 installieren
|
||||||
|
sudo apt install -y gcc-13 g++-13
|
||||||
|
|
||||||
|
echo "=== GCC-13 als Standard setzen ==="
|
||||||
|
# GCC-13 als Standard setzen
|
||||||
|
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 130 --slave /usr/bin/g++ g++ /usr/bin/g++-13
|
||||||
|
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-13 130
|
||||||
|
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-13 130
|
||||||
|
|
||||||
|
echo "=== Bibliotheken installieren ==="
|
||||||
|
# Benötigte Bibliotheken
|
||||||
|
sudo apt install -y libssl-dev libjsoncpp-dev libpqxx-dev
|
||||||
|
|
||||||
|
echo "=== PostgreSQL installieren (falls nicht vorhanden) ==="
|
||||||
|
# PostgreSQL (falls Datenbank lokal laufen soll)
|
||||||
|
sudo apt install -y postgresql postgresql-contrib
|
||||||
|
|
||||||
|
echo "=== Überprüfung der Installation ==="
|
||||||
|
echo "GCC Version:"
|
||||||
|
gcc --version
|
||||||
|
echo ""
|
||||||
|
echo "CMake Version:"
|
||||||
|
cmake --version
|
||||||
|
echo ""
|
||||||
|
echo "Installation der Abhängigkeiten abgeschlossen!"
|
||||||
52
deploy/update.sh
Executable file
52
deploy/update.sh
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# YourChat Update Script
|
||||||
|
# Für zukünftige Updates der Anwendung
|
||||||
|
|
||||||
|
set -e # Beende bei Fehlern
|
||||||
|
|
||||||
|
echo "=== YourChat - Update Script ==="
|
||||||
|
echo "Dieses Script aktualisiert eine bestehende Installation."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Prüfe ob wir im richtigen Verzeichnis sind
|
||||||
|
if [ ! -f "CMakeLists.txt" ]; then
|
||||||
|
echo "Fehler: CMakeLists.txt nicht gefunden. Bitte im YourChat-Root-Verzeichnis ausführen."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Prüfe ob Anwendung installiert ist
|
||||||
|
if [ ! -f "/opt/yourchat/yourchat" ]; then
|
||||||
|
echo "Fehler: YourChat ist nicht installiert. Bitte zuerst ./deploy/deploy.sh ausführen."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== Service stoppen ==="
|
||||||
|
sudo systemctl stop yourchat || true
|
||||||
|
|
||||||
|
echo "=== Anwendung bauen ==="
|
||||||
|
./deploy/build.sh
|
||||||
|
|
||||||
|
echo "=== Anwendung aktualisieren ==="
|
||||||
|
echo "Kopiere neue Binaries..."
|
||||||
|
sudo cp build/yourchat /opt/yourchat/
|
||||||
|
sudo cp build/ws_probe /opt/yourchat/
|
||||||
|
sudo chmod +x /opt/yourchat/yourchat
|
||||||
|
sudo chmod +x /opt/yourchat/ws_probe
|
||||||
|
sudo chown yourchat:yourchat /opt/yourchat/yourchat
|
||||||
|
sudo chown yourchat:yourchat /opt/yourchat/ws_probe
|
||||||
|
|
||||||
|
echo "=== Konfiguration aktualisieren ==="
|
||||||
|
./deploy/update_config.sh
|
||||||
|
|
||||||
|
echo "=== Service neu starten ==="
|
||||||
|
sudo systemctl start yourchat
|
||||||
|
|
||||||
|
echo "=== Update abgeschlossen! ==="
|
||||||
|
echo ""
|
||||||
|
echo "Status prüfen:"
|
||||||
|
sudo systemctl status yourchat
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Logs anzeigen:"
|
||||||
|
echo "sudo journalctl -u yourchat -f"
|
||||||
160
deploy/update_config.sh
Executable file
160
deploy/update_config.sh
Executable file
@@ -0,0 +1,160 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# YourChat Konfigurations-Update Script
|
||||||
|
# Ergänzt fehlende Einträge in der Konfigurationsdatei ohne bestehende zu überschreiben
|
||||||
|
|
||||||
|
set -e # Beende bei Fehlern
|
||||||
|
|
||||||
|
echo "=== YourChat - Konfigurations-Update Script ==="
|
||||||
|
|
||||||
|
CONFIG_SOURCE="config/chatconfig.json"
|
||||||
|
CONFIG_TARGET="/opt/yourchat/config/chatconfig.json"
|
||||||
|
|
||||||
|
# Prüfe ob Quell-Konfiguration existiert
|
||||||
|
if [ ! -f "$CONFIG_SOURCE" ]; then
|
||||||
|
echo "Fehler: Quell-Konfiguration $CONFIG_SOURCE nicht gefunden."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Prüfe ob Ziel-Konfiguration existiert
|
||||||
|
if [ ! -f "$CONFIG_TARGET" ]; then
|
||||||
|
echo "Ziel-Konfiguration nicht gefunden. Kopiere komplette Konfiguration..."
|
||||||
|
sudo cp "$CONFIG_SOURCE" "$CONFIG_TARGET"
|
||||||
|
sudo chown yourchat:yourchat "$CONFIG_TARGET"
|
||||||
|
sudo chmod 644 "$CONFIG_TARGET"
|
||||||
|
echo "Konfiguration kopiert."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== Aktualisiere Konfiguration (fehlende Einträge ergänzen) ==="
|
||||||
|
|
||||||
|
# Temporäre Dateien erstellen
|
||||||
|
TEMP_SOURCE=$(mktemp)
|
||||||
|
TEMP_TARGET=$(mktemp)
|
||||||
|
TEMP_MERGED=$(mktemp)
|
||||||
|
|
||||||
|
# JSON-Dateien in temporäre Dateien kopieren
|
||||||
|
cp "$CONFIG_SOURCE" "$TEMP_SOURCE"
|
||||||
|
cp "$CONFIG_TARGET" "$TEMP_TARGET"
|
||||||
|
|
||||||
|
# Python-Script für JSON-Merge erstellen
|
||||||
|
cat > /tmp/merge_config.py << 'EOF'
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def merge_json(source_file, target_file, output_file):
|
||||||
|
"""Führt JSON-Dateien zusammen, ohne bestehende Einträge zu überschreiben"""
|
||||||
|
|
||||||
|
with open(source_file, 'r') as f:
|
||||||
|
source_data = json.load(f)
|
||||||
|
|
||||||
|
with open(target_file, 'r') as f:
|
||||||
|
target_data = json.load(f)
|
||||||
|
|
||||||
|
def merge_dict(source, target):
|
||||||
|
"""Rekursiv Dictionaries zusammenführen"""
|
||||||
|
result = target.copy()
|
||||||
|
|
||||||
|
for key, value in source.items():
|
||||||
|
if key not in result:
|
||||||
|
# Neuer Schlüssel - hinzufügen
|
||||||
|
result[key] = value
|
||||||
|
elif isinstance(value, dict) and isinstance(result[key], dict):
|
||||||
|
# Beide sind Dictionaries - rekursiv zusammenführen
|
||||||
|
result[key] = merge_dict(value, result[key])
|
||||||
|
elif isinstance(value, list) and isinstance(result[key], list):
|
||||||
|
# Beide sind Listen - nur neue Einträge hinzufügen
|
||||||
|
existing_items = set()
|
||||||
|
for item in result[key]:
|
||||||
|
if isinstance(item, dict) and 'name' in item:
|
||||||
|
existing_items.add(item['name'])
|
||||||
|
else:
|
||||||
|
existing_items.add(str(item))
|
||||||
|
|
||||||
|
for item in value:
|
||||||
|
if isinstance(item, dict) and 'name' in item:
|
||||||
|
if item['name'] not in existing_items:
|
||||||
|
result[key].append(item)
|
||||||
|
else:
|
||||||
|
if str(item) not in existing_items:
|
||||||
|
result[key].append(item)
|
||||||
|
# Für andere Typen: bestehenden Wert beibehalten
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
merged_data = merge_dict(source_data, target_data)
|
||||||
|
|
||||||
|
with open(output_file, 'w') as f:
|
||||||
|
json.dump(merged_data, f, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
|
return merged_data
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 4:
|
||||||
|
print("Verwendung: python3 merge_config.py <source> <target> <output>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
source_file = sys.argv[1]
|
||||||
|
target_file = sys.argv[2]
|
||||||
|
output_file = sys.argv[3]
|
||||||
|
|
||||||
|
try:
|
||||||
|
merged_data = merge_json(source_file, target_file, output_file)
|
||||||
|
print("Konfiguration erfolgreich zusammengeführt!")
|
||||||
|
|
||||||
|
# Zeige Änderungen an
|
||||||
|
print("\nNeue/aktualisierte Einträge:")
|
||||||
|
with open(target_file, 'r') as f:
|
||||||
|
original_data = json.load(f)
|
||||||
|
|
||||||
|
def show_changes(source, target, path=""):
|
||||||
|
for key, value in source.items():
|
||||||
|
current_path = f"{path}.{key}" if path else key
|
||||||
|
|
||||||
|
if key not in target:
|
||||||
|
print(f" + {current_path}: {value}")
|
||||||
|
elif isinstance(value, dict) and isinstance(target[key], dict):
|
||||||
|
show_changes(value, target[key], current_path)
|
||||||
|
elif isinstance(value, list) and isinstance(target[key], list):
|
||||||
|
# Zeige neue Listeneinträge
|
||||||
|
existing_names = set()
|
||||||
|
for item in target[key]:
|
||||||
|
if isinstance(item, dict) and 'name' in item:
|
||||||
|
existing_names.add(item['name'])
|
||||||
|
|
||||||
|
for item in value:
|
||||||
|
if isinstance(item, dict) and 'name' in item:
|
||||||
|
if item['name'] not in existing_names:
|
||||||
|
print(f" + {current_path}: {item}")
|
||||||
|
|
||||||
|
show_changes(merged_data, original_data)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler beim Zusammenführen: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Python-Script ausführbar machen und ausführen
|
||||||
|
chmod +x /tmp/merge_config.py
|
||||||
|
|
||||||
|
echo "Führe Konfigurationen zusammen..."
|
||||||
|
python3 /tmp/merge_config.py "$TEMP_SOURCE" "$TEMP_TARGET" "$TEMP_MERGED"
|
||||||
|
|
||||||
|
# Backup der alten Konfiguration erstellen
|
||||||
|
echo "Erstelle Backup der alten Konfiguration..."
|
||||||
|
sudo cp "$CONFIG_TARGET" "${CONFIG_TARGET}.backup.$(date +%Y%m%d_%H%M%S)"
|
||||||
|
|
||||||
|
# Neue Konfiguration installieren
|
||||||
|
echo "Installiere neue Konfiguration..."
|
||||||
|
sudo cp "$TEMP_MERGED" "$CONFIG_TARGET"
|
||||||
|
sudo chown yourchat:yourchat "$CONFIG_TARGET"
|
||||||
|
sudo chmod 644 "$CONFIG_TARGET"
|
||||||
|
|
||||||
|
# Aufräumen
|
||||||
|
rm -f "$TEMP_SOURCE" "$TEMP_TARGET" "$TEMP_MERGED" /tmp/merge_config.py
|
||||||
|
|
||||||
|
echo "=== Konfigurations-Update abgeschlossen! ==="
|
||||||
|
echo "Backup erstellt: ${CONFIG_TARGET}.backup.*"
|
||||||
|
echo ""
|
||||||
|
echo "Service neu starten mit: sudo systemctl restart yourchat"
|
||||||
@@ -94,13 +94,7 @@ namespace Yc
|
|||||||
newUser->start();
|
newUser->start();
|
||||||
Json::Value roomList = _parent->jsonRoomList();
|
Json::Value roomList = _parent->jsonRoomList();
|
||||||
newUser->sendMsg(ChatUser::roomList, roomList, "", "");
|
newUser->sendMsg(ChatUser::roomList, roomList, "", "");
|
||||||
// Private Rückmeldung an den User: In welchem Raum befindet er/sie sich jetzt?
|
|
||||||
{
|
|
||||||
Json::Value msg = Json::objectValue;
|
|
||||||
msg["tr"] = "room_entered";
|
|
||||||
msg["to"] = _name;
|
|
||||||
newUser->sendMsg(ChatUser::system, msg, "", "");
|
|
||||||
}
|
|
||||||
// Sende aktuelle Userliste an den neuen User
|
// Sende aktuelle Userliste an den neuen User
|
||||||
Json::Value currentUserList = userList();
|
Json::Value currentUserList = userList();
|
||||||
newUser->sendMsg(ChatUser::userListe, currentUserList, "", "");
|
newUser->sendMsg(ChatUser::userListe, currentUserList, "", "");
|
||||||
@@ -112,8 +106,11 @@ namespace Yc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Broadcast an andere Nutzer: Benutzer X hat den Raum betreten (mit Farbinfo)
|
// Broadcast an andere Nutzer: Benutzer X hat den Chat betreten (mit Farbinfo)
|
||||||
addMessage(ChatUser::system, "user_entered_room", newUser->name(), newUser->color());
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] addUser: Sending 'user_entered_chat' message for user: " << newUser->name() << std::endl;
|
||||||
|
#endif
|
||||||
|
addMessage(ChatUser::system, "user_entered_chat", newUser->name(), newUser->color());
|
||||||
_initRound();
|
_initRound();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -174,6 +171,20 @@ namespace Yc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChatRoom::removeUserDisconnected(std::shared_ptr<ChatUser> userToRemove)
|
||||||
|
{
|
||||||
|
for (auto it = _users.begin(); it != _users.end(); ++it)
|
||||||
|
{
|
||||||
|
if (*it == userToRemove)
|
||||||
|
{
|
||||||
|
// Spezielle Nachricht für Verbindungsabbrüche
|
||||||
|
addMessage(ChatUser::system, std::string("user_disconnected"), (*it)->name(), (*it)->color());
|
||||||
|
_users.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ChatRoom::setStop()
|
void ChatRoom::setStop()
|
||||||
{
|
{
|
||||||
_stop = true;
|
_stop = true;
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ namespace Yc
|
|||||||
bool userNameExists(std::string userName);
|
bool userNameExists(std::string userName);
|
||||||
void removeUser(std::string _token, bool silent = false);
|
void removeUser(std::string _token, bool silent = false);
|
||||||
void removeUser(std::shared_ptr<ChatUser> user, bool silent = false);
|
void removeUser(std::shared_ptr<ChatUser> user, bool silent = false);
|
||||||
|
void removeUserDisconnected(std::shared_ptr<ChatUser> userToRemove);
|
||||||
void setStop();
|
void setStop();
|
||||||
void addMessage(ChatUser::MsgType type, const char *messageText, std::string userName = "", std::string color = "");
|
void addMessage(ChatUser::MsgType type, const char *messageText, std::string userName = "", std::string color = "");
|
||||||
void addMessage(ChatUser::MsgType type, std::string messageText, std::string userName = "", std::string color = "");
|
void addMessage(ChatUser::MsgType type, std::string messageText, std::string userName = "", std::string color = "");
|
||||||
|
|||||||
@@ -111,6 +111,11 @@ namespace Yc
|
|||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ChatUser::getToken() const
|
||||||
|
{
|
||||||
|
return _token;
|
||||||
|
}
|
||||||
|
|
||||||
bool ChatUser::validateToken(std::string token)
|
bool ChatUser::validateToken(std::string token)
|
||||||
{
|
{
|
||||||
return (token == _token);
|
return (token == _token);
|
||||||
@@ -155,16 +160,57 @@ namespace Yc
|
|||||||
void ChatUser::checkerTask()
|
void ChatUser::checkerTask()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
// Heartbeat-Intervall: Alle 10 Sekunden Verbindung prüfen
|
||||||
|
const int HEARTBEAT_INTERVAL = 2;
|
||||||
|
int heartbeatCounter = 0;
|
||||||
|
|
||||||
while (!_stop)
|
while (!_stop)
|
||||||
{
|
{
|
||||||
fd_set readSd;
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
FD_ZERO(&readSd);
|
|
||||||
FD_SET(_socket, &readSd);
|
// Heartbeat-Check alle 10 Sekunden
|
||||||
timeval tv;
|
heartbeatCounter++;
|
||||||
tv.tv_sec = 0;
|
if (heartbeatCounter >= HEARTBEAT_INTERVAL) {
|
||||||
tv.tv_usec = 500;
|
heartbeatCounter = 0;
|
||||||
int selectResult = select(_socket + 1, &readSd, NULL, NULL, &tv);
|
|
||||||
if (selectResult == 1 && FD_ISSET(_socket, &readSd) == 1)
|
// Prüfe Verbindung mit MSG_PEEK (nicht-blockierend)
|
||||||
|
char peek;
|
||||||
|
ssize_t r = recv(_socket, &peek, 1, MSG_PEEK | MSG_DONTWAIT);
|
||||||
|
|
||||||
|
if (r == 0) {
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Verbindung zum Client abgebrochen (Token: <hidden>)" << std::endl;
|
||||||
|
#endif
|
||||||
|
_parent->removeUserDisconnected(shared_from_this());
|
||||||
|
_stop = true;
|
||||||
|
if (thread.joinable() && std::this_thread::get_id() == thread.get_id()) {
|
||||||
|
thread.detach();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (r < 0) {
|
||||||
|
// EINTR = Interrupted system call (normal), EAGAIN/EWOULDBLOCK = No data available (normal)
|
||||||
|
// Andere Fehler bedeuten Verbindungsabbruch
|
||||||
|
if (errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Socket-Fehler: " << strerror(errno) << " (Token: <hidden>)" << std::endl;
|
||||||
|
#endif
|
||||||
|
_parent->removeUserDisconnected(shared_from_this());
|
||||||
|
_stop = true;
|
||||||
|
if (thread.joinable() && std::this_thread::get_id() == thread.get_id()) {
|
||||||
|
thread.detach();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional: Sende Heartbeat-Ping an Client
|
||||||
|
// (kann helfen, NAT/Firewall-Verbindungen aktiv zu halten)
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Heartbeat check passed for user: " << _name << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ursprüngliche Verbindungsprüfung (alle 1 Sekunde)
|
||||||
{
|
{
|
||||||
char peek;
|
char peek;
|
||||||
ssize_t r = recv(_socket, &peek, 1, MSG_PEEK);
|
ssize_t r = recv(_socket, &peek, 1, MSG_PEEK);
|
||||||
@@ -172,7 +218,7 @@ namespace Yc
|
|||||||
#ifdef YC_DEBUG
|
#ifdef YC_DEBUG
|
||||||
std::cout << "[Debug] Verbindung zum Client abgebrochen (Token: <hidden>)" << std::endl;
|
std::cout << "[Debug] Verbindung zum Client abgebrochen (Token: <hidden>)" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
_parent->removeUser(_token);
|
_parent->removeUserDisconnected(shared_from_this());
|
||||||
_stop = true;
|
_stop = true;
|
||||||
if (thread.joinable() && std::this_thread::get_id() == thread.get_id()) {
|
if (thread.joinable() && std::this_thread::get_id() == thread.get_id()) {
|
||||||
thread.detach();
|
thread.detach();
|
||||||
@@ -180,6 +226,7 @@ namespace Yc
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string msg = readSocket(_socket);
|
std::string msg = readSocket(_socket);
|
||||||
if (msg == "")
|
if (msg == "")
|
||||||
{
|
{
|
||||||
@@ -347,7 +394,7 @@ namespace Yc
|
|||||||
}
|
}
|
||||||
else if (jsonTree["type"].asString() == "join")
|
else if (jsonTree["type"].asString() == "join")
|
||||||
{
|
{
|
||||||
changeRoom(jsonTree["newroom"].asString(), jsonTree["password"].asString());
|
changeRoom(jsonTree["room"].asString(), jsonTree["password"].asString());
|
||||||
}
|
}
|
||||||
else if (jsonTree["type"].asString() == "userlist")
|
else if (jsonTree["type"].asString() == "userlist")
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ namespace Yc
|
|||||||
ChatUser(std::shared_ptr<ChatRoom> parent, std::string name, std::string color, int socket);
|
ChatUser(std::shared_ptr<ChatRoom> parent, std::string name, std::string color, int socket);
|
||||||
~ChatUser();
|
~ChatUser();
|
||||||
std::string name() const;
|
std::string name() const;
|
||||||
|
std::string getToken() const;
|
||||||
bool validateToken(std::string token);
|
bool validateToken(std::string token);
|
||||||
bool isUser(std::shared_ptr<ChatUser> toValidate);
|
bool isUser(std::shared_ptr<ChatUser> toValidate);
|
||||||
void sendMsg(MsgType type, std::string message, std::string userName, std::string color);
|
void sendMsg(MsgType type, std::string message, std::string userName, std::string color);
|
||||||
|
|||||||
@@ -147,11 +147,29 @@ namespace Yc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Server::roomAllowed(std::string roomName, std::string userName, std::string password){
|
bool Server::roomAllowed(std::string roomName, std::string userName, std::string password){
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] roomAllowed called with roomName: '" << roomName << "', userName: '" << userName << "'" << std::endl;
|
||||||
|
std::cout << "[Debug] Available rooms: ";
|
||||||
for (auto &room: _rooms) {
|
for (auto &room: _rooms) {
|
||||||
if (room->name() == roomName && room->accessAllowed(userName, password)) {
|
std::cout << "'" << room->name() << "' ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (auto &room: _rooms) {
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Checking room: '" << room->name() << "' against requested: '" << roomName << "'" << std::endl;
|
||||||
|
#endif
|
||||||
|
if (room->name() == roomName && room->accessAllowed(userName, password)) {
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Room found and access allowed!" << std::endl;
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Room not found or access denied" << std::endl;
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,42 +177,97 @@ namespace Yc {
|
|||||||
if (!roomAllowed(newRoom, user->name(), password)) {
|
if (!roomAllowed(newRoom, user->name(), password)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string oldRoomName = "";
|
||||||
|
// Finde den aktuellen Raum des Users
|
||||||
|
for (auto &room: _rooms) {
|
||||||
|
if (room->userIsInRoom(user->name())) {
|
||||||
|
oldRoomName = room->name();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Json::Value userMsg = Json::objectValue;
|
Json::Value userMsg = Json::objectValue;
|
||||||
userMsg["tr"] = "room_change_user";
|
userMsg["tr"] = "room_change_user";
|
||||||
userMsg["to"] = newRoom;
|
userMsg["to"] = newRoom;
|
||||||
|
|
||||||
|
// Nur Nachrichten senden, wenn der User bereits in einem Raum ist (Raumwechsel)
|
||||||
|
if (!oldRoomName.empty()) {
|
||||||
|
for (auto &room: _rooms) {
|
||||||
|
if (room->name() == oldRoomName) {
|
||||||
|
// Sende Nachricht an alle User im alten Raum, dass der User den Raum verlassen hat
|
||||||
|
Json::Value leaveMsg = Json::objectValue;
|
||||||
|
leaveMsg["tr"] = "user_left_room";
|
||||||
|
leaveMsg["userName"] = user->name();
|
||||||
|
leaveMsg["userColor"] = user->color();
|
||||||
|
leaveMsg["destination"] = newRoom;
|
||||||
|
room->addMessage(ChatUser::system, leaveMsg, "", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entferne User aus dem alten Raum
|
||||||
for (auto &room: _rooms) {
|
for (auto &room: _rooms) {
|
||||||
if (room->userIsInRoom(user->name())) {
|
if (room->userIsInRoom(user->name())) {
|
||||||
room->removeUser(user);
|
room->removeUser(user->getToken(), true); // silent = true, da wir eigene Nachrichten senden
|
||||||
Json::Value msg = Json::objectValue;
|
break;
|
||||||
msg["tr"] = "room_change_to";
|
|
||||||
msg["to"] = newRoom;
|
|
||||||
userMsg["from"] = room->name();
|
|
||||||
room->addMessage(ChatUser::system, msg, user->name(), user->color());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
user->sendMsg(ChatUser::system, userMsg, "", "");
|
|
||||||
|
// Füge User zum neuen Raum hinzu
|
||||||
for (auto &room: _rooms) {
|
for (auto &room: _rooms) {
|
||||||
if (room->name() == newRoom) {
|
if (room->name() == newRoom) {
|
||||||
Json::Value msg = Json::objectValue;
|
#ifdef YC_DEBUG
|
||||||
msg["tr"] = "room_change_to";
|
std::cout << "[Debug] changeRoom: Adding user '" << user->name() << "' to room '" << newRoom << "'" << std::endl;
|
||||||
msg["from"] = userMsg["from"];
|
std::cout << "[Debug] changeRoom: oldRoomName = '" << (oldRoomName.empty() ? "EMPTY" : oldRoomName) << "'" << std::endl;
|
||||||
room->addMessage(ChatUser::system, msg, user->name(), user->color());
|
#endif
|
||||||
|
|
||||||
room->addUserWhenQueueEmpty(user);
|
room->addUserWhenQueueEmpty(user);
|
||||||
|
|
||||||
|
// Nur bei Raumwechsel (nicht beim ersten Beitritt) die Nachricht senden
|
||||||
|
if (!oldRoomName.empty()) {
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] changeRoom: Sending 'user_entered_room' message (room change)" << std::endl;
|
||||||
|
#endif
|
||||||
|
Json::Value joinMsg = Json::objectValue;
|
||||||
|
joinMsg["tr"] = "user_entered_room";
|
||||||
|
joinMsg["userName"] = user->name();
|
||||||
|
joinMsg["userColor"] = user->color();
|
||||||
|
joinMsg["origin"] = oldRoomName;
|
||||||
|
room->addMessage(ChatUser::system, joinMsg, "", "");
|
||||||
|
} else {
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] changeRoom: NOT sending 'user_entered_room' message (first join)" << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::createRooms(Json::Value roomList) {
|
void Server::createRooms(Json::Value roomList) {
|
||||||
auto self = shared_from_this();
|
auto self = shared_from_this();
|
||||||
bool created = false;
|
bool created = false;
|
||||||
|
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] createRooms called with roomList size: " << roomList.size() << std::endl;
|
||||||
|
std::cout << "[Debug] roomList content: " << roomList << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Attempting to load rooms from database..." << std::endl;
|
||||||
|
#endif
|
||||||
std::string query = R"(
|
std::string query = R"(
|
||||||
SELECT r.id, r.title, r.password_hash, r.room_type_id, r.is_public, r.owner_id, r.min_age, r.max_age, r.created_at, r.updated_at, rt.tr as room_type
|
SELECT r.id, r.title, r.password_hash, r.room_type_id, r.is_public, r.owner_id, r.min_age, r.max_age, r.created_at, r.updated_at, rt.tr as room_type
|
||||||
FROM chat.room r
|
FROM chat.room r
|
||||||
LEFT JOIN chat.room_type rt ON r.room_type_id = rt.id
|
LEFT JOIN chat.room_type rt ON r.room_type_id = rt.id
|
||||||
)";
|
)";
|
||||||
auto result = _database->exec(query);
|
auto result = _database->exec(query);
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Database query result size: " << result.size() << std::endl;
|
||||||
|
#endif
|
||||||
for (const auto& row : result) {
|
for (const auto& row : result) {
|
||||||
Json::Value room;
|
Json::Value room;
|
||||||
room["id"] = row["id"].as<int>();
|
room["id"] = row["id"].as<int>();
|
||||||
@@ -214,19 +287,41 @@ namespace Yc {
|
|||||||
auto newRoom = std::make_shared<ChatRoom>(self, room);
|
auto newRoom = std::make_shared<ChatRoom>(self, room);
|
||||||
_rooms.push_back(newRoom);
|
_rooms.push_back(newRoom);
|
||||||
created = true;
|
created = true;
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Created room from database: " << room["name"].asString() << std::endl;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Database error: " << e.what() << std::endl;
|
||||||
|
#endif
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
// ignore DB errors, fallback below
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Unknown database error occurred" << std::endl;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!created) {
|
if (!created) {
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Database loading failed, trying fallback rooms..." << std::endl;
|
||||||
|
#endif
|
||||||
// fallback to provided JSON room list (if any)
|
// fallback to provided JSON room list (if any)
|
||||||
if (roomList.isArray() && roomList.size() > 0) {
|
if (roomList.isArray() && roomList.size() > 0) {
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Loading " << roomList.size() << " fallback rooms from config" << std::endl;
|
||||||
|
#endif
|
||||||
for (const auto& room : roomList) {
|
for (const auto& room : roomList) {
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Creating fallback room: " << room["name"].asString() << std::endl;
|
||||||
|
#endif
|
||||||
auto newRoom = std::make_shared<ChatRoom>(self, room);
|
auto newRoom = std::make_shared<ChatRoom>(self, room);
|
||||||
_rooms.push_back(newRoom);
|
_rooms.push_back(newRoom);
|
||||||
created = true;
|
created = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] No fallback rooms in config, creating default room" << std::endl;
|
||||||
|
#endif
|
||||||
// final fallback: builtin default room
|
// final fallback: builtin default room
|
||||||
Json::Value room;
|
Json::Value room;
|
||||||
room["name"] = "Halle";
|
room["name"] = "Halle";
|
||||||
@@ -239,6 +334,13 @@ namespace Yc {
|
|||||||
created = true;
|
created = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef YC_DEBUG
|
||||||
|
std::cout << "[Debug] Total rooms created: " << _rooms.size() << std::endl;
|
||||||
|
for (const auto& room : _rooms) {
|
||||||
|
std::cout << "[Debug] Room: " << room->name() << std::endl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::handleRequest() {
|
void Server::handleRequest() {
|
||||||
@@ -260,10 +362,36 @@ namespace Yc {
|
|||||||
std::cout << "[YourChat] Verbindung akzeptiert von " << clientIP << ":" << ntohs(sockAddr.sin_port) << " (fd=" << userSock << ")" << std::endl;
|
std::cout << "[YourChat] Verbindung akzeptiert von " << clientIP << ":" << ntohs(sockAddr.sin_port) << " (fd=" << userSock << ")" << std::endl;
|
||||||
int flags = 1;
|
int flags = 1;
|
||||||
setsockopt(userSock, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
|
setsockopt(userSock, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
|
||||||
int ka2 = 1; setsockopt(userSock, SOL_SOCKET, SO_KEEPALIVE, &ka2, sizeof(ka2));
|
|
||||||
|
// Aggressive TCP Keep-Alive für schnelle Verbindungsabbruch-Erkennung
|
||||||
|
int ka2 = 1;
|
||||||
|
setsockopt(userSock, SOL_SOCKET, SO_KEEPALIVE, &ka2, sizeof(ka2));
|
||||||
|
|
||||||
|
// Keep-Alive Parameter: 5 Sekunden bis zum ersten Probe, dann alle 2 Sekunden
|
||||||
|
int keepalive_time = 5; // 5 Sekunden bis zum ersten Probe
|
||||||
|
int keepalive_intvl = 2; // 2 Sekunden zwischen Probes
|
||||||
|
int keepalive_probes = 3; // 3 Probes bevor Verbindung als tot betrachtet wird
|
||||||
|
|
||||||
|
setsockopt(userSock, IPPROTO_TCP, TCP_KEEPIDLE, &keepalive_time, sizeof(keepalive_time));
|
||||||
|
setsockopt(userSock, IPPROTO_TCP, TCP_KEEPINTVL, &keepalive_intvl, sizeof(keepalive_intvl));
|
||||||
|
setsockopt(userSock, IPPROTO_TCP, TCP_KEEPCNT, &keepalive_probes, sizeof(keepalive_probes));
|
||||||
|
|
||||||
// Begrenze Blockierzeit beim Senden, um langsame Clients nicht alle zu verzögern
|
// Begrenze Blockierzeit beim Senden, um langsame Clients nicht alle zu verzögern
|
||||||
timeval sendTimeout; sendTimeout.tv_sec = 0; sendTimeout.tv_usec = 500000; // 500ms
|
timeval sendTimeout; sendTimeout.tv_sec = 0; sendTimeout.tv_usec = 500000; // 500ms
|
||||||
setsockopt(userSock, SOL_SOCKET, SO_SNDTIMEO, &sendTimeout, sizeof(sendTimeout));
|
setsockopt(userSock, SOL_SOCKET, SO_SNDTIMEO, &sendTimeout, sizeof(sendTimeout));
|
||||||
|
|
||||||
|
// Socket-Optionen für schnellere Fehlererkennung
|
||||||
|
int reuseAddr = 1;
|
||||||
|
setsockopt(userSock, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr));
|
||||||
|
|
||||||
|
// LINGER-Option: Sofort schließen bei Verbindungsabbruch
|
||||||
|
struct linger linger_opt;
|
||||||
|
linger_opt.l_onoff = 1;
|
||||||
|
linger_opt.l_linger = 0; // 0 Sekunden = sofort schließen
|
||||||
|
setsockopt(userSock, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof(linger_opt));
|
||||||
|
|
||||||
|
// TCP_NODELAY bereits gesetzt (oben)
|
||||||
|
// TCP Keep-Alive bereits konfiguriert (oben)
|
||||||
std::string msg = readSocket(userSock);
|
std::string msg = readSocket(userSock);
|
||||||
#ifdef YC_DEBUG
|
#ifdef YC_DEBUG
|
||||||
std::cout << "[Debug] Neue Anfrage erhalten: " << msg << std::endl;
|
std::cout << "[Debug] Neue Anfrage erhalten: " << msg << std::endl;
|
||||||
|
|||||||
Reference in New Issue
Block a user