ArnLib  4.0.x
Active Registry Network
Chat Demo

Demonstration with a simple chat program. It consists of a server and a client part. After starting the server, any number of clients can be started.

This demo is focused on the Service API (RPC) functionalty of ArnLib. Slots are remotely called from clients to server and the other way back. All is done with standard function calls without any visual serializing.

It's also a demo of Discover Remote, althou client side is as simple as possible without any remote control.

Chat Server** ChatSapi.hpp, MainWindow.hpp, MainWindow.cpp, main.cpp

Chat Client** MainWindow.hpp, MainWindow.cpp, main.cpp

Chat Server


ChatSapi.hpp

#ifndef CHATSAPI_HPP
#define CHATSAPI_HPP
class ChatSapi : public ArnSapi
{
Q_OBJECT
public:
explicit ChatSapi( QObject* parent = 0) : ArnSapi( parent) {}
signals:
no_queue void pv_list();
void pv_newMsg( QString name, QString msg);
void pv_infoQ();
void rq_updateMsg( int seq, QString name, QString msg);
void rq_info( QString name, QString ver);
};
#endif // CHATSAPI_HPP

MainWindow.hpp

#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP
#include "ChatSapi.hpp"
#include <QTimer>
#include <QStringList>
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow( QWidget *parent = 0);
~MainWindow();
private slots:
void doNewSession( QString path);
void doSessionClosed();
void doUpdateView();
void on_shutDownButton_clicked();
void doTimeUpdate();
void sapiList();
void sapiNewMsg( QString name, QString msg);
void sapiInfoQ();
void sapiDefault( const QByteArray& data);
private:
Ui::MainWindow *_ui;
QStringList _chatNameList;
QStringList _chatMsgList;
QTimer _timer1s;
int _connectCount;
ArnItem _arnTime;
ArnServer* _server;
ChatSapi* _commonSapi;
ArnDiscoverRemote* _discoverRemote;
};
#endif // MAINWINDOW_HPP

MainWindow.cpp

#include "MainWindow.hpp"
#include "tmp/ui_MainWindow.h"
#include <QTime>
#include <QDebug>
MainWindow::MainWindow( QWidget *parent) :
QMainWindow( parent, Qt::CustomizeWindowHint | Qt::WindowMinimizeButtonHint),
_ui( new Ui::MainWindow)
{
_ui->setupUi( this);
_connectCount = 0;
doUpdateView();
_timer1s.start(1000);
connect( &_timer1s, SIGNAL(timeout()), this, SLOT(doTimeUpdate()));
_server = new ArnServer( ArnServer::Type::NetSync, this);
_server->start(0); // Start server on dynamic port
_discoverRemote = new ArnDiscoverRemote( this);
_discoverRemote->setService("Demo Chat Server");
_discoverRemote->addGroup("arndemo/chat");
_discoverRemote->addCustomProperty("ChatProtoVer", "1.0");
_discoverRemote->startUseServer( _server);
_arnTime.open("//Chat/Time/value");
typedef ArnSapi::Mode SMode;
_commonSapi = new ChatSapi( this);
_commonSapi->open("//Chat/Pipes/pipeCommon", SMode::Provider | SMode::UseDefaultCall);
_commonSapi->batchConnectTo( this, "sapi");
ArnItem* arnPipes = new ArnItem("//Chat/Pipes/", this);
connect( arnPipes, SIGNAL(arnItemCreated(QString)), this, SLOT(doNewSession(QString)));
}
MainWindow::~MainWindow()
{
delete _ui;
}
void MainWindow::doNewSession( QString path)
{
if (!Arn::isProviderPath( path)) return; // Only provider pipe is used
typedef ArnSapi::Mode SMode;
ChatSapi* soleSapi = new ChatSapi( this);
soleSapi->open( path, SMode::Provider | SMode::UseDefaultCall);
soleSapi->batchConnectTo( this, "sapi");
connect( soleSapi, SIGNAL(pipeClosed()), soleSapi, SLOT(deleteLater()));
connect( soleSapi, SIGNAL(pipeClosed()), this, SLOT(doSessionClosed()));
++_connectCount;
doUpdateView();
}
void MainWindow::doSessionClosed()
{
--_connectCount;
doUpdateView();
}
void MainWindow::doUpdateView()
{
_ui->connectCount->setText( QString::number( _connectCount));
}
void MainWindow::on_shutDownButton_clicked()
{
qWarning() << "About to shut down.";
delete _discoverRemote; // Must be deleted while still in the main eventloop
_discoverRemote = 0;
QApplication::quit();
}
void MainWindow::doTimeUpdate()
{
_arnTime = QTime::currentTime().toString();
}
void MainWindow::sapiList()
{
ChatSapi* sapi = qobject_cast<ChatSapi*>( sender());
Q_ASSERT(sapi);
for (int i = 0; i < _chatNameList.size(); ++i) {
sapi->rq_updateMsg( i, _chatNameList.at(i), _chatMsgList.at(i));
}
}
void MainWindow::sapiNewMsg( QString name, QString msg)
{
_chatNameList += name;
_chatMsgList += msg;
int seq = _chatNameList.size() - 1;
_commonSapi->rq_updateMsg( seq, name, msg);
}
void MainWindow::sapiInfoQ()
{
ChatSapi* sapi = qobject_cast<ChatSapi*>( sender());
Q_ASSERT(sapi);
sapi->rq_info("Arn Chat Demo", "1.2");
}
void MainWindow::sapiDefault( const QByteArray& data)
{
ChatSapi* sapi = qobject_cast<ChatSapi*>( sender());
Q_ASSERT(sapi);
qDebug() << "chatDefault:" << data;
sapi->sendText("Chat Sapi: Can't find method, use $help.");
}

main.cpp

#include "MainWindow.hpp"
#include <QApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

Chat Client

MainWindow.hpp

#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP
#include "../ArnDemoChatServer/ChatSapi.hpp"
#include <QMainWindow>
#include <QVector>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow( QWidget *parent = 0);
~MainWindow();
private slots:
void doSendLine();
void doTimeUpdate( QString timeStr);
void sapiUpdateMsg( int seq, QString name, QString msg);
void sapiInfo( QString name, QString ver);
private:
Ui::MainWindow *_ui;
QVector<QString> _chatNameList;
QVector<QString> _chatMsgList;
ArnClient _arnClient;
ChatSapi _commonSapi;
ChatSapi _soleSapi;
ArnItem _arnTime;
};
#endif // MAINWINDOW_HPP

MainWindow.cpp

#include "MainWindow.hpp"
#include "tmp/ui_MainWindow.h"
MainWindow::MainWindow( QWidget* parent) :
QMainWindow( parent),
_ui( new Ui::MainWindow)
{
_ui->setupUi( this);
_ui->userEdit->setFocus();
connect( _ui->lineEdit, SIGNAL(returnPressed()), this, SLOT(doSendLine()));
_arnClient.addMountPoint("//");
_arnClient.setAutoConnect(true);
ArnDiscoverConnector* connector = new ArnDiscoverConnector( _arnClient, "DemoChat");
connector->setResolver( new ArnDiscoverResolver());
connector->setService("Demo Chat Server");
connector->start();
_arnTime.open("//Chat/Time/value");
connect( &_arnTime, SIGNAL(changed(QString)), this, SLOT(doTimeUpdate(QString)));
_commonSapi.open("//Chat/Pipes/pipeCommon");
_commonSapi.batchConnectTo( this, "sapi");
_soleSapi.open("//Chat/Pipes/pipe", ArnSapi::Mode::UuidAutoDestroy);
_soleSapi.batchConnectTo( this, "sapi");
_soleSapi.pv_infoQ();
_soleSapi.pv_list();
}
MainWindow::~MainWindow()
{
delete _ui;
}
void MainWindow::doTimeUpdate( QString timeStr)
{
_ui->timeEdit->setTime( QTime::fromString( timeStr));
}
void MainWindow::doSendLine()
{
QString myName = _ui->userEdit->text();
QString line = _ui->lineEdit->text();
_ui->lineEdit->clear();
_soleSapi.pv_newMsg( myName, line);
}
void MainWindow::sapiUpdateMsg( int seq, QString name, QString msg)
{
if (seq >= _chatNameList.size()) {
_chatNameList.resize( seq + 1);
_chatMsgList.resize( seq + 1);
}
_chatNameList[ seq] = name;
_chatMsgList[ seq] = msg;
QString text;
for (int i = 0; i < _chatNameList.size(); ++i) {
text += _chatNameList.at(i) + ": " + _chatMsgList.at(i) + "\n";
}
_ui->textEdit->setText( text);
}
void MainWindow::sapiInfo( QString name, QString ver)
{
_ui->appNameLabel->setText( name);
_ui->verLabel->setText( ver);
}

main.cpp

#include "MainWindow.hpp"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

Pictures

Arn_chat_demo_1.png