Improved socket read/write
[dashstudio.git] / src / shell / networkhandler.cpp
blob400654ce2fb1f21dd578a14b432f0f67971665a5
1 /***************************************************************************
2 * Copyright (C) 2007 by David Cuadrado *
3 * krawek@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include "networkhandler.h"
23 // Qt
24 #include <QXmlStreamReader>
25 #include <QXmlStreamWriter>
26 #include <QTemporaryFile>
28 // DCore
29 #include <dcore/debug.h>
31 // DGui
32 #include <dgui/osd.h>
34 // YAMF
35 #include <yamf/model/command/processor.h>
36 #include <yamf/model/command/base.h>
38 // Dash
39 #include "dash/project.h"
41 #include "dash/network/socket.h"
42 #include "dash/network/filereceiver.h"
44 #include "dash/network/package/newproject.h"
45 #include "dash/network/package/connect.h"
46 #include "dash/network/package/listprojects.h"
47 #include "dash/network/package/openproject.h"
49 #include "dash/network/parser/ackparser.h"
51 #include "dash/network/parser/projectlistparser.h"
52 #include "dash/network/parser/projectparser.h"
54 #include "projectmanager.h"
56 #include "ui_displayprojects.h"
58 #include "comm/comm.h"
59 #include "comm/chatwindow.h"
61 NetworkHandler::NetworkHandler(ProjectManager *manager, QObject *parent) : QObject(parent), m_manager(manager), m_socket(new Dash::Network::Socket), m_dispatcher(new Dash::Network::Package::Dispatcher), m_waitingResponse(false)
63 m_processor = new YAMF::Command::Processor(manager->project());
64 m_socket->addObserver(this);
65 m_receiver = new Dash::Network::FileReceiver;
66 m_socket->addObserver(m_receiver);
68 m_comm = new Comm(this);
69 addObserver(m_comm);
71 connect(m_receiver, SIGNAL(finished(const QString &)), this, SLOT(onReceiverFinished(const QString &)));
75 NetworkHandler::~NetworkHandler()
77 delete m_dispatcher;
78 delete m_socket;
79 delete m_receiver;
80 delete m_comm;
83 void NetworkHandler::connectToHost(const QString &host, quint16 port, const QString &login, const QString &password)
85 m_commands.clear();
87 m_socket->connectToHost(host, port);
88 Dash::Network::Package::Connect cnx(login, password, 0);
89 m_socket->send(cnx.toString().toLocal8Bit());
92 bool NetworkHandler::send(const QString &xml)
94 QString tosend;
95 if( !m_sign.isEmpty() )
97 QXmlStreamReader reader(xml);
98 QXmlStreamWriter writer(&tosend);
100 bool isRoot = false;
101 while( ! reader.atEnd() )
103 reader.readNext();
105 writer.writeCurrentToken(reader);
106 if( reader.tokenType() == QXmlStreamReader::StartElement && !isRoot )
108 dfDebug << "Writing sing on " << reader.name().toString();
109 writer.writeAttribute("sign", m_sign);
110 isRoot = true;
114 else
116 tosend = xml;
119 dfDebug << "SENDING: " << tosend.left(100) << " SIGN IS : " << m_sign;
121 return m_socket->send(tosend.toLocal8Bit());
124 void NetworkHandler::addObserver(Dash::Network::Package::Observer *observer)
126 m_dispatcher->addObserver(observer);
129 void NetworkHandler::removeObserver(Dash::Network::Package::Observer *observer)
131 m_dispatcher->removeObserver(observer);
134 void NetworkHandler::execute(YAMF::Command::Base *cmd)
136 bool isEmpty = m_commands.isEmpty();
138 dfDebug << "ENCOLANDO: " << cmd->toXml().left(100);
140 m_commands.enqueue(cmd);
141 if( isEmpty && !m_waitingResponse && !m_sign.isEmpty() )
143 m_waitingResponse = send(cmd->toXml());
145 if( !m_waitingResponse)
147 m_commands.dequeue();
152 void NetworkHandler::newProject(const ProjectParams *params)
154 Dash::Network::Package::NewProject newProjectPackage(params->projectName, params->author, params->description);
155 this->send(newProjectPackage.toString());
158 void NetworkHandler::openProject()
160 Dash::Network::Package::ListProjects list;
161 this->send(list.toString());
164 void NetworkHandler::openProject(const QString &projectName)
166 m_currentPackage = "openproject";
167 Dash::Network::Package::OpenProject project(projectName);
168 this->send(project.toString());
171 bool NetworkHandler::isOpen() const
173 return m_socket->state() == QAbstractSocket::ConnectedState;
176 bool NetworkHandler::isValid() const
178 return this->isOpen() && !m_sign.isEmpty();
181 void NetworkHandler::showChatWindow()
183 if( isValid() )
185 m_comm->chatWindow()->show();
187 else
189 DGui::Osd::self()->display(tr("You are not authenticated."), DGui::Osd::Error );
193 void NetworkHandler::readed(const QString &txt)
195 dfDebug << "READED: " << txt.left(100);
197 QString root;
200 QXmlStreamReader reader(txt);
201 while( !reader.atEnd() )
203 if( reader.readNext() == QXmlStreamReader::StartElement )
205 root = reader.name().toString();
206 break;
210 if( root.isEmpty() )
212 dWarning() << "Invalid package: " << txt.left(100)+"...."+txt.right(100);
213 dWarning() << "Error was: " << reader.errorString();
218 if( !root.isEmpty() )
220 if( root == "ack" )
222 Dash::Network::Parser::AckParser parser;
223 if( parser.parse(txt) )
225 m_sign = parser.sign();
226 DGui::Osd::self()->display(parser.motd(), DGui::Osd::Info);
228 if( !m_commands.isEmpty() )
230 m_waitingResponse = true;
231 send(m_commands.first()->toXml());
235 else if( root == "command" )
237 D_SHOW_VAR(m_commands.size());
238 bool executed = false;
240 if( m_waitingResponse && !m_commands.isEmpty() )
242 m_waitingResponse = false;
244 QXmlStreamReader reader(txt);
246 reader.readNext();
247 reader.readNext();
248 QString sign = reader.attributes().value("sign").toString();
250 if( sign == m_sign )
252 m_manager->setLocal(true);
253 m_commands.dequeue()->redo(); // FIXME: add to stack?
254 m_manager->setLocal(false);
256 executed = true;
258 if( ! m_commands.isEmpty() )
260 m_waitingResponse = true;
261 send(m_commands.first()->toXml());
266 if( !executed ) // External command
268 m_manager->setLocal(true);
269 m_processor->execute(txt);
270 m_manager->setLocal(false);
273 else if( root == "projectlist" )
275 Dash::Network::Parser::ProjectList projectList;
277 if( projectList.parse(txt) )
279 QDialog choose;
280 Ui::DisplayProjects ui;
281 ui.setupUi(&choose);
283 foreach( Dash::Network::Parser::ProjectList::Project p, projectList.projects())
285 QTreeWidgetItem *item = new QTreeWidgetItem(ui.projects);
286 item->setText(0, p.name);
287 item->setText(1, p.author);
288 item->setText(2, p.description);
291 if( choose.exec() == QDialog::Accepted )
293 if( QTreeWidgetItem *ci = ui.projects->currentItem() )
295 QString projectName = ci->text(0);
297 openProject(projectName);
301 else
303 DGui::Osd::self()->display(QObject::tr("Error displaying the project list"), DGui::Osd::Error);
306 else if( root == "project" ) // FIXME: Remove
308 qFatal("OOops!");
309 Dash::Network::Parser::Project projectParser;
311 QTemporaryFile file;
313 if( projectParser.parse(txt) && file.open() )
315 file.write(projectParser.projectData());
316 file.flush();
318 m_manager->setLocal(true);
319 m_manager->loadProject(file.fileName());
320 m_manager->setLocal(false);
322 else
324 DGui::Osd::self()->display(QObject::tr("Error loading project"), DGui::Osd::Error);
327 else if( root == "transfer" )
329 QXmlStreamReader reader(txt);
330 while(! reader.atEnd() )
332 if( reader.readNext() == QXmlStreamReader::StartElement )
334 int bytes = reader.attributes().value("bytes").toString().toInt();
336 m_socket->setFormat(Dash::Network::Socket::Binary);
337 m_receiver->start(bytes);
341 else if( root == "connected" )
343 QXmlStreamReader reader(txt);
344 QStringList logins;
345 while(! reader.atEnd() )
347 if( reader.readNext() == QXmlStreamReader::StartElement )
349 if(reader.name() == "user")
351 logins << reader.attributes().value("login").toString();
355 m_comm->chatWindow()->addUsers(logins);
357 else if( root == "disconnected" )
359 QString login;
361 QXmlStreamReader reader(txt);
362 while(! reader.atEnd() )
364 if( reader.readNext() == QXmlStreamReader::StartElement )
366 if(reader.name() == "user")
368 login = reader.attributes().value("login").toString();
369 break;
374 m_comm->chatWindow()->removeUser(login);
376 else
378 m_dispatcher->addSource(root, txt);
379 m_dispatcher->process();
384 void NetworkHandler::dataReaded(const QByteArray &data)
386 Q_UNUSED(data);
391 * @param fileName
393 void NetworkHandler::onReceiverFinished(const QString &fileName)
395 m_socket->setFormat(Dash::Network::Socket::Text);
397 dfDebug << m_currentPackage << " file: " << fileName;
399 if( m_currentPackage == "openproject" )
401 m_manager->setLocal(true);
403 qDebug() << QFile::exists(fileName);
405 if( !m_manager->loadProject(fileName) )
407 qFatal("Cannot load the project!");
409 m_manager->setLocal(false);
410 QFile::remove(fileName);