Skip to content

Client Server Kommunikation

Marc Staebler edited this page Mar 25, 2026 · 5 revisions

Client-Server-Kommunikation

UserApps bestehen aus einem Server-Teil (JavaScript auf dem AppServer) und einem Client-Teil (HTML/JS im Knuddels-Client). Dieses Kapitel erklärt, wie die beiden miteinander kommunizieren.


Architektur-Überblick

┌─────────────────────┐         ┌─────────────────────┐
│   Client (Browser)  │  Events │   Server (Rhino)    │
│                     │ ──────► │                     │
│  www/index.html     │         │  main.js            │
│  Client.sendEvent() │         │  App.onEventReceived │
│                     │ ◄────── │                     │
│  Client.addEventListener()    │  session.sendEvent()│
└─────────────────────┘         └─────────────────────┘

AppContent öffnen

Bevor Client-Server-Kommunikation stattfinden kann, musst du dem Nutzer ein HTML-UI anzeigen. Das geschieht über AppContent:

// Servercode (innerhalb von var App = { ... };)
chatCommands: {
    openApp: function(user, params, command) {
        // pageData: initiale Daten, die an den Client geschickt werden
        var pageData = {
            username: user.getNick(),
            points: user.getPersistence().getNumber('points', 0)
        };

        var htmlFile = new HTMLFile("index.html", pageData);
        var popup = AppContent.popupContent(htmlFile, 480, 720);
        popup.setResponsive(true);

        if (user.canShowAppViewMode(AppViewMode.Popup)) {
            user.sendAppContent(popup);
        } else {
            user.sendPrivateMessage("Die App kann auf deinem Gerät leider nicht angezeigt werden.");
        }
    }
},

Das Client-Objekt

Wenn der Server AppContent an einen Nutzer sendet, wird das HTML nicht isoliert dargestellt, sondern in der Knuddels-Client-Umgebung. Diese stellt automatisch das globale Client-Objekt bereit, über das die Kommunikation mit dem Server läuft.

pageData empfangen

Die beim Erstellen der HTMLFile übergebenen Daten sind im Client verfügbar:

// Clientcode (www/index.html)
var pageData = {};
if (typeof Client !== 'undefined') {
    pageData = Client.pageData;
}

// pageData enthält jetzt { username: "...", points: 42 }
document.getElementById('name').textContent = pageData.username;

Hinweis: pageData kann nur serialisierbare Daten enthalten (Strings, Zahlen, Arrays, Objekte). Keine Funktionen!


Events: Client → Server

Der Client sendet Events an den Server mit Client.sendEvent():

// Clientcode
function kaufeItem(itemId) {
    if (typeof Client !== 'undefined' && Client.sendEvent) {
        Client.sendEvent('kaufeItem', { itemId: itemId, menge: 1 });
    }
}

Der Server empfängt das Event im onEventReceived-Hook:

// Servercode (innerhalb von var App = { ... };)
onEventReceived: function(user, type, data, appContentSession) {
    if (type === "kaufeItem") {
        var itemId = data.itemId;
        var menge = data.menge;

        // Kauf verarbeiten...
        KnuddelsServer.getDefaultLogger().info(
            user.getNick() + ' kauft Item ' + itemId
        );

        // Antwort an den Client senden
        appContentSession.sendEvent('kaufErfolgreich', {
            itemId: itemId,
            neuerKontostand: 950
        });
    }
},

Events: Server → Client

Der Server sendet Events an den Client über die appContentSession:

// Servercode (innerhalb von var App = { ... };)
onEventReceived: function(user, type, data, appContentSession) {
    if (type === "getHighscore") {
        var highscore = berechneHighscore();
        appContentSession.sendEvent('highscore', { daten: highscore });
    }
},

Der Client lauscht auf Events mit Client.addEventListener():

// Clientcode
if (typeof Client !== 'undefined') {
    Client.addEventListener("highscore", function(event) {
        var daten = event.data;
        zeigeHighscore(daten);
    });

    Client.addEventListener("kaufErfolgreich", function(event) {
        document.getElementById('kontostand').textContent = event.data.neuerKontostand;
    });
}

Lokales Frontend-Testen

Du kannst dein Frontend auch ohne Server lokal im Browser testen, indem du prüfst, ob Client definiert ist:

// Clientcode
var pageData = {};
if (typeof Client !== 'undefined') {
    // Läuft im Knuddels-Client
    pageData = Client.pageData;
} else {
    // Läuft lokal im Browser – Testdaten verwenden
    pageData = {
        username: "TestUser",
        points: 100
    };
}

Close-Listener

Du kannst reagieren, wenn ein Nutzer das App-Fenster schließt:

// Servercode (innerhalb von var App = { ... };)
chatCommands: {
    openApp: function(user, params, command) {
        var htmlFile = new HTMLFile("index.html", {});
        var popup = AppContent.popupContent(htmlFile, 480, 720);

        user.sendAppContent(popup);

        popup.addCloseListener(function(user, appContent) {
            user.sendPrivateMessage(
                "App geschlossen. Klicke °>/openApp|hier<°, um sie erneut zu öffnen."
            );
        });
    }
},

Limits

  • sendEvent-Daten: maximal 10.000 Zeichen pro Event
  • Frequenz: Das Versenden von sehr vielen Events in kurzer Zeit kann vom Server gedrosselt werden. Achte auf Datensparsamkeit.
  • pageData: Sollte möglichst kompakt sein, da es bei jedem Öffnen übertragen wird

Direct Connection

Standardmäßig laufen Events über den Knuddels-Chat-Protokoll-Kanal. Für mehr Geschwindigkeit kannst du Direct Connection aktivieren:

# In app.config
directConnection = knuddelsDE
# Für den Dev-Server:
# directConnection = knuddelsDEV

Vorteile: Schnellere Datenübertragung, größere Datenmengen möglich

Hinweis: Einzelne Entwickler haben von vereinzelten Verbindungsproblemen mit Direct Connection berichtet (App öffnet sich nicht oder schließt sich unerwartet). In der Praxis funktioniert Direct Connection bei den meisten Apps zuverlässig – auch bei großen UserApps mit vielen Nutzern. Wenn du es aktivierst, teste die App gründlich auf verschiedenen Geräten.


API-Referenz


← Zurück zur Übersicht

Navigation

Einstieg

Kernkonzepte

Features

Tutorials

Referenz & Hilfe

Clone this wiki locally