chatroom.cpp 6.17 KB
#include "chatroom.h"
#include "ui_chatroom.h"

list<QString> sendQueue;

std::mutex myMutex;

std::mutex msgMutex;
unique_lock<std::mutex>* msgLock;

std::condition_variable msgListNotEmpty;

Chatroom::Chatroom(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Chatroom)
{
    ui->setupUi(this);
    QList<int> chatSizes;
    QList<int> splitSizes;
    chatSizes.push_front(ui->chatText->height());
    chatSizes.push_front(100);
    splitSizes.push_front(ui->chatWindow->width());
    splitSizes.push_front(200);
    ui->chatSplitter->setSizes(chatSizes);
    ui->windowSplitter->setSizes(splitSizes);
    connected = false;
    msgLock = new unique_lock<std::mutex>(msgMutex,std::defer_lock);
    send = NULL;
    recv = NULL;

    connect(ui->actionConnect,SIGNAL(triggered()),this,SLOT(startSession()));
    connect(ui->actionExit,SIGNAL(triggered()),this,SLOT(finish()));
    connect(this,SIGNAL(threadsFinished(bool)),this,SLOT(finishThreads(bool)));
    connect(ui->inputText,SIGNAL(msgReady()),this,SLOT(sendMsg()));
    connect(ui->actionDisconnect,SIGNAL(triggered()),this,SLOT(disconnectChatroom()));
    connect(ui->sendButton,SIGNAL(clicked()),this,SLOT(sendMsg()));
    connect(this,SIGNAL(messagesToPrint()),this,SLOT(printMsg()));
}

void sendThread(Socket* s, Chatroom* chat)
{
    string send;
    while(chat->getConnected())
    {
        while(sendQueue.empty())
        {
            msgLock->lock();
            msgListNotEmpty.wait(*msgLock);
            if(!chat->getConnected())
            {
                return;
            }
            msgLock->unlock();
        }
        msgLock->lock();
        send = sendQueue.front().toStdString();
        sendQueue.pop_front();
        try
        {
            if(send[0] == '@')
            {
                send = '1' + send;
            }
            else
            {
                send = '0' + send;
            }
            *s << send;
            msgLock->unlock();
            send = send.substr(1);
            if(send == "/disconnect" || send == "/exit")
            {
                break;
            }
            chat->putMsgToPrintQueue(chat->getNickname().toStdString().append(": ").append(send));
        }
        catch(SocketException& e)
        {
            cout << e.description() << endl;
        }
    }
    cout << "sendThread finished" << endl;
}

void recvThread(Socket* s, Chatroom* chat)
{
    string recv;
    while(true)
    {
        try
        {
            *s >> recv;
            if(recv[0] == '1')
            {
                recv = recv.substr(1);
                chat->relayMsg(recv);
                continue;
            }
            else if(recv[0] == '0')
            {
                recv = recv.substr(1);
            }
        }
        catch(SocketException &e)
        {
            chat->setConnected(false);
            cout << e.description() << endl;
            msgListNotEmpty.notify_all();
            emit chat->threadsFinished(false);
            break;
        }
        if(recv == "DISC_OK")
        {
            cout << "Disconnecting" << endl;
            chat->setConnected(false);
            msgListNotEmpty.notify_all();
            emit chat->threadsFinished(false);
            break;
        }
        else if(recv == "EXIT_OK")
        {
            cout << "Exiting" << endl;
            chat->setConnected(false);
            msgListNotEmpty.notify_all();
            emit chat->threadsFinished(true);
            break;
        }
        else
        {
            chat->putMsgToPrintQueue(recv);
        }
    }
    cout << "recvThread finished" << endl;
}

bool Chatroom::getConnected()
{
    myMutex.lock();
    bool val = connected;
    myMutex.unlock();
    return val;
}

void Chatroom::setConnected(bool status)
{
    myMutex.lock();
    connected = status;
    myMutex.unlock();
}

void Chatroom::putMsgToPrintQueue(string &msg)
{
    printQueue.push_back(msg);
    emit messagesToPrint();
}

string Chatroom::getSender(string& msg)
{
   return msg.substr(5,msg.find(':')-5);
}

void Chatroom::relayMsg(string& msg)
{
    string sender = getSender(msg);
    map<string,ChatWindow>::iterator it = activeChats.begin();
    if(activeChats.find(sender) == activeChats.end())
    {
        //LAUNCH new windowchat
    }
    it = activeChats.find(sender);
    it->second.printMsg(msg);
}

void Chatroom::printMsg()
{
    while(!printQueue.empty())
    {
        string msg = printQueue.front();
        ui->chatText->printMsg(msg);
        printQueue.pop_front();
    }
}

void Chatroom::putMsgToSendQueue(QString& msg)
{
    msgMutex.lock();
    sendQueue.push_back(msg);
    msgMutex.unlock();
    msgListNotEmpty.notify_all();
}

void Chatroom::setNickname(QString nick)
{
    nickname = nick;
}

QString Chatroom::getNickname()
{
    return nickname;
}

void Chatroom::startSession()
{
    LoginScreen login(&s,this);
    login.exec();
    int result = login.result();
    if(result == QDialog::Accepted)
    {
        ui->inputText->setReadOnly(false);
    }
    else if(result == QDialog::Rejected)
    {
        return;
    }
    connected = true;
    ui->chatText->printServerMsg("Connected to chatroom");
    recv = new std::thread(recvThread,&s,this);
    send = new std::thread(sendThread,&s,this);
}

void Chatroom::sendMsg()
{
    QString msg = ui->inputText->toPlainText();
    ui->inputText->clear();
    putMsgToSendQueue(msg);
}

void Chatroom::finish()
{
    if(recv == NULL && send == NULL)
    {
        ui->inputText->setReadOnly(true);
        ui->chatText->printServerMsg("Disconnected");
        this->close();
    }
    msgMutex.lock();
    sendQueue.clear();
    sendQueue.push_back("/exit");
    msgMutex.unlock();
    msgListNotEmpty.notify_all();
}

void Chatroom::disconnectChatroom()
{
    msgMutex.lock();
    sendQueue.clear();
    sendQueue.push_back("/disconnect");
    msgMutex.unlock();
    msgListNotEmpty.notify_all();
}

void Chatroom::finishThreads(bool exit)
{
    myMutex.lock();
    ui->inputText->setReadOnly(true);
    recv->join();
    send->join();
    myMutex.unlock();
    ui->chatText->printServerMsg("Disconnected");
    send = NULL;
    recv = NULL;
    if(exit)
    {
        this->close();
    }
}

Chatroom::~Chatroom()
{
    delete msgLock;
    delete recv;
    delete send;
    delete ui;
}