From: deztructor Date: Mon, 16 Nov 2009 13:20:04 +0000 (+0000) Subject: Client-server through DBus, cmake support X-Git-Url: http://git.maemo.org/git/?p=qtrapids;a=commitdiff_plain;h=06410091b1e07c443849f0fe71050654c6fb9710 Client-server through DBus, cmake support git-svn-id: file:///svnroot/qtrapids/trunk@22 42ac0dd5-4c8c-4c71-bb3e-ecdfe252ffda --- diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..adee58e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,12 @@ +project(qtrapids) +cmake_minimum_required(VERSION 2.6) +set(CMAKE_VERBOSE_MAKEFILE ON) + +add_definitions(-Wall -g) + +find_package(Qt4 REQUIRED) + +add_subdirectory(./dbus) +add_subdirectory(./src/client) +add_subdirectory(./src/server) + diff --git a/dbus/CMakeLists.txt b/dbus/CMakeLists.txt new file mode 100644 index 0000000..4a4c67c --- /dev/null +++ b/dbus/CMakeLists.txt @@ -0,0 +1,24 @@ +SET(SOURCES com.ixonos.qtrapids.xml) +SET(PROXY_SRC proxy.h proxy.cpp) +SET(SERVER_SRC server.h server.cpp) + +SET(PROXY_TARGET + ${CMAKE_HOME_DIRECTORY}/src/client/proxy.h + ${CMAKE_HOME_DIRECTORY}/src/client/proxy.cpp) + +SET(SERVER_TARGET + ${CMAKE_HOME_DIRECTORY}/src/server/server.h + ${CMAKE_HOME_DIRECTORY}/src/server/server.cpp) + +SET(GENERATED_FILES ${PROXY_SRC} ${SERVER_SRC}) + +ADD_CUSTOM_COMMAND(OUTPUT ${GENERATED_FILES} + COMMAND qdbusxml2cpp -a server -c QtRapidsServer -i "qtrapids/dbus.hpp" -p proxy ${SOURCES} + COMMAND cp ${PROXY_SRC} ${CMAKE_HOME_DIRECTORY}/src/client + COMMAND cp ${SERVER_SRC} ${CMAKE_HOME_DIRECTORY}/src/server + DEPENDS ${SOURCES} + COMMENT "DBus API sources") + + +ADD_CUSTOM_TARGET(dbusapi ALL DEPENDS ${GENERATED_FILES}) + diff --git a/dbus/com.ixonos.qtrapids.xml b/dbus/com.ixonos.qtrapids.xml new file mode 100644 index 0000000..92f5702 --- /dev/null +++ b/dbus/com.ixonos.qtrapids.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/includes.pri b/includes.pri index 108a4fb..0c073f1 100644 --- a/includes.pri +++ b/includes.pri @@ -1,4 +1,5 @@ INCLUDEPATH = /usr/local/include/libtorrent \ - /usr/local/include/boost-1_38 + /usr/local/include/boost-1_38 \ + ../include CONFIG -= debug diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt new file mode 100644 index 0000000..d2ae12d --- /dev/null +++ b/src/client/CMakeLists.txt @@ -0,0 +1,48 @@ +INCLUDE(${QT_USE_FILE}) + +INCLUDE_DIRECTORIES(../include) + +FIND_LIBRARY(BOOST_SYSTEM boost_system-mt) +IF(${BOOST_SYSTEM} STREQUAL BOOST_SYSTEM-NOTFOUND) + MESSAGE(SEND_ERROR ${BOOST_SYSTEM}) +ENDIF(${BOOST_SYSTEM} STREQUAL BOOST_SYSTEM-NOTFOUND) + +INCLUDE_DIRECTORIES( + ${QT_INCLUDE_DIR} + ${QT_QTTEST_INCLUDE_DIR} + ${QT_QTDBUS} + ${QT_QTGUI} +) + +SET_SOURCE_FILES_PROPERTIES(./proxy.cpp ./proxy.h PROPERTIES GENERATED 1) + +SET(MOC_HEADERS + ./DownloadView.h + ./MainWindow.h + ./PreferencesDialog.h + ./proxy.h + ./SeedView.h +) + +SET(SRC + ./DownloadView.cpp + ./main.cpp + ./MainWindow.cpp + ./PreferencesDialog.cpp + ./proxy.cpp + ./SeedView.cpp +) + +QT4_WRAP_CPP(SRC ${MOC_HEADERS}) +ADD_EXECUTABLE(qtrapids ${SRC} ${MOC_HEADERS}) + +ADD_DEFINITIONS(-DQT_SHARED) +TARGET_LINK_LIBRARIES(qtrapids + ${QT_QTGUI_LIBRARY} + ${QT_QTCORE_LIBRARY} + ${QT_QTDBUS_LIBRARY} + ${QT_QTTEST_LIBRARY} + -lboost_system-mt +) + +ADD_DEPENDENCIES(qtrapids dbusapi) diff --git a/src/client/DownloadView.cpp b/src/client/DownloadView.cpp new file mode 100644 index 0000000..d2201db --- /dev/null +++ b/src/client/DownloadView.cpp @@ -0,0 +1,181 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include + +#include "DownloadView.h" + +#include +#include +#include + +namespace qtrapids +{ + + DownloadView::DownloadView(QWidget* parent) : + QTreeWidget(parent), + items_() + { + setRootIsDecorated(false); // Hide branch lines, making one-level treeview (similar to list) + setHeaderItem(DownloadViewItem::getHeaderItem()); + + connect(this, SIGNAL(itemPressed(QTreeWidgetItem*, int)), + this, SLOT(on_itemClicked(QTreeWidgetItem*, int))); + + } + + + DownloadView::~DownloadView() + { + } + + void DownloadView::updateItem(TorrentState const& info, ParamsMap_t other_info) + { + DownloadItems_t::iterator p = items_.find(info.hash); + if (p != items_.end()) { + updateItem_(p.value(), info, other_info); + } else { + addItem_(info, other_info); + } + } + + void DownloadView::addItem_(TorrentState const& info, ParamsMap_t) + { + DownloadViewItem *item = new DownloadViewItem + ( info.hash, + QStringList() + << info.name + << formatSize(info.total_size) + << GetStatusString((TorrentStatus::Id)info.state) + << formatProgress(info.progress) + << QString::number(info.down_rate, 'f', 2) + << QString::number(info.up_rate, 'f', 2) + << QString::number(info.seeds) + "/" + QString::number(info.leeches) + << QString::number(info.ratio) + << "ETA" ); + + QBrush brushTmp(GetStatusColor((TorrentStatus::Id)info.state)); + item->setForeground(2, brushTmp); + + addTopLevelItem(item); + items_[info.hash] = item; + } + + + void DownloadView::updateItem_(DownloadViewItem *item + , TorrentState const& info, ParamsMap_t) + { + item->setData(2, Qt::DisplayRole, + QVariant(GetStatusString((TorrentStatus::Id)info.state))); + item->setData(3, Qt::DisplayRole, + QVariant(formatProgress(info.progress))); + item->setData(4, Qt::DisplayRole, + QVariant(QString::number(info.down_rate))); + item->setData(5, Qt::DisplayRole, + QVariant(QString::number(info.up_rate))); + item->setData(6, Qt::DisplayRole, + QString::number(info.seeds) + "/" + QString::number(info.leeches)); + + QBrush brushTmp(GetStatusColor((TorrentStatus::Id)info.state)); + item->setForeground(2, brushTmp); + } + + + QString DownloadView::removeSelected() + { + qDebug() << "DownloadView::removeSelected() " << topLevelItemCount() ; + + DownloadViewItem *item = dynamic_cast (currentItem()); + QString hash = item->getHash(); + + int removed = items_.remove(hash); + if (!removed) + qDebug() << "Inconsistent download view state on item removal"; + + int index = indexOfTopLevelItem(currentItem()); + if (index >= 0) { + takeTopLevelItem(index); + } + + qDebug() << "DownloadView::removeSelected() " << topLevelItemCount() ; + + return hash; + } + + + void DownloadView::on_itemClicked(QTreeWidgetItem * , int) + { + /* + qDebug() << "DownloadView::on_itemClicked(()" << item << "," << column; + qDebug() << "current item" << currentItem(); + + if (item == currentItem() && item->isSelected()) { + item->setSelected(false); + } + */ + } + + + QString DownloadView::GetStatusString(TorrentStatus::Id status) + { + switch (status) { + case TorrentStatus::QUEUED_FOR_CHECKING : + return tr("Queued"); + case TorrentStatus::CHECKING_FILES : + return tr("Checking"); + case TorrentStatus::DOWNLOADING_METADATA : + return tr("DL meta"); + case TorrentStatus::DOWNLOADING : + return tr("Downloading"); + case TorrentStatus::FINISHED : + return tr("Finished"); + case TorrentStatus::SEEDING : + return tr("Seeding"); + case TorrentStatus::ALLOCATING : + return tr("Allocating"); + case TorrentStatus::CHECKING_RESUME_DATA : + return tr("Checking resume"); + default: + return tr("N/A"); + } + } + + + QColor DownloadView::GetStatusColor(TorrentStatus::Id status) + { + QColor green(40,205,40); + QColor yellow(255,174,0); + + switch (status) { + case TorrentStatus::QUEUED_FOR_CHECKING : + case TorrentStatus::CHECKING_FILES : + case TorrentStatus::DOWNLOADING_METADATA : + case TorrentStatus::ALLOCATING : + case TorrentStatus::CHECKING_RESUME_DATA: + return yellow; + case TorrentStatus::DOWNLOADING : + case TorrentStatus::FINISHED : + case TorrentStatus::SEEDING : + return green; + default: + return QColor(); + } + } + +} // namespace qtrapids diff --git a/src/client/DownloadView.h b/src/client/DownloadView.h new file mode 100644 index 0000000..abc7ea6 --- /dev/null +++ b/src/client/DownloadView.h @@ -0,0 +1,118 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef DOWNLOADVIEW_H +#define DOWNLOADVIEW_H + +#include +#include +#include + +#include + + +namespace qtrapids +{ + + class DownloadViewItem; + + typedef QHash DownloadItems_t; + + /** + @class DownloadView + @brief A view showing all downloaded torrents + @author Lassi Väätämöinen + */ + class DownloadView : public QTreeWidget + { + Q_OBJECT + + public: + DownloadView(QWidget* parent); + + ~DownloadView(); + + void updateItem(TorrentState const& info, ParamsMap_t other_info); + QString removeSelected(); + + private slots: + void on_itemClicked(QTreeWidgetItem * item, int column); + private: + + void addItem_(TorrentState const& info, ParamsMap_t other_info); + void updateItem_(DownloadViewItem *item + , TorrentState const& info, ParamsMap_t other_info); + + // Maps torrent to downloadview item. + // Key: SHA1 info hash of torrent. Data: View item corresponding to torrent. + DownloadItems_t items_; + + // Private functions. + static QString GetStatusString(TorrentStatus::Id status); + static QColor GetStatusColor(TorrentStatus::Id status); + }; + + + /** + @class DownloadViewItem + @brief Represents one item row of DownloadView + */ + class DownloadViewItem : public QTreeWidgetItem { + + public: + DownloadViewItem(QTreeWidget* parent, int type) : + QTreeWidgetItem(parent, type = QTreeWidgetItem::UserType) {}; + + DownloadViewItem(QString hash, const QStringList& strings, + int type = QTreeWidgetItem::UserType) : + QTreeWidgetItem (strings, type = Type), + hash_(hash) + {} + + + /// @return An item comprising of string list, suitable for QTableView + /// header. + static DownloadViewItem *getHeaderItem() + { + DownloadViewItem *item + = new DownloadViewItem("", QStringList() + << "Name" + << "Size" << "Status" + << "Progress" << "DL speed" + << "UL speed" << "Seeds/Leechers" + << "Ratio" << "ETA"); + + return item; + } + + /// @todo QTorrentHandle as one hidden column + + QString getHash() const + { + return hash_; + } + + private: + QString hash_; + }; + +} // namespace qtrapids + +#endif // DOWNLOADVIEW_H + diff --git a/src/client/MainWindow.cpp b/src/client/MainWindow.cpp new file mode 100644 index 0000000..e200865 --- /dev/null +++ b/src/client/MainWindow.cpp @@ -0,0 +1,234 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "DownloadView.h" +#include "SeedView.h" +#include "PreferencesDialog.h" + +#include "MainWindow.h" + +namespace qtrapids +{ + + const QString ABOUT_TEXT + = QString(QObject::trUtf8("QtRapids, a simple BitTorrent client based on" + "\nQt and Libtorrent." + "\n\nURL: http://qtrapids.garage.maemo.org/" + "\n\nAuthor(s):\nLassi Väätämöinen, lassi.vaatamoinen@ixonos.com" + "\nDenis Zalevskiy, denis.zalewsky@ixonos.com" + "\n\nIxonos Plc, Finland\n")); + + + // Consturctor + MainWindow::MainWindow() : + QMainWindow(), // Superclass + tabWidget_(NULL), + dlView_(NULL), + seedView_(NULL), + preferencesDialog_(NULL), + settings_(QCoreApplication::organizationName() + , QCoreApplication::applicationName()), + server_(QtRapidsServer::staticInterfaceName() + , "/qtrapids", QDBusConnection::sessionBus()) + // torrentHandles_(), + { + // MENUBAR + QMenuBar *menuBar = new QMenuBar(); + QMenu *tempMenu = NULL; + + tempMenu = menuBar->addMenu(tr("&File")); + QAction *openAction = tempMenu->addAction(tr("&Open")); + QAction *removeAction = tempMenu->addAction(tr("&Remove")); + removeAction->setEnabled(false); + QAction *quitAction = tempMenu->addAction(tr("&Quit")); + + tempMenu = menuBar->addMenu(tr("&Settings")); + QAction *preferencesAction = tempMenu->addAction(tr("&Preferences")); + + tempMenu = menuBar->addMenu(tr("&Help")); + QAction *aboutAction = tempMenu->addAction(tr("&About")); + QAction *aboutQtAction = tempMenu->addAction(tr("About &Qt")); + + setMenuBar(menuBar); + connect(openAction, SIGNAL(triggered()), this, SLOT(on_openAction_clicked())); + connect(removeAction, SIGNAL(triggered()), this, SLOT(on_removeAction_clicked())); + connect(this, SIGNAL(itemSelected(bool)), removeAction, SLOT(setEnabled(bool))); + connect(quitAction, SIGNAL(triggered()), this, SLOT(on_quitAction_clicked())); + connect(preferencesAction, SIGNAL(triggered()), this, SLOT(on_preferencesAction_clicked())); + connect(aboutAction, SIGNAL(triggered()), this, SLOT(on_aboutAction_clicked())); + connect(aboutQtAction, SIGNAL(triggered()), this, SLOT(on_aboutQtAction_clicked())); + + // TABWIDGET (central widget) + tabWidget_ = new QTabWidget(); + + /// @todo Exception handling + dlView_ = new DownloadView(this); + seedView_ = new SeedView(this); + tabWidget_->addTab(dlView_, tr("Downloads")); + tabWidget_->addTab(seedView_, tr("Seeds")); + connect(dlView_, SIGNAL(itemSelectionChanged()), this, + SLOT(on_downloadItemSelectionChanged())); + + connect(seedView_, SIGNAL(itemSelectionChanged()), this, + SLOT(on_seedItemSelectionChanged())); + + // Tab widget as central widget. + setCentralWidget(tabWidget_); + + // TOOLBAR + QToolBar *toolBar = new QToolBar(); + toolBar->addAction(tr("Open")); + removeAction = toolBar->addAction(tr("Remove")); + removeAction->setEnabled(false); + addToolBar(Qt::TopToolBarArea, toolBar); + + connect(this, SIGNAL(itemSelected(bool)), removeAction, + SLOT(setEnabled(bool))); + connect(toolBar, SIGNAL(actionTriggered(QAction*)), this, + SLOT(handleToolBarAction(QAction*))); + + QVariant geometry(settings_.value("geometry")); + if (!geometry.isNull()) { + qDebug() << "restoring geometry"; + restoreGeometry(geometry.toByteArray()); + } + } + + + MainWindow::~MainWindow() + { + settings_.setValue("geometry", saveGeometry()); + } + + // =========================== SLOTS ================================= + void MainWindow::on_openAction_clicked() + { + QFileDialog *dialog = new QFileDialog( this, "Open torrent file", QString(), tr("Torrent files (*.torrent)")); + dialog->setFileMode(QFileDialog::ExistingFile); + connect(dialog, SIGNAL(fileSelected(const QString&)), this, SLOT(on_torrentFileSelected(const QString&))); + dialog->show(); + + } + + void MainWindow::on_removeAction_clicked() + { + QString hash = dlView_->removeSelected(); + try { + server_.removeTorrent(hash); + } catch (...) { + qDebug() << "Exception removing torrent"; + } + } + + void MainWindow::on_quitAction_clicked() + { + close(); + } + + void MainWindow::on_preferencesAction_clicked() + { + if (!preferencesDialog_) { + preferencesDialog_ = new PreferencesDialog(this); + } + preferencesDialog_->show(); + preferencesDialog_->raise(); + preferencesDialog_->activateWindow(); + } + + void MainWindow::on_aboutAction_clicked() + { + QMessageBox::about(this, tr("About QtRapids"), ABOUT_TEXT); + } + + + void MainWindow::on_aboutQtAction_clicked() + { + QMessageBox::aboutQt (this, tr("About Qt")); + } + + + void MainWindow::on_downloadItemSelectionChanged() + { + qDebug() << "MainWindow::on_seedItemSelectionChanged():" << dlView_->currentItem(); + if (dlView_->currentItem() != NULL) { + emit(itemSelected(true)); + } else { + emit(itemSelected(false)); + } + } + + void MainWindow::on_seedItemSelectionChanged() + { + qDebug() << "MainWindow::on_seedItemSelectionChanged():" << seedView_->currentItem(); + if (seedView_->currentItem() != NULL) { + emit(itemSelected(true)); + } else { + emit(itemSelected(false)); + } + } + + void MainWindow::handleToolBarAction(QAction* action) + { + if (action->text() == "Open") { + on_openAction_clicked(); + } else if (action->text() == "Remove") { + on_removeAction_clicked(); + } + } + + void MainWindow::on_torrentFileSelected(const QString& file) + { + qDebug() << " MainWindow::on_torrentFileSelected(): " << file; + // Torrent filename empty, do nothing. + if (file == "") { + return; + } + + // Otherwise add torrent + // For params, see: http://www.rasterbar.com/products/libtorrent/manual.html#add-torrent + // save_path is the only mandatory parameter, rest are optional. + //addParams.storage_mode = libtorrent::storage_mode_allocate; + try { + server_.addTorrent(file, settings_.value("download/directory").toString() + , ParamsMap_t()); + } catch (...) { + qDebug() << "Exception adding torrent"; + } + } + + + void MainWindow::alert(qtrapids::TorrentState info, qtrapids::ParamsMap_t other_info) + { + std::cerr << "got alert" << std::endl; + dlView_->updateItem(info, other_info); + } + +} // namespace qtrapids diff --git a/src/client/MainWindow.h b/src/client/MainWindow.h new file mode 100644 index 0000000..43e2bc4 --- /dev/null +++ b/src/client/MainWindow.h @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include + +#include "proxy.h" + +class QTabWidget; +class DownloadView; +class PreferencesDialog; + +namespace qtrapids +{ + + class SeedView; + + /** + @author Lassi Väätämöinen + */ + class MainWindow : public QMainWindow { + Q_OBJECT; + + public: + + MainWindow(); + ~MainWindow(); + + void connectToServer() + { + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + + connect(&server_ + , SIGNAL(alert(qtrapids::TorrentState + , qtrapids::ParamsMap_t)) + , this + , SLOT(alert(qtrapids::TorrentState + , qtrapids::ParamsMap_t))); + server_.getState(); + } + + signals: + void itemSelected(bool enabled); + + public slots: + private slots: + void on_openAction_clicked(); + void on_removeAction_clicked(); + void on_quitAction_clicked(); + void on_preferencesAction_clicked(); + void on_aboutAction_clicked(); + void on_aboutQtAction_clicked(); + void on_downloadItemSelectionChanged(); + void on_seedItemSelectionChanged(); + void handleToolBarAction(QAction* action); + void on_torrentFileSelected(const QString& file); + void alert(qtrapids::TorrentState, qtrapids::ParamsMap_t); + + private: + QTabWidget *tabWidget_; + DownloadView *dlView_; + SeedView *seedView_; + PreferencesDialog *preferencesDialog_; + QSettings settings_; + + //std::vector< std::auto_ptr const > torrentHandles_; + + QtRapidsServer server_; + + + //bool IsNewTorrent(std::auto_ptr handlePtr); + }; + +} // namespace qtrapids + +#endif diff --git a/src/client/PreferencesDialog.cpp b/src/client/PreferencesDialog.cpp new file mode 100644 index 0000000..9ee381b --- /dev/null +++ b/src/client/PreferencesDialog.cpp @@ -0,0 +1,143 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PreferencesDialog.h" + +PreferencesDialog::PreferencesDialog(QWidget* parent, Qt::WindowFlags f) : + QDialog(parent, f), // Superclass + dirLineEdit_(NULL), + dialogButtons_(NULL), + settings_() +{ + setWindowTitle("Preferences"); + + QBoxLayout *verticalBox = new QBoxLayout(QBoxLayout::TopToBottom); + QBoxLayout *horizontalBox1 = new QBoxLayout(QBoxLayout::LeftToRight); + setLayout(verticalBox); + verticalBox->addLayout(horizontalBox1); + + QLabel *dirLabel = new QLabel(tr("Download directory: ")); + dirLineEdit_ = new QLineEdit(this); + QPushButton *browseDirButton = new QPushButton(tr("Browse..")); + + horizontalBox1->addWidget(dirLabel); + horizontalBox1->addWidget(dirLineEdit_); + horizontalBox1->addWidget(browseDirButton); + + connect(browseDirButton, SIGNAL(clicked()), + this, SLOT(on_browseDirButtonClicked())); + + + dialogButtons_ = new QDialogButtonBox(this); + dialogButtons_->setStandardButtons(QDialogButtonBox::Ok + | QDialogButtonBox::Apply + | QDialogButtonBox::Cancel); + + verticalBox->addWidget(dialogButtons_); + + connect(dialogButtons_, SIGNAL(clicked(QAbstractButton*)), + this, SLOT(on_buttonClicked(QAbstractButton*))); + + // Set saved preference values to fields. + ReadSettings(); + +} + + +PreferencesDialog::~PreferencesDialog() +{ +} + +// ======================== SLOTS ======================== +void PreferencesDialog::on_browseDirButtonClicked() +{ + QFileDialog *dialog + = new QFileDialog(this, "Download directory", + QString(), tr("Torrent files (*.torrent)")); + + dialog->setFileMode(QFileDialog::Directory); + dialog->setOption(QFileDialog::ShowDirsOnly, true); + + connect(dialog, SIGNAL(fileSelected(const QString&)), + this, SLOT(on_downloadDirectorySelected(const QString&))); + + dialog->show(); +} + +void PreferencesDialog::on_buttonClicked(QAbstractButton* button) +{ + switch (dialogButtons_->buttonRole ( button ) ) + { + case QDialogButtonBox::AcceptRole : + qDebug() << "PreferencesDialog: OK"; + WriteSettings(); + close(); + break; + case QDialogButtonBox::ApplyRole : + qDebug() << "PreferencesDialog: APPLY"; + WriteSettings(); + break; + case QDialogButtonBox::RejectRole : + qDebug() << "PreferencesDialog: CANCEL"; + close(); + break; + default: + return; + } +} + +void PreferencesDialog::on_downloadDirectorySelected(const QString& directory) +{ + qDebug() << "PreferencesDialog::on_downloadDirectorySelected(): " << directory; + // Torrent filename empty, do nothing. + if (directory == "") + return; + + dirLineEdit_->insert(directory); + + /// @todo check that user has privileges to write to this directory. +} + + +// ========================= Private functions ========================== +void PreferencesDialog::WriteSettings() +{ + settings_.setValue("download/directory", dirLineEdit_->text()); + + // NOTE: We might need to call QSettigns::sync() here to instantly write settings. + // settings are written also by QSettings() destructor and by event loop at regular interval. +} + +void PreferencesDialog::ReadSettings() +{ + dirLineEdit_->insert(settings_.value("download/directory").toString()); + + // NOTE: We might need to call QSettigns::sync() here to instantly write settings. + // settings are written also by QSettings() destructor and by event loop at regular interval. +} + diff --git a/src/client/PreferencesDialog.h b/src/client/PreferencesDialog.h new file mode 100644 index 0000000..c368ea0 --- /dev/null +++ b/src/client/PreferencesDialog.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef PREFERENCESDIALOG_H +#define PREFERENCESDIALOG_H + +#include +#include + + +class QAbstractButton; +class QLineEdit; +class QDialogButtonBox; + +/** + @author Lassi Väätämöinen +*/ +class PreferencesDialog : public QDialog +{ + + Q_OBJECT + + public: + PreferencesDialog(QWidget* parent = 0, Qt::WindowFlags f = 0); + + ~PreferencesDialog(); + + private slots: + void on_browseDirButtonClicked(); + void on_buttonClicked(QAbstractButton* button); + void on_downloadDirectorySelected(const QString& directory); + + private: + QLineEdit *dirLineEdit_; + QDialogButtonBox *dialogButtons_; + QSettings settings_; + + // Private functions: + void WriteSettings(); + void ReadSettings(); +}; + +#endif diff --git a/src/client/SeedView.cpp b/src/client/SeedView.cpp new file mode 100644 index 0000000..3d4d320 --- /dev/null +++ b/src/client/SeedView.cpp @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "SeedView.h" + +#include + +namespace qtrapids +{ + + SeedView::SeedView(QWidget* parent): + QTreeWidget(parent) + { + setRootIsDecorated(false); // Hide branch lines, making one-level treeview (similar to list) + setHeaderItem(SeedViewItem::getHeaderItem()); + + connect(this, SIGNAL(itemPressed(QTreeWidgetItem*, int)), + this, SLOT(on_itemPressed(QTreeWidgetItem*, int))); + } + + + SeedView::~SeedView() + { + } + + void SeedView::on_itemPressed(QTreeWidgetItem * item, int column) + { + qDebug() << "SeedView::on_itemPressed() " << item << "," << column; + } + +} // namespace qtrapids diff --git a/src/client/SeedView.h b/src/client/SeedView.h new file mode 100644 index 0000000..2eb8e15 --- /dev/null +++ b/src/client/SeedView.h @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef SEEDVIEW_H +#define SEEDVIEW_H + +#include + +namespace qtrapids +{ + + class TorrentHandle; + class SeedViewItem; + + /** + @author Lassi Väätämöinen + */ + class SeedView : public QTreeWidget + { + Q_OBJECT + public: + SeedView(QWidget* parent); + + ~SeedView(); + + private slots: + void on_itemPressed(QTreeWidgetItem *item, int column); + + private: + + // Name + // Size + // Status + // UP speed + // Seeds/Leechers + // Connected peers + // total uploaded + // ratio + }; + + /** + @class DownloadViewItem + @brief Represents one item row of DownloadView + */ + class SeedViewItem : public QTreeWidgetItem { + + public: + + SeedViewItem(QTreeWidget* parent, int type) : + QTreeWidgetItem(parent, type = QTreeWidgetItem::UserType) {}; + + SeedViewItem(const QStringList& strings, int type = QTreeWidgetItem::UserType ) : + QTreeWidgetItem (strings, type = Type) {}; + + + /// @return An item comprising of string list, suitable for QTableView + /// header. + static SeedViewItem *getHeaderItem() + { + SeedViewItem *item + = new SeedViewItem(QStringList() + << "Name" + << "Size" << "Status" + << "Progress" << "UL speed" << "Seeds/Leechers" + << "Conn. peers" + << "Ratio"); + + return item; + } + + /// @todo TorrentHandle as one hidden column + }; + +} // namespace qtrapids + +#endif diff --git a/src/client/gui.pro b/src/client/gui.pro new file mode 100644 index 0000000..866e0f5 --- /dev/null +++ b/src/client/gui.pro @@ -0,0 +1,40 @@ +include (../../includes.pri) + +SOURCES += DownloadView.cpp \ + SeedView.cpp \ + MainWindow.cpp \ + main.cpp \ + PreferencesDialog.cpp \ + proxy.cpp + + +HEADERS += DownloadView.h \ + SeedView.h \ + MainWindow.h \ + PreferencesDialog.h \ + proxy.h \ + ../include/qtrapids/dbus.hpp \ + ../include/qtrapids/info.hpp + + +TEMPLATE = app + +TARGET = qtrapids + +CONFIG -= release + +CONFIG += debug \ + qtestlib + +QT += dbus + +DESTDIR = ../../bin + +INCLUDEPATH += ../include + +LIBS += -L../../bin \ + -L../engine + +QMAKE_LFLAGS_DEBUG += -L. + +LIBS += -lboost_system-mt diff --git a/src/client/main.cpp b/src/client/main.cpp new file mode 100644 index 0000000..81b7b15 --- /dev/null +++ b/src/client/main.cpp @@ -0,0 +1,74 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include +#include +#include +//#include +//#include "DownloadView.h" + +#include "MainWindow.h" + +using qtrapids::MainWindow; + +int main(int argc, char *argv[]) +{ + + QCoreApplication::setOrganizationName("Ixonos"); + QCoreApplication::setOrganizationDomain("ixonos.com"); + QCoreApplication::setApplicationName("QtRapids"); + + // Q_INIT_RESOURCE(application); + QApplication app(argc, argv); + MainWindow mainWindow; + mainWindow.connectToServer(); + // mainWindow->setGeometry(QApplication::desktop()->screenGeometry()); + + mainWindow.show(); + + /* + DownloadView* dlw = new DownloadView(NULL); + //qtrapids * mw = new qtrapids(); + dlw->show(); + DownloadViewItem* dlwItem = new DownloadViewItem(QStringList() << "Name" + << "Size" << "Status" + << "Progress" << "DL speed" + << "UL speed" << "Seeds/Leechers" + << "ratio"); + DownloadViewItem* dlwItem2 = new DownloadViewItem(QStringList() << "Name" + << "1000" << "Downloading" + << "23%" << "11" + << "0.1" << "0/2" + << "1.10"); + //dlwItem->insertChild(0, new DownloadViewItem(QStringList() << "Name")); + dlw->insertTopLevelItem(0,dlwItem); + dlw->insertTopLevelItem(1,dlwItem2); + + for (unsigned i = 0; i < 10; ++i) + { + DownloadViewItem *editItem = dynamic_cast + (dlw->itemAt(QPoint(0,0))); + editItem->setData ( 8, Qt::DisplayRole, QVariant("EDITED" + QString::number(i, 'g', 2))); + QTest::qSleep(2000); + } + */ + + + return app.exec(); +} diff --git a/src/include/qtrapids/dbus.hpp b/src/include/qtrapids/dbus.hpp new file mode 100644 index 0000000..52681d4 --- /dev/null +++ b/src/include/qtrapids/dbus.hpp @@ -0,0 +1,120 @@ +#ifndef _QTRAPIDS_DBUS_HPP_ +#define _QTRAPIDS_DBUS_HPP_ + +#include +#include +#include + +// TMP TODO +#include + +namespace qtrapids +{ + + struct TorrentState + { + TorrentState() + : hash("") + , name("") + , state(0) + , progress(0) + , down_rate(0) + , up_rate(0) + , seeds(0) + , leeches(0) + , ratio(0) + , total_size(0) + { } + + QString hash; + QString name; + uint state; + uint progress; + uint down_rate; + uint up_rate; + uint seeds; + uint leeches; + uint ratio; + qulonglong total_size; + }; + + typedef QHash ParamsMap_t; + typedef QHash const ParamsMapConst_t; + typedef QHash::iterator ParamsMapIterator_t; + typedef QHash::const_iterator ParamsMapConstIterator_t; + + static inline QDBusArgument& operator << (QDBusArgument& argument + , TorrentState const& state) + { + std::cout << "serialize" << std::endl; + argument.beginStructure(); + argument << state.hash << state.name << state.state << state.progress + << state.down_rate << state.up_rate << state.seeds + << state.leeches << state.ratio << state.total_size; + argument.endStructure(); + return argument; + } + + static inline QDBusArgument const& operator >> (QDBusArgument const& argument + , TorrentState& state) + { + std::cout << "deserialize" << std::endl; + argument.beginStructure(); + argument >> state.hash >> state.name >> state.state >> state.progress + >> state.down_rate >> state.up_rate >> state.seeds + >> state.leeches >> state.ratio >> state.total_size; + argument.endStructure(); + return argument; + } + + static inline QDBusArgument& operator << (QDBusArgument& argument + , ParamsMapConst_t& params) + { + ParamsMapConstIterator_t p; + std::cout << "serialize params" << std::endl; + argument.beginMap(); + for (p = params.constBegin(); p != params.constEnd(); ++p) { + argument.beginMapEntry(); + argument << p.key() << p.value(); + argument.endMapEntry(); + } + argument.endMap(); + return argument; + } + + static inline QDBusArgument const& operator >> (QDBusArgument const& argument + , ParamsMap_t& params) + { + ParamsMapConstIterator_t p; + QString key, value; + std::cout << "deserialize params" << std::endl; + argument.beginMap(); + for (p = params.constBegin(); p != params.constEnd(); ++p) { + argument.beginMapEntry(); + argument >> key >> value; + params[key] = value; + argument.endMapEntry(); + } + argument.endMap(); + return argument; + } + + + // class DBusConnector + // { + // public: + // DBusConnector() + // : connection_() + // { + // } + // private: + // QDBusConnection connection_; + // }; + +} + +Q_DECLARE_METATYPE(qtrapids::TorrentState); +Q_DECLARE_METATYPE(qtrapids::ParamsMap_t); + +#endif // _QTRAPIDS_DBUS_HPP_ + diff --git a/src/include/qtrapids/error.hpp b/src/include/qtrapids/error.hpp new file mode 100644 index 0000000..0bf83f5 --- /dev/null +++ b/src/include/qtrapids/error.hpp @@ -0,0 +1,53 @@ +#ifndef _QTRAPIDS_ERROR_HPP_ +#define _QTRAPIDS_ERROR_HPP_ + +#include + +namespace qtrapids +{ + + class Error + { + public: + + Error() + : msg_("") + { } + + Error(char const *msg) + : msg_(msg) + {} + + template + void append_to_msg(T val) + { + msg_ << val; + } + + private: + QString msg_; + + }; + + template + Error& operator << (Error &self, T val) + { + self.append_to_msg(val); + return self; + } + + class InvalidArgument : public Error + { + }; + + template + InvalidArgument& operator << (InvalidArgument &self, T val) + { + self.append_to_msg(val); + return self; + } + +} + +#endif // _QTRAPIDS_ERROR_HPP_ + diff --git a/src/include/qtrapids/format.hpp b/src/include/qtrapids/format.hpp new file mode 100644 index 0000000..8094101 --- /dev/null +++ b/src/include/qtrapids/format.hpp @@ -0,0 +1,52 @@ +#ifndef _QTRAPIDS_FORMAT_HPP_ +#define _QTRAPIDS_FORMAT_HPP_ + +#include +#include + + + +namespace qtrapids +{ + + + static inline QString formatProgress(uint progress) + { + return QString::number(((double)progress) / torrent_progress_max * 100); + } + + namespace + { + + static const qulonglong size_KB = 1024; + static const qulonglong size_MB = size_KB << 10; + static const qulonglong size_GB = size_MB << 10; + + static char const* size_names[] = { + "GB", + "MB", + "KB", + "B" + }; + } + + static inline QString formatSize(qulonglong size) + { + qulonglong unit = size_GB; + char const ** unit_name = &size_names[0]; + QString ret(""); + for (unit = size_GB; unit > 0; unit >>= 10, ++unit_name) { + if (size & (~(unit - 1))) { + ret += (QString::number(size / unit) + *unit_name); + return ret; + } + } + ret += (QString::number(size / unit) + "B"); + return ret; + } + + +} // namespace qtrapids + +#endif // _QTRAPIDS_FORMAT_HPP_ + diff --git a/src/include/qtrapids/info.hpp b/src/include/qtrapids/info.hpp new file mode 100644 index 0000000..6265155 --- /dev/null +++ b/src/include/qtrapids/info.hpp @@ -0,0 +1,35 @@ +#ifndef _QTRAPIDS_INFO_HPP_ +#define _QTRAPIDS_INFO_HPP_ + +#include + +#include +#include + +namespace qtrapids +{ + + static const uint32_t torrent_progress_max = std::numeric_limits::max(); + + typedef libtorrent::torrent_status TorrentStatus_t; + typedef libtorrent::torrent_status::state_t TorrentStatusIds_t; + + struct TorrentStatus + { + enum Id { + QUEUED_FOR_CHECKING = TorrentStatus_t::queued_for_checking, + CHECKING_FILES = TorrentStatus_t::checking_files, + DOWNLOADING_METADATA = TorrentStatus_t::downloading_metadata, + DOWNLOADING = TorrentStatus_t::downloading, + FINISHED = TorrentStatus_t::finished, + SEEDING = TorrentStatus_t::seeding, + ALLOCATING = TorrentStatus_t::allocating, + CHECKING_RESUME_DATA = TorrentStatus_t::checking_resume_data, + UNSPECIFIED + }; + }; + +} + +#endif // _QTRAPIDS_INFO_HPP_ + diff --git a/src/server/AlertWaiterThread.cpp b/src/server/AlertWaiterThread.cpp new file mode 100644 index 0000000..f6029be --- /dev/null +++ b/src/server/AlertWaiterThread.cpp @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "AlertWaiterThread.hpp" +#include + + +namespace qtrapids +{ + + // Constants: + // Timeout for waiting alerts + const libtorrent::time_duration ALERT_WAIT_TIMEOUT + = libtorrent::time_duration(libtorrent::seconds(15)); + + + AlertWaiterThread::AlertWaiterThread(session_t *session, QObject* parent) : + QThread(parent), + btSession_(session) + { + } + + + AlertWaiterThread::~AlertWaiterThread() + { + } + + + void AlertWaiterThread::allAlerts(bool enable) + { + // If all enabled, set all alert cateogries: + if (enable) { + btSession_->set_alert_mask(libtorrent::alert::all_categories); + } else { + // Otherwise set to default, which is only error notifications. + btSession_->set_alert_mask(libtorrent::alert::error_notification); + } + } + + + void AlertWaiterThread::run() + { + alert_t const *alertTemp = NULL; + while (true) { + // wait_for_alert() call blocks. Returns libtorrent alert. + // Returns NULL, if no alerts in timeout period. + alertTemp = btSession_->wait_for_alert(ALERT_WAIT_TIMEOUT); + emit alert(); + // 2000 us = 2ms. Gives main thread time to handle alert signal. + usleep(2000); + } + } + +} diff --git a/src/server/AlertWaiterThread.hpp b/src/server/AlertWaiterThread.hpp new file mode 100644 index 0000000..9d35226 --- /dev/null +++ b/src/server/AlertWaiterThread.hpp @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef ALERTWAITERTHREAD_H +#define ALERTWAITERTHREAD_H + +#include +#include "TorrentSession.hpp" + +namespace qtrapids +{ + + /** + @author Lassi Väätämöinen + */ + class AlertWaiterThread : public QThread + { + Q_OBJECT + + public: + AlertWaiterThread(session_t *session, QObject *parent = 0); + + virtual ~AlertWaiterThread(); + + void allAlerts(bool enable = true); + + virtual void run(); // Overridden from QThread + + signals: + void alert(); + + private: + session_t *const btSession_; + + }; + +} // namespace qtrapids + +#endif diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt new file mode 100644 index 0000000..2429ac0 --- /dev/null +++ b/src/server/CMakeLists.txt @@ -0,0 +1,45 @@ +INCLUDE(${QT_USE_FILE}) + +FIND_LIBRARY(TORRENT_RASTERBAR torrent-rasterbar) +IF(${TORRENT_RASTERBAR} STREQUAL TORRENT_RASTERBAR-NOTFOUND) + MESSAGE(SEND_ERROR ${TORRENT_RASTERBAR}) +ENDIF(${TORRENT_RASTERBAR} STREQUAL TORRENT_RASTERBAR-NOTFOUND) + +INCLUDE_DIRECTORIES(../include) + +INCLUDE_DIRECTORIES( + ${QT_INCLUDE_DIR} + ${QT_QTDBUS_INCLUDE_DIR} + ${QT_QTSQL_INCLUDE_DIR} +) + +SET_SOURCE_FILES_PROPERTIES(./server.cpp ./server.h PROPERTIES GENERATED 1) + +SET(MOC_HEADERS + ./AlertWaiterThread.hpp + ./TorrentHandle.hpp + ./TorrentSession.hpp + ./server.h +) + +SET(SRC + ./AlertWaiterThread.cpp + ./main.cpp + ./server.cpp + ./TorrentHandle.cpp + ./TorrentSession.cpp +) + +QT4_WRAP_CPP(SRC ${MOC_HEADERS} ) + +ADD_EXECUTABLE(qtrapids-server ${SRC} ${MOC_HEADERS}) + +ADD_DEFINITIONS(-DQT_SHARED) +TARGET_LINK_LIBRARIES(qtrapids-server + ${QT_QTCORE_LIBRARY} + ${QT_QTDBUS_LIBRARY} + ${QT_QTSQL_LIBRARY} + -ltorrent-rasterbar +) + +ADD_DEPENDENCIES(qtrapids-server dbusapi) diff --git a/src/server/ServerDb.hpp b/src/server/ServerDb.hpp new file mode 100644 index 0000000..060bb96 --- /dev/null +++ b/src/server/ServerDb.hpp @@ -0,0 +1,128 @@ +#ifndef _SERVERDB_HPP_ +#define _SERVERDB_HPP_ + +#include +#include +#include + +namespace qtrapids +{ + + class ServerSettings + { + + public: + ServerSettings(QSettings *settings) + : settings_(settings) + { } + + ~ServerSettings() + { + + } + + QString getDbEngine() const + { + return getParamAndStore("db_engine", getDefaultDbEngine()).toString(); + } + + QString getDbName() const + { + QString default_db_path(QDir::home().filePath(appName() + ".sqlite")); + return getParamAndStore("db", default_db_path).toString(); + } + + QString getTorrentsDir() const + { + QString default_dir(QDir::home().filePath(QString(".") + appName())); + return getParamAndStore("db", default_dir).toString(); + + } + + private: + + ServerSettings(ServerSettings const&); + ServerSettings& operator= (ServerSettings const&); + + static inline QString appName() + { + return QCoreApplication::applicationName(); + } + + static QString getDefaultDbEngine() + { + // for (QStringListIterator p = QSqlDatabase::drivers(); p.hasNext();) { + // return p.next(); + // } + return "QSQLITE"; + } + + QVariant getParamAndStore(QString const& name, QVariant default_value) const + { + QVariant v(settings_->value(name)); + if (!v.isNull()) { + return v; + } + + settings_->setValue(name, default_value); + return default_value; + } + + mutable QSettings *settings_; + }; + + class ServerDb + { + + public: + ServerDb(ServerSettings *settings) + : db_(QSqlDatabase::addDatabase(settings->getDbEngine())) + { + QString db_name(settings->getDbName()); + db_.setDatabaseName(db_name); + + if (!db_.open()) { + qDebug() << "cant open db"; + return; + } + qDebug() << "opened " << db_name; + + QSqlQuery q; + if (!q.exec("create table torrents (hash varchar primary key, path varchar, savepath varchar);\n")) { + qDebug() << "cant create table: " << q.lastError().text(); + } + } + + ~ServerDb() + { + db_.close(); + } + + void addTorrent(const QString &hash, const QString &path, const QString &save_path) + { + if (!db_.open()) { + qDebug() << "cant open db"; + } + QSqlQuery query_add_; + query_add_.prepare("INSERT INTO torrents (hash, path, savepath) VALUES (?, ?, ?)"); + query_add_.bindValue(0, hash); + query_add_.bindValue(1, path); + query_add_.bindValue(2, save_path); + if (!query_add_.exec()) { + qDebug() << "cant add torrent info into db: " + << query_add_.lastError().text(); + } + db_.close(); + } + + private: + + ServerDb(ServerDb const&); + ServerDb& operator= (ServerDb const&); + + QSqlDatabase db_; + }; + +} // namespace qtrapids + +#endif // _SERVERDB_HPP_ diff --git a/src/server/TorrentHandle.cpp b/src/server/TorrentHandle.cpp new file mode 100644 index 0000000..d4b5533 --- /dev/null +++ b/src/server/TorrentHandle.cpp @@ -0,0 +1,143 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "TorrentHandle.hpp" +#include + + +namespace qtrapids +{ + + TorrentHandle::TorrentHandle(libtorrent::torrent_handle handle) : + torrentHandle_(handle) + { + } + + + TorrentHandle::~TorrentHandle() + { + } + + + TorrentStatus_t TorrentHandle::status() const + { + return torrentHandle_.status(); + } + + + torrent_info_cref TorrentHandle::getTorrentInfo() const + { + return torrentHandle_.get_torrent_info(); + } + + + bool TorrentHandle::isValid() const + { + return torrentHandle_.is_valid(); + } + + + QString TorrentHandle::name() const + { + return QString::fromStdString(torrentHandle_.name()); + } + + size_t TorrentHandle::getTotalSize() const + { + torrent_info_cref info = getTorrentInfo(); + return static_cast (info.total_size()); + } + + + TorrentStatus::Id TorrentHandle::state() const + { + TorrentStatus::Id s = (TorrentStatus::Id)(status().state); + return ( (s < TorrentStatus::UNSPECIFIED) + ? s : TorrentStatus::UNSPECIFIED ); + } + + + float TorrentHandle::progress() const + { + TorrentStatus_t statusTmp = status(); + return statusTmp.progress; + } + + float TorrentHandle::uploadRate() const + { + TorrentStatus_t statusTmp = status(); + return statusTmp.upload_rate; + } + + + float TorrentHandle::downloadRate() const + { + TorrentStatus_t statusTmp = status(); + return statusTmp.download_rate; + } + + + qint32 TorrentHandle::numSeeds() const + { + TorrentStatus_t statusTmp = status(); + return statusTmp.list_seeds; + } + + + qint32 TorrentHandle::numLeeches() const + { + TorrentStatus_t statusTmp = status(); + return (statusTmp.list_peers - statusTmp.list_seeds); + } + + + qint32 TorrentHandle::ratio() const + { + TorrentStatus_t statusTmp = status(); + size_t ratio; + if (statusTmp.total_payload_download == 0) { + ratio = 0; + } else { + ratio = static_cast (statusTmp.total_payload_upload / statusTmp.total_payload_download); + } + + return ratio; + } + + + torrent_handle_t TorrentHandle::getHandle() const + { + return torrentHandle_; + } + + + bool TorrentHandle::operator==(TorrentHandle const& h) const + { + return torrentHandle_ == h.torrentHandle_; + } + + + bool TorrentHandle::operator<(TorrentHandle const& h) const + { + return torrentHandle_ < h.torrentHandle_; + } + + +} diff --git a/src/server/TorrentHandle.hpp b/src/server/TorrentHandle.hpp new file mode 100644 index 0000000..c84c174 --- /dev/null +++ b/src/server/TorrentHandle.hpp @@ -0,0 +1,87 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.com * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef QTORRENTHANDLE_H +#define QTORRENTHANDLE_H + +#include +#include + +#include +#include + +namespace qtrapids +{ + + typedef libtorrent::torrent_info const& torrent_info_cref; + typedef libtorrent::torrent_handle torrent_handle_t; + typedef libtorrent::sha1_hash Sha1Hash; + + + inline QString Hash2QStr(Sha1Hash const& hash) + { + return QString(hash.to_string().c_str()); + } + + /** + @author Lassi Väätämöinen + */ + class TorrentHandle + { + public: + + TorrentHandle(libtorrent::torrent_handle handle); + ~TorrentHandle(); + + + + torrent_info_cref getTorrentInfo() const; + + bool isValid() const; + + Sha1Hash hash() const + { + return torrentHandle_.info_hash(); + } + + QString name() const; + size_t getTotalSize() const; + TorrentStatus::Id state() const; + float progress() const; + float uploadRate() const; + float downloadRate() const; + qint32 numSeeds() const; + qint32 numLeeches() const; + qint32 ratio() const; + + torrent_handle_t getHandle() const; + bool operator==(TorrentHandle const& h) const; + bool operator<(TorrentHandle const& h) const; + + private: + TorrentHandle(); // Prevent default construct. + torrent_handle_t torrentHandle_; + + TorrentStatus_t status() const; + + }; + +} + +#endif diff --git a/src/server/TorrentSession.cpp b/src/server/TorrentSession.cpp new file mode 100644 index 0000000..514b2c9 --- /dev/null +++ b/src/server/TorrentSession.cpp @@ -0,0 +1,147 @@ +#include "TorrentSession.hpp" +#include "TorrentHandle.hpp" +#include "AlertWaiterThread.hpp" + + +namespace qtrapids +{ + + + + TorrentSession::TorrentSession(QObject *parent, QSettings *settings) + : QObject(parent) + , btSession_() + , alertWaiter_(new AlertWaiterThread(&btSession_, this)) + { + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + new QtRapidsServer(this); + + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.registerObject("/qtrapids", this); + dbus.registerService("com.ixonos.qtrapids"); + + alertWaiter_->allAlerts(); + connect(alertWaiter_, SIGNAL(alert()), this, SLOT(on_alert())); + alertWaiter_->start(); + + + } + + void TorrentSession::on_alert() + //NOTE: al parameter not necessarily needed here, as we pop_alert() now! + { + + //qDebug() << "QBittorrentSession:on_alert(" << al << ")"; + // if (al) + // qDebug() << "on_alert():" << QString::fromStdString(al->message()); + + std::auto_ptr alertPtr = btSession_.pop_alert(); + + if (alertPtr.get() != NULL) { + + torrent_alert_t *ta = dynamic_cast (alertPtr.get()); + + qDebug() + << "QBittorrentSession::on_alert(): " + << QString::fromStdString(alertPtr->message()); + + + if (ta) { + TorrentHandle handle(ta->handle); + TorrentState state; + + state.hash = Hash2QStr(handle.hash()); + state.state = handle.state(); + state.progress = handle.progress() * torrent_progress_max; + state.down_rate = handle.downloadRate(); + state.up_rate = handle.uploadRate(); + state.seeds = handle.numSeeds(); + state.leeches = handle.numLeeches(); + + ParamsMap_t params; + emit alert(state, params); + } + + } + } + + void TorrentSession::getState() + { + torrents_t::const_iterator p; + for (p = torrents_.constBegin(); p != torrents_.constEnd(); ++p) { + TorrentHandlePtr handle = *p; + TorrentState state; + QString hash = Hash2QStr(handle->hash()); + + state.hash = hash; + state.name = handle->name(); + state.state = handle->state(); + state.progress = handle->progress() * torrent_progress_max; + state.down_rate = handle->downloadRate(); + state.up_rate = handle->uploadRate(); + state.seeds = handle->numSeeds(); + state.leeches = handle->numLeeches(); + state.total_size = handle->getTotalSize(); + + emit alert(state, ParamsMap_t()); + } + } + + void TorrentSession::addTorrent(const QString &path, const QString &save_path + , qtrapids::ParamsMap_t other_params) + { + add_torrent_params_t addParams; + QFile torrent_file(path); + if (!torrent_file.exists()) { + qWarning() << "Torrent file " << path << "doesn't exist"; + return; + } + + qDebug() << "addTorrent: " << path << " save to " << save_path; + boost::intrusive_ptr tiTmp + = new libtorrent::torrent_info(path.toStdString()); + addParams.ti = tiTmp; + + // save_path is the only mandatory parameter, rest are optional. + addParams.save_path = save_path.toStdString(); + //addParams.storage_mode = libtorrent::storage_mode_allocate; + + TorrentHandlePtr handle(new TorrentHandle(btSession_.add_torrent(addParams))); + QString hash = Hash2QStr(handle->hash()); + + TorrentState state; + + state.hash = hash; + state.name = handle->name(); + state.state = handle->state(); + state.progress = handle->progress() * torrent_progress_max; + state.down_rate = handle->downloadRate(); + state.up_rate = handle->uploadRate(); + state.seeds = handle->numSeeds(); + state.leeches = handle->numLeeches(); + state.total_size = handle->getTotalSize(); + + torrents_[hash] = handle; + + emit alert(state, ParamsMap_t()); + } + + void TorrentSession::removeTorrent(const QString &hash) + { + torrents_t::iterator p = torrents_.find(hash); + if (p == torrents_.end()) { + qDebug() << "Invalid request to remove torrent with hash " << hash; + return; + } + try { + btSession_.remove_torrent(p.value()->getHandle()); + } catch (torrent_exception_t e) { + qDebug() << // e.what() + "exception catched" + ; + } + } + + +} // namespace qtrapids diff --git a/src/server/TorrentSession.hpp b/src/server/TorrentSession.hpp new file mode 100644 index 0000000..76b11f2 --- /dev/null +++ b/src/server/TorrentSession.hpp @@ -0,0 +1,73 @@ +#ifndef _TEST_HPP_ +#define _TEST_HPP_ + +#include "TorrentHandle.hpp" +#include "server.h" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +class QSettings; + +namespace qtrapids +{ + + typedef QWeakPointer settings_weak_ptr; + + class AlertWaiterThread; + typedef libtorrent::session session_t; + typedef libtorrent::session const* session_cptr; + + typedef libtorrent::add_torrent_params add_torrent_params_t; + typedef libtorrent::alert alert_t; + // typedef libtorrent::alert const* alert_cptr; + typedef libtorrent::torrent_alert torrent_alert_t; + typedef libtorrent::libtorrent_exception torrent_exception_t; + + typedef QSharedPointer TorrentHandlePtr; + typedef QHash torrents_t; + + class ServerDb; + class ServerSettings; + + class TorrentSession : public QObject + { + + Q_OBJECT; + Q_CLASSINFO("D-Bus Interface", "com.ixonos.qtrapids"); + + public: + + TorrentSession(QObject *parent, QSettings *); + + public slots: + + void getState(); + void addTorrent(const QString &path, const QString &save_path + , qtrapids::ParamsMap_t other_params); + void removeTorrent(const QString &hash); + + signals: + void alert(qtrapids::TorrentState info, qtrapids::ParamsMap_t other_info); + + private slots: + void on_alert(); + + private: + session_t btSession_; + AlertWaiterThread *alertWaiter_; + torrents_t torrents_; + }; + +} // namespace qtrapids + +#endif // _TEST_HPP_ diff --git a/src/server/create_db.sql b/src/server/create_db.sql new file mode 100644 index 0000000..6d41407 --- /dev/null +++ b/src/server/create_db.sql @@ -0,0 +1,2 @@ +drop table torrents; +create table torrents(path varchar, savepath varchar); diff --git a/src/server/main.cpp b/src/server/main.cpp new file mode 100644 index 0000000..ef74cd3 --- /dev/null +++ b/src/server/main.cpp @@ -0,0 +1,19 @@ +#include +//#include "server.h" +#include "TorrentSession.hpp" + +using qtrapids::TorrentSession; +using qtrapids::settings_weak_ptr; + +int main(int argc, char *argv[]) +{ + QCoreApplication::setOrganizationName("Ixonos"); + QCoreApplication::setOrganizationDomain("ixonos.com"); + QCoreApplication::setApplicationName("QtRapids"); + QSettings settings(QCoreApplication::organizationName() + , QCoreApplication::applicationName()); + + QCoreApplication app(argc, argv); + TorrentSession server(&app, &settings); + return app.exec(); +} diff --git a/src/server/server.pro b/src/server/server.pro new file mode 100644 index 0000000..eb10030 --- /dev/null +++ b/src/server/server.pro @@ -0,0 +1,36 @@ +include (../../includes.pri) + +TEMPLATE = app + +CONFIG += console debug +CONFIG -= app_bundle + +VERSION = 0.2 + +HEADERS += \ +TorrentSession.hpp \ +AlertWaiterThread.hpp \ +TorrentHandle.hpp \ +server.h \ +../include/qtrapids/dbus.hpp \ +../include/qtrapids/status.hpp + +SOURCES += \ + main.cpp \ + server.cpp \ + TorrentSession.cpp \ + TorrentHandle.cpp \ + AlertWaiterThread.cpp + +QT += dbus sql + +QT -= gui + +CONFIG -= release + +TARGET = qtrapids-server + +DESTDIR = ../../bin + +LIBS += -ltorrent-rasterbar + diff --git a/src/src.pro b/src/src.pro index 27453b1..71cda24 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,7 +1,6 @@ SUBDIRS += engine \ gui - CONFIG += ordered \ warn_on \ thread \