]> git.zarvox.org Git - shareboard.git/commitdiff
Action improvements and connection error clarity.
authorDrew Fisher <drew.m.fisher@gmail.com>
Thu, 7 Oct 2010 03:00:21 +0000 (20:00 -0700)
committerDrew Fisher <drew.m.fisher@gmail.com>
Thu, 7 Oct 2010 03:00:21 +0000 (20:00 -0700)
This patchset reworks the structure of Action and its subclasses.
It also adds polymorphic receiving of some types of actions over
the network.

Lastly, connection errors are now reported to the user.

action.cpp
action.h
connectionmanager.cpp
connectionmanager.h
mainwindow.cpp
mainwindow.h

index fe82a2191851c656029106126fc64b265ed4eb39..ed5df1cb1a9d13d81c11a610e679acbdaa2ef5f7 100644 (file)
@@ -2,14 +2,14 @@
 
 Action::Action() {
        type = INVALID;
-       id = 0;
-       approved = false;
+       mesgID = 0;
+       userID = 0;
 }
 
 Action::Action(Type t) {
        type = t;
-       id = 0;
-       approved = false;
+       mesgID = 0;
+       userID = 0;
 }
 
 Action::~Action() {
@@ -41,8 +41,18 @@ DrawLineAction::DrawLineAction() : Action(Action::DrawLine) {
 DrawLineAction::~DrawLineAction() {
 }
 
+AddImageAction::AddImageAction() {
+}
+AddImageAction::~AddImageAction() {
+}
+
+UserChatAction::UserChatAction() {
+}
+UserChatAction::~UserChatAction() {
+}
+
 QTextStream& operator<<(QTextStream& out, const Action& action) {
-       out << "0 " << action.id << " 0 " << static_cast<quint16>(action.type) ; // mesgID, userID, timestamp, mesgType
+       out << "0 " << action.userID << " " << action.timestamp.toString("yyyy-MM-ddThh:mm:ss.zzz") << " " << static_cast<quint16>(action.type) ; // mesgID, userID, timestamp, mesgType
        switch(action.type) {
                case Action::INVALID: break;
                case Action::UserJoin:
@@ -82,11 +92,7 @@ QTextStream& operator<<(QTextStream& out, const Action& action) {
        return out;
 }
 
-/*QTextStream& operator>>(QTextStream& in, Action& action){
-       quint16 k;
-       in >> k >> action.id >> action.approved >> action.when;
-       action.type = static_cast<Action::Type>(k);
-       return in;
-}*/
-
+// operator>> can't be implemented in this manner since we need to handle
+// different types and operator>> works on a reference to the base class.
+// Thus, I'm pushing this sort of functionality into the connection manager. - Drew
 
index 3f2baf2ff22a8a5c37ede699c29a648f5a56d333..9e25722c85a6552a6a35700e188840c9457910b6 100644 (file)
--- a/action.h
+++ b/action.h
@@ -26,10 +26,9 @@ public:
        virtual ~Action();
 
        Type type;
-       // UUID uuid; // Unique id for this 
-       int id; // Which user does this refer to?
-       bool approved; // Has the server approved this event yet?
-       QDateTime when; // Time at which the server made this event official
+       qint32 mesgID; // Unique id for this 
+       qint32 userID; // Which user does this refer to?
+       QDateTime timestamp; // Time at which the server made this event official
 
 };
 
index 515a46ce8ff321c0de5ad8e79f5fa0fdcc28cf63..db02dfeb33f876b0da10d0240806c2ace9572144 100644 (file)
@@ -10,6 +10,7 @@ ConnectionManager::ConnectionManager(QObject* parent) : QObject(parent) {
        QObject::connect(sock, SIGNAL(connected()), this, SLOT(onConnect()));
        QObject::connect(sock, SIGNAL(disconnected()), this, SLOT(onDisconnect()));
        QObject::connect(sock, SIGNAL(readyRead()), this, SLOT(haveData()));
+       QObject::connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError()));
 }
 
 ConnectionManager::~ConnectionManager() {
@@ -24,22 +25,141 @@ void ConnectionManager::joinServer(QString _username, QString host) {
 }
 
 void ConnectionManager::sendAction(Action* action) {
-       switch(action->type) { // Handle serializing all actions
-               default:
-                       break;
-       }
-       
+       QByteArray output;
+       QTextStream t(&output);
+       t << (*action);
+       qDebug() << "Sending" << output.size() << "bytes for action of type" << action->type;
+       sock->write(output);
 }
 void ConnectionManager::haveData() {
-       data.append(sock->readAll());
-       // Check if we have a full action waiting, if so, dispatch
-       // Event structure:
-       // uint32 num_bytes (we don't support things larger than 4GB, kthx
-       // uint16 type
-       // char approved
-       // QDateTime when
-       // [rest of details]
-       qDebug() << data.size() << " bytes read so far";
+       while(sock->canReadLine()) {
+               QByteArray data = sock->readLine(0); // Read a line, however many bytes it takes
+               QTextStream textstream(&data);
+               qint32 mesgID = -1;
+               qint32 userID = -1;
+               quint16 t = 0; // Type
+               QString timestring;
+               textstream >> mesgID >> userID >> timestring >> t;
+
+               // Validate input
+               QDateTime timestamp = QDateTime::fromString(timestring, "yyyy-MM-ddTHH-mm-ss.zzz");
+               if(mesgID == -1 || userID == -1 || !timestamp.isValid() ) {
+                       qWarning() << "Received invalid message from server; discarding.";
+                       continue;
+               }
+
+               // Abstract factory go!
+               Action::Type type = static_cast<Action::Type>(t);
+               Action* act;
+               switch(type) {
+                       case Action::INVALID: // We should never get an invalid action from the server...
+                               continue;
+                       case Action::UserJoin:
+                               {
+                               act = new UserJoinAction();
+                               UserJoinAction* action = static_cast<UserJoinAction*>(act);
+                               QString username;
+                               textstream >> username;
+                               if(textstream.status() != QTextStream::Ok) {
+                                       qWarning() << "Got invalid username from server :(";
+                                       delete action;
+                                       continue;
+                               }
+                               action->username = username;
+                               action->mesgID = mesgID;
+                               action->userID = userID;
+                               action->timestamp = timestamp;
+                               break;
+                               }
+                       case Action::UserPart:
+                               {
+                               act = new UserPartAction();
+                               UserPartAction* action = static_cast<UserPartAction*>(act);
+                               action->mesgID = mesgID;
+                               action->userID = userID;
+                               action->timestamp = timestamp;
+                               break;
+                               }
+                       case Action::MouseMove:
+                               {
+                               act = new MouseMoveAction();
+                               qreal x = 0;
+                               qreal y = 0;
+                               textstream >> x >> y;
+                               // Ignore invalid mouse positions; replace with 0,0
+                               MouseMoveAction* action = static_cast<MouseMoveAction*>(act);
+                               action->pos = QPointF(x,y);
+                               action->mesgID = mesgID;
+                               action->userID = userID;
+                               action->timestamp = timestamp;
+                               break;
+                               }
+                       case Action::DrawLine:
+                               {
+                               /*
+                               act = new DrawLineAction();
+                               action = static_cast<DrawLineAction*>(act);
+                               int red = 0;
+                               int green = 0;
+                               int blue = 0;
+                               int width = 1;
+                               textstream >> red >> green >> blue >> width;
+                               if(textstream.status() != QTextStream::Ok){
+                                       qWarning() << "Received invalid line data from server :(";
+                                       delete action;
+                                       continue;
+                               }
+                               do {
+                                       // some stuff with the points
+                               } while(textstream.status() == QTextStream::Ok);
+                               action->color = QColor::fromRgb(red, green, blue);
+                               action->width = width;
+                               action->mesgID = mesgID;
+                               action->userID = userID;
+                               action->timestamp = timestamp;
+                               */
+                               break;
+                               }
+                       case Action::AddImage:
+                               {
+                               /*
+                               act = new AddImageAction();
+                               AddImageAction* action = static_cast<AddImageAction*>(act);
+                               // do somethin with the top-left point
+                               // handle reading image data as base64-encoded binary, bleah
+                               action->mesgID = mesgID;
+                               action->userID = userID;
+                               action->timestamp = timestamp;
+                               */
+                               break;
+                               }
+                       case Action::UserChat:
+                               {
+                               act = new UserChatAction();
+                               UserChatAction* action = static_cast<UserChatAction*>(act);
+                               QString chat;
+                               textstream >> chat;
+                               if(textstream.status() != QTextStream::Ok) {
+                                       qWarning() << "Got invalid text chat from server :(";
+                                       delete action;
+                                       continue;
+                               }
+                               action->mesgID = mesgID;
+                               action->userID = userID;
+                               action->timestamp = timestamp;
+                               action->text = chat;
+                               break;
+                               }
+                       default:
+                               qWarning() << "Received invalid type from server :(";
+                               continue;
+               }
+               Q_ASSERT(act != NULL);
+
+               // HistoryManager::instance()->newAction(action);
+
+               qDebug() << "Dispatched action with type " << act->type << " that was " << data.size() << " bytes long";
+       }
 }
 
 void ConnectionManager::onConnect() {
@@ -53,3 +173,9 @@ void ConnectionManager::onDisconnect() {
        qDebug() << "Disconnected";
        emit disconnected();
 }
+
+void ConnectionManager::onError() {
+       QString e = sock->errorString();
+       qDebug() << "connection error: " << e;
+       emit error(e);
+}
index 9b1e37bbcbcb60e9af56887266fe6072d9fe4d7f..74f981fa3f37ef4dd9e510c15a24938174aa038f 100644 (file)
@@ -5,6 +5,7 @@
 #include <QByteArray>
 #include <QString>
 #include <QTextStream>
+#include <QAbstractSocket>
 
 class Action;
 class QTcpSocket;
@@ -19,12 +20,14 @@ class ConnectionManager : public QObject{
                //void actionRecieved(Action* act); // act is freed by recipient of signal
                void connected();
                void disconnected();
+               void error(QString e);
        public slots:
                void joinServer(QString _username, QString host);
                void sendAction(Action* action);
+               void onError();
        private:
                QString username;
-               QByteArray data;
+               //QByteArray data;
                QTcpSocket* sock;
                QTextStream* textStream;
        private slots:
index d9f1848e19e0f0edbe2bd7aff834ce95b0cbe7e5..872d247e051863a203ff145ec3f634487d3210c3 100644 (file)
@@ -23,6 +23,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) {
        QObject::connect(board, SIGNAL(connectToServer(QString, QString)), connMan, SLOT(joinServer(QString, QString)));
        QObject::connect(connMan, SIGNAL(connected()),    this, SLOT(switchToBoard()));
        QObject::connect(connMan, SIGNAL(disconnected()), this, SLOT(switchToConnect()));
+       QObject::connect(connMan, SIGNAL(error(QString)), this, SLOT(showError(QString)));
 
        statusBar()->showMessage("Ready");
 }
@@ -73,6 +74,10 @@ void MainWindow::switchToConnect() {
        statusBar()->showMessage(QString("Switched to connection prompt"));
 }
 
+void MainWindow::showError(QString error) {
+       statusBar()->showMessage(error);
+}
+
 void MainWindow::createActions() {
        //joinAction = new QAction("Joi&n a board online", this);
        loadPastAction = new QAction("&Open a board", this);
index e5dff43ac5a6666ee282a10fec55b515f0cb3e44..8f06f9891edfe28294ada3ba338056f174eb92fe 100644 (file)
@@ -21,6 +21,7 @@ public slots:
        void quit();
        void switchToBoard();
        void switchToConnect();
+       void showError(QString error);
 private:
        void createActions();
        void createMenus();