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() {
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:
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
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() {
}
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() {
qDebug() << "Disconnected";
emit disconnected();
}
+
+void ConnectionManager::onError() {
+ QString e = sock->errorString();
+ qDebug() << "connection error: " << e;
+ emit error(e);
+}
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");
}
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);