]> git.zarvox.org Git - shareboard.git/blob - connectionmanager.cpp
Implement image insertion and placement, tool selection, and eraser.
[shareboard.git] / connectionmanager.cpp
1 #include "connectionmanager.h"
2 #include <QDebug>
3 #include <QTcpSocket>
4 #include <QTextStream>
5 #include "action.h"
6 #include "base64.h"
7 #include "shareboard.h"
8
9 ConnectionManager::ConnectionManager(QObject* parent) : QObject(parent) {
10         sock = new QTcpSocket();
11         textStream = new QTextStream(sock);
12         QObject::connect(sock, SIGNAL(connected()), this, SLOT(onConnect()));
13         QObject::connect(sock, SIGNAL(disconnected()), this, SLOT(onDisconnect()));
14         QObject::connect(sock, SIGNAL(readyRead()), this, SLOT(haveData()));
15         QObject::connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError()));
16 }
17
18 ConnectionManager::~ConnectionManager() {
19         if (sock) delete sock;
20 }
21
22 void ConnectionManager::setTarget(Shareboard* t) {
23         board = t;
24 }
25
26 void ConnectionManager::joinServer(QString _username, QString host) {
27         username = _username;
28         quint16 port = 4260;
29         sock->connectToHost(host, port);
30         qDebug() << "Connecting to " << host << "as " << _username;
31 }
32
33 void ConnectionManager::sendAction(Action* action) {
34         QByteArray output;
35         QTextStream t(&output);
36         t << (*action);
37         t.flush();
38         qDebug() << "Sending" << output.size() << "bytes for action of type" << action->type;
39         sock->write(output);
40 }
41 void ConnectionManager::haveData() {
42         while(sock->canReadLine()) {
43                 QByteArray data = sock->readLine(0); // Read a line, however many bytes it takes
44                 QTextStream textstream(&data);
45                 qint32 mesgID = -1;
46                 qint32 userID = -1;
47                 quint16 t = 0; // Type
48                 QString timestring;
49                 textstream >> mesgID >> userID >> timestring >> t;
50                 /*qDebug() << "Read line:";
51                 qDebug() << "\tmesgID: "<< mesgID;
52                 qDebug() << "\tuserID: "<< userID;
53                 qDebug() << "\ttime  : "<< timestring;
54                 qDebug() << "\ttype  : "<< t;*/
55
56                 // Validate input
57                 QDateTime timestamp = QDateTime::fromString(timestring, "yyyy-MM-ddTHH:mm:ss.zzz");
58                 if(mesgID == -1 || userID == -1 || !timestamp.isValid() ) {
59                         qWarning() << "Received invalid message from server; discarding.";
60                         continue;
61                 }
62
63                 // Abstract factory go!
64                 Action::Type type = static_cast<Action::Type>(t);
65                 Action* act;
66                 switch(type) {
67                         case Action::INVALID: // We should never get an invalid action from the server...
68                                 continue;
69                         case Action::UserJoin:
70                                 {
71                                 act = new UserJoinAction();
72                                 UserJoinAction* action = static_cast<UserJoinAction*>(act);
73                                 QString username;
74                                 textstream >> username;
75                                 if(textstream.status() != QTextStream::Ok) {
76                                         qWarning() << "Got invalid username from server :(";
77                                         delete action;
78                                         continue;
79                                 }
80                                 action->username = username;
81                                 action->mesgID = mesgID;
82                                 action->userID = userID;
83                                 action->timestamp = timestamp;
84                                 qDebug() << "Update: got UserJoin:" << username << "joined";
85                                 break;
86                                 }
87                         case Action::UserPart:
88                                 {
89                                 act = new UserPartAction();
90                                 UserPartAction* action = static_cast<UserPartAction*>(act);
91                                 action->mesgID = mesgID;
92                                 action->userID = userID;
93                                 action->timestamp = timestamp;
94                                 break;
95                                 }
96                         case Action::MouseMove:
97                                 {
98                                 act = new MouseMoveAction();
99                                 qreal x = 0;
100                                 qreal y = 0;
101                                 textstream >> x >> y;
102                                 // Ignore invalid mouse positions; replace with 0,0
103                                 MouseMoveAction* action = static_cast<MouseMoveAction*>(act);
104                                 action->pos = QPointF(x,y);
105                                 action->mesgID = mesgID;
106                                 action->userID = userID;
107                                 action->timestamp = timestamp;
108                                 break;
109                                 }
110                         case Action::DrawLine:
111                                 {
112                                 act = new DrawLineAction();
113                                 DrawLineAction* action = static_cast<DrawLineAction*>(act);
114                                 int red = 0;
115                                 int green = 0;
116                                 int blue = 0;
117                                 int width = 1;
118                                 textstream >> red >> green >> blue >> width;
119                                 if(textstream.status() != QTextStream::Ok){
120                                         qWarning() << "Received invalid line data from server :(";
121                                         delete action;
122                                         continue;
123                                 }
124                                 do {
125                                         qreal x = 0;
126                                         qreal y = 0;
127                                         textstream >> x >> y;
128                                         action->points.append(QPointF(x,y));
129                                         // some stuff with the points
130                                 } while(textstream.status() == QTextStream::Ok);
131                                 action->color = QColor::fromRgb(red, green, blue);
132                                 action->width = width;
133                                 action->mesgID = mesgID;
134                                 action->userID = userID;
135                                 action->timestamp = timestamp;
136                                 break;
137                                 }
138                         case Action::AddImage:
139                                 {
140                                 qDebug() << "Sending AddImage action!";
141                                 act = new AddImageAction();
142                                 AddImageAction* action = static_cast<AddImageAction*>(act);
143                                 qreal x = 0;
144                                 qreal y = 0;
145                                 textstream >> x >> y;
146                                 action->topLeft = QPointF(x,y);
147                                 // handle reading image data as base64-encoded binary, bleah
148                                 QString im;
149                                 textstream >> im;
150                                 // im is a base64-encoded binary string.
151                                 QByteArray ba = fromBase64(im); // Convert back to binary data
152                                 action->image.loadFromData(ba, "PNG");
153                                 action->mesgID = mesgID;
154                                 action->userID = userID;
155                                 action->timestamp = timestamp;
156                                 break;
157                                 }
158                         case Action::UserChat:
159                                 {
160                                 act = new UserChatAction();
161                                 UserChatAction* action = static_cast<UserChatAction*>(act);
162                                 QString chat;
163                                 textstream >> chat;
164                                 if(textstream.status() != QTextStream::Ok) {
165                                         qWarning() << "Got invalid text chat from server :(";
166                                         delete action;
167                                         continue;
168                                 }
169                                 action->mesgID = mesgID;
170                                 action->userID = userID;
171                                 action->timestamp = timestamp;
172                                 action->text = chat;
173                                 break;
174                                 }
175                         case Action::UserSynced:
176                                 {
177                                 board->setUserID(userID);
178                                 qDebug() << "User is synced :)";
179                                 continue;
180                                 }
181                                 break;
182                         case Action::ClearBoard:
183                                 {
184                                 act = new ClearBoardAction();
185                                 ClearBoardAction* action = static_cast<ClearBoardAction*>(act);
186                                 action->mesgID = mesgID;
187                                 action->userID = userID;
188                                 action->timestamp = timestamp;
189                                 }
190                                 break;
191                         default:
192                                 qWarning() << "Received invalid type from server :(";
193                                 continue;
194                 }
195                 Q_ASSERT(act != NULL);
196
197                 board->postAction(act);
198
199                 //qDebug() << "Dispatched action with type " << act->type << " that was " << data.size() << " bytes long";
200         }
201 }
202
203 void ConnectionManager::onConnect() {
204         qDebug() << "connection established";
205         emit connected();
206         (*textStream) << "0 0 0 1 " << username << endl;
207         qDebug() << "sent JoinAction";
208 }
209
210 void ConnectionManager::onDisconnect() {
211         qDebug() << "Disconnected";
212         emit disconnected();
213 }
214
215 void ConnectionManager::onError() {
216         QString e = sock->errorString();
217         qDebug() << "connection error: " << e;
218         emit error(e);
219 }