User- und Dozenten-Chat

Der Pool Video Switch verfügt über einen Nachrichtendienst, der dem Internet Relay Chat (IRC) ähnelt. Es soll zur Verbesserung der Kommunikation zwischen allen Teilnehmern einer Sitzung dienen. Diese Funktionalität kann bei Bedarf auch abgeschaltet werden.

Chat starten

Den Chat kann man auf zwei unterschiedliche Weisen starten.
Die erste Möglichkeit ist mittels der Clientleiste (Menü -> Chat)

und die zweite durch rechten Mausklick auf das Systray-Icon.

Dabei ist darauf zu achten, dass der Chat erst gestartet werden kann, wenn der Client mit der Steuerkonsole verbunden ist.

Features

  • Private Nachrichten

Private Gespräche zwischen 2 Teilnehmern sind auch möglich und leicht zu starten durch Doppelklick auf dem Nickname des gewünschten Gesprächspartners. Alle Teilnehmer werden auf der rechten Seite des Chatfensters aufgelistet.

  • Öffentliche Nachrichten

Defaultmäßig ist der @all-Kanal (öffentlicher Chat-Raum) aktiviert. Gespräche in diesem Kanal sind für alle Teilnehmer sichtbar und kann bsw. dazu dienen, wichtige Informationen zu verteilen.

  • File Sharing

Dateien untereinander austauschen erfolgt leicht und schnell, indem man zuerst auf den entsprechenden Empfänger (Im Chat-Fenster) recht-klickt und dann "Send File..." auswählt. Dabei ist darauf zu achten, dass die Größe einer Datei maximal 2GByte betragen darf.

Einstellungen

Client

  • Clients können keine Einstellungen vornehmen. Der Chat wird zentral vom Server gesteuert.

Server

  • Verbieten/Erlauben von privaten Gesprächen

TBA

  • Ein/Aus-Schalten des @all-Kanals

TBA

  • Ein/Aus-Schalten des gesamten Chats

TBA

Technisches

Komponente
  • PVSMsg
  • PVSServerConnection
  • PVSConnectionManager
  • Daemon
  • PVSChatChlient
  • ...

Aufbau des Chat-Clients

Initialisierung

PVS::PVS() : QObject()
{
    .....

    _chat = new PVSChatClient();
    _chat->setServerConnection(_pvsServerConnection);
    _chat->getChatMsgHandler().addListener(this, &PVS::chat_receive);
    _chat->getChatCommandHandler().addListener(this, &PVS::UpdateChatClients);

}

Als Feld des PVS-Objekts (siehe src/pvs.h) wird das PVSChatClient-Objekt "_chat" erzeugt, welches alle nötige Funktionen zum Empfang/Versenden von Chat-Nachrichten besitzt. Verständlicherweise kann der Chat-Client Nachrichten vom Server empfangen bzw. zum Server versenden nur wenn es eine Verbindung zu diesem besteht, eine solche Verbindung ist bereit vorhanden im PVS-Objekt und wird an das _chat-Objekt weiter gegeben mittels folgender Methode

void PVSChatClient::setServerConnection(PVSServerConnection* sc)
{
    if (sc)
    {
        _chatServerConnection = sc;
        _chatServerConnection->addChatHandler("*", this, &PVSChatClient::receive);
    }
}

Hier wird außerdem in der PVSChatClient-Klasse den Dispatcher der Verbindung eingerichtet damit die receive-Methode der PVSChatClient-Klasse von der PVSServerConnection-Klasse her ausgeführt werden kann so bald eine Chat-Nachricht von Server empfangen wird.

In derselben Art und Weise wird in der PVS-Klasse den Dispatcher für die chat_receive-Methode eingerichtet, damit diese von der PVSChatClient-Klasse her ausgeführt werden kann sobald eine Nachricht berits behandelt wurde.

chat->getChatHandler().addListener(this, &PVS::chat_receive);

Senden von Chat-Nachrichten

[GUI] ~> PVS::chat_send ~> PVSChatClient::send ~> PVSServerConnection::sendMessage ~> [SERVER]

Chat-Nachrichten werden zuerst vom Nutzer in der Chat-GUI eingegeben und mittels des Knopfes "Send" zur Übertragung freigegeben. Bis hier ist eine Chat-Nachricht kein Objekt sondern nur zwie QStrings (Empfänger und die eigentliche Nachricht) die anhand D-Bus an die PVS-Klasse weitergeleitet werden, wo die Methode "chat_send" beide Strings zur Freigabe ins Netz gibt.

Nun ist die PVSChatClient-Klasse für die eingentliche Übertragung ins Netz zuständig. Laut dem PVS-Protokoll dürfen nur PVSMgs ins Netz übetragen werden, deswegen macht die send-Methode aus den 2 erhalten QStrings eine PVSMsg mit folgendem Gestallt:

PVSMsg
Feld Obj-Typ Inhalt Beschreibung
type enum PVSMSG Signatur der Chat-Nachrichten.
ident QString <Username des Empfägers>
msg QString <Username des Absenders> + ":" + <Die eigentliche Nachricht> Da PVSMsg keine Stelle für den Absender-Username besitzt, wir dieser am Anfang der Nachricht hinzufügt. Der Doppeltpunkt dazwischen dient zum späteren Parsen.
sndID integer 0 Später trägt der Server die ID des Absenders ein.

und schickt diese ins Netz über die Verbindung zum Server. Zu diesem Zeitpunkt hat die Chat-Nachricht den Client verlassen und der Server ist (bei erfolgreicher Übertragung) dafür zuständig, die Nachricht zu behandeln.

Bearbeitung der Chat-Nachrichten im Server

Chat-Nachrichten werden auf der Serverseite in der Klasse "PVSConnectionManager" mittels der "OnChat"-Methode behandelt. Es wird zuerst nach dem Empfänger gesucht, der im Feld "ident" der Nachricht zu finden ist, und nach dem Absender. Der Absender befindet sich im Feld "msg" der Nachricht. Er ist durch einen Doppelpunkt von der eigentliche Nachricht getrennt und wird durch einfaches Parsen abgelesen und entfernt. Nun dass sowohl Empfänger als auch Absender vorhanden sind, wird die Nachricht an beide per Netz geschickt, so dass wenn der Absender seine eigene Nachricht bekommt, dies als Bestätigung gilt, dass der Server diese Nachricht erfolgreich behandelt hat.

Empfangen von Chat-Nachrichten

[SERVER] ~> PVSServerConnection::handleClientMsg ~> PVSChatClient::receive ~> PVS::chat_receive ~> [GUI]

Nachrichten vom Server werden in der PVSServerConnection-Klasse empfangen. Alle Nachrichten von Typ "PVSMSG" sind Chat-Nachrichten und werden über den Dispatcher an die PVSChatClient-Klasse weiter geleitet (siehe Methode "PVSServerConnection::handleClientMsg"), wo sie von der receive-Methode behandelt werden.

void PVSChatClient::receive(PVSMsg recv)
{
    PVSChatMsg chatMsg(recv);

    if(chatMsg.isCommand()) // command message for update of the client list.
    {
        _chatCommandDispatcher.fire(chatMsg);
    }
    else // conversation message.
    {
        _chatMessageDispatcher.fire(chatMsg);
    }
}

Die receive-Methode der PVSChatClient-Klasse macht zuerst aus der PVSMessage eine PVSChatMessage. In Abhängigkeit vom Gestalt der PVSMessage können zwei arten von PVSChatMessage's generiert werden:

  1. Befehl-Nachrichten: Ein Aufrug der Methode "isCommand" angewendet auf solche Nachrichten liefert den Boolean-Wert "true" zurück.
  2. Gespräch-Nachrichten

PVSMsg's mit dem oben beschriebenen Gestalt generieren Gespräch-Nachrichten. Solche Nachrichten werden über den "chatMessageDispatcher" an die PVS-Klasse weitergeleitet wo letztendlich die Übergabe an die Chat-GUI erfolgt.

void PVS::chat_receive(PVSChatMsg msg)
{
    emit chat_receive(msg.getNickFrom(), msg.getNickTo(), msg.getMsg());
}

Im welchem Fall Befehl-Nachrichten erzeugt werden, behandeln wir im nächsten Abschnitt.

Nutzerliste

Auf der rechten Seite des Chat-Fensters steht eine Liste mit den Nutzernamen aller Chat-Teilnehmer. Diese Liste ändert sich automatisch wenn ein Nutzer den Chat verlässt oder ein neuer Nutzer den Chat betritt. Die Nutzerliste wird komplett vom Server verwaltet und funktioniert folgendermaßen:

Die Klasse "PVSConnectionManager" ist dafür zuständig, alle Client-Server-Verbindungen zu verwaltet. Von dort werden alle verbundene Clients über die neuen Ereignisse in der Client-Liste informiert.

Nutzer hinzufügen:

Kommt ein neuer Client im Server hinzu, so wird dieser zuerst mittels der Methode "_sendEventToClients_" darüber informiert, welche Clients bereits im Server eingetragen sind.

void PVSConnectionManager::onClientNew(PVSClientConnection* newConnection)
{
    ...
    sendEventToClients(QString("addedConnection"), newConnection, "");
    ...
}

Bis hier ist der neue Client noch für alle andere Clients unbekannt. Er darf bekannt gegeben werden erst wenn er über einen Nutzername verfügt. Die Zuweisung davon erfolgt in der Methode "onLoginUsername", wo mittels der Methode "_sendEventToClients"_ nicht nur jeder Client sondern auch der neuer Client selbst (da unter Umständen der Nutzername verändert wird) davon informiert wird. Außerdem wird das Ereignis in den Chatlog eingetragen.

void PVSConnectionManager::onLoginUsername(PVSMsg command)
{
    ...
        ConsoleLog writeChat(tmp->getUserName()+" has joined the chat.");
        sendEventToClients(QString("addedClient"), tmp->getPVSClientConnection(), tmp->getUserName() +":"+ tmp->getIp());
    ...
}

Nutzer entfernen:

Auch wenn ein Client nicht mehr vorhanden ist , muss man alle andre Clients davon informieren und das Ereignis in den Chatlog eintragen.

void PVSConnectionManager::onClientRemove(PVSClientConnection* removedConnection)
{
    ...
    ConsoleLog writeChat(tmp->getUserName()+" has left the chat.");
    sendEventToClients("removedClient", removedConnection , tmp->getUserName()+":"+tmp->getIp());
    ...
}

Clients erhalten die Ereignisse:

Wie bereits besprochen werden Clients von Server benachrichtigt jedes mal wenn eine Änderung in der Client-Liste (auf dem Server) vorgenommen wurde. Alle diese Informationen werden auch als Chat-Nachrichten versendet aber anders bearbeitet. Eine Chat-Nachricht dieser Art hat folgendes Gestalt:

PVSMsg
Feld Obj-Typ Inhalt Beschreibung
type enum PVSMSG Signatur der Chat-Nachrichten.
ident QString <Befehl> "clientToAdd", "assignedName" oder "clientToRemove"
msg QString <Leere QString> + ":" + <Username des Clients> + ":" + <IP-Adresse des Clients> Die Ermittlung der IP-Adresse spielt eine große Rolle fürs File sharing.
sndID integer 0 Unbenutzt.

Sobald einen Client ein solche Nachricht bekommt, mach er daraus in der PVSChatClient-Klasse ein PVSChatmsg-Objekt, das als Befehl erkannt und über den Befehl-Dispatcher ("_chatCommandDispatcher") an der Methode "UpdateChatClients" de PVS-Klasse weitergeleitet wird.

void PVS::UpdateChatClients(PVSChatMsg chatCommand)
{
    if(chatCommand.getCommand().compare("clientToAdd") == 0)
    {
        _chat->addClient(chatCommand.getUsername(), chatCommand.getIp());
        emit chat_client_add(chatCommand.getUsername());
    }

    if(chatCommand.getCommand().compare("clientToRemove") == 0)
    {
        _chat->removeClient(chatCommand.getUsername());
        emit chat_client_remove(chatCommand.getUsername());
    }

    if(chatCommand.getCommand().compare("assignedName") == 0)
    {
        _chat->setSource(chatCommand.getUsername());
    }
}

Je nachdem welcher Befehl die Nachricht enthält, können 3 unterschiedliche Änderungen vorgenommen werden. Eine Befehl-Nachricht hat folgendes Gestalt:

PVSChatMsg
Feld Typ Inhalt Beschreibung
_command QString "clientToAdd","clientToRemove" oder "assignedName" Es gibt an was für eine Änderung in der Nutzerliste vorgenommen werden soll.
_username QString <Username> Der zu eintragende/entfernende/überschreibende Benutzername
_ip QString <IP-Adresse> Die zu dem "_username" gehörende IP-Adresse

Zusammenfassung

...

topbar.png - PVS Topbar (312.1 kB) jc, 04/09/2010 05:05 pm

systemtray.png - PVS Systemtray (313.1 kB) jc, 04/09/2010 05:05 pm

chat_window.png - PVS Chat Window (153.3 kB) jc, 04/09/2010 05:05 pm

chat_window_small.png (62.5 kB) jc, 04/12/2010 12:21 pm

systemtray_small.png (112.7 kB) jc, 04/12/2010 12:21 pm

topbar_small.png (112.2 kB) jc, 04/12/2010 12:21 pm