From 383c0e14189bda74826f58673391d53cab4bcb2b Mon Sep 17 00:00:00 2001 From: buinsky Date: Tue, 6 Jan 2015 23:04:23 +0300 Subject: [PATCH] Implement sync/maindata request --- src/webui/btjson.cpp | 171 +++++++++++++++++++++++++---------- src/webui/btjson.h | 2 + src/webui/requesthandler.cpp | 10 ++ src/webui/requesthandler.h | 1 + src/webui/webapplication.h | 4 +- 5 files changed, 140 insertions(+), 48 deletions(-) diff --git a/src/webui/btjson.cpp b/src/webui/btjson.cpp index 4106e47c5..2e21eca3f 100644 --- a/src/webui/btjson.cpp +++ b/src/webui/btjson.cpp @@ -101,6 +101,7 @@ static const char KEY_TORRENT_ETA[] = "eta"; static const char KEY_TORRENT_STATE[] = "state"; static const char KEY_TORRENT_SEQUENTIAL_DOWNLOAD[] = "seq_dl"; static const char KEY_TORRENT_FIRST_LAST_PIECE_PRIO[] = "f_l_piece_prio"; +static const char KEY_TORRENT_LABEL[] = "label"; // Tracker keys static const char KEY_TRACKER_URL[] = "url"; @@ -147,6 +148,8 @@ static const char KEY_FULL_UPDATE[] = "full_update"; static const char KEY_RESPONSE_ID[] = "rid"; static const char KEY_SUFFIX_REMOVED[] = "_removed"; +QVariantMap getTranserInfoMap(); +QVariantMap toMap(const QTorrentHandle& h); void processMap(QVariantMap prevData, QVariantMap data, QVariantMap &syncData); void processHash(QVariantHash prevData, QVariantHash data, QVariantHash &syncData, QVariantList &removedItems); void processList(QVariantList prevData, QVariantList data, QVariantList &syncData, QVariantList &removedItems); @@ -204,36 +207,6 @@ private: #endif }; -static QVariantMap toMap(const QTorrentHandle& h) -{ - libtorrent::torrent_status status = h.status(torrent_handle::query_accurate_download_counters); - - QVariantMap ret; - ret[KEY_TORRENT_HASH] = h.hash(); - ret[KEY_TORRENT_NAME] = h.name(); - ret[KEY_TORRENT_SIZE] = static_cast(status.total_wanted); - ret[KEY_TORRENT_PROGRESS] = h.progress(status); - ret[KEY_TORRENT_DLSPEED] = status.download_payload_rate; - ret[KEY_TORRENT_UPSPEED] = status.upload_payload_rate; - if (QBtSession::instance()->isQueueingEnabled() && h.queue_position(status) >= 0) - ret[KEY_TORRENT_PRIORITY] = h.queue_position(status); - else - ret[KEY_TORRENT_PRIORITY] = -1; - ret[KEY_TORRENT_SEEDS] = status.num_seeds; - ret[KEY_TORRENT_NUM_COMPLETE] = status.num_complete; - ret[KEY_TORRENT_LEECHS] = status.num_peers - status.num_seeds; - ret[KEY_TORRENT_NUM_INCOMPLETE] = status.num_incomplete; - const qreal ratio = QBtSession::instance()->getRealRatio(status); - ret[KEY_TORRENT_RATIO] = (ratio > QBtSession::MAX_RATIO) ? -1 : ratio; - ret[KEY_TORRENT_STATE] = h.torrentState().toString(); - ret[KEY_TORRENT_ETA] = h.eta(); - ret[KEY_TORRENT_SEQUENTIAL_DOWNLOAD] = status.sequential_download; - if (h.has_metadata()) - ret[KEY_TORRENT_FIRST_LAST_PIECE_PRIO] = h.first_last_piece_first(); - - return ret; -} - /** * Returns all the torrents in JSON format. * @@ -266,7 +239,7 @@ QByteArray btjson::getTorrents(QString filter, QString label, std::vector::const_iterator end = torrents.end(); QTorrentFilter torrentFilter(filter, label); - for(; it != end; ++it) { + for (; it != end; ++it) { QTorrentHandle torrent = QTorrentHandle(*it); if (torrentFilter.apply(torrent)) @@ -290,6 +263,76 @@ QByteArray btjson::getTorrents(QString filter, QString label, return json::toJson(torrent_list); } +/** + * The function returns the changed data from the server to synchronize with the web client. + * Return value is map in JSON format. + * Map contain the key: + * - "Rid": ID response + * Map can contain the keys: + * - "full_update": full data update flag + * - "torrents": dictionary contains information about torrents. + * - "torrents_removed": a list of hashes of removed torrents + * - "labels": list of labels + * - "labels_removed": list of removed labels + * - "queueing": priority system usage flag + * - "server_state": map contains information about the status of the server + * The keys of the 'torrents' dictionary are hashes of torrents. + * Each value of the 'torrents' dictionary contains map. The map can contain following keys: + * - "name": Torrent name + * - "size": Torrent size + * - "progress: Torrent progress + * - "dlspeed": Torrent download speed + * - "upspeed": Torrent upload speed + * - "priority": Torrent priority (-1 if queuing is disabled) + * - "num_seeds": Torrent seeds connected to + * - "num_complete": Torrent seeds in the swarm + * - "num_leechs": Torrent leechers connected to + * - "num_incomplete": Torrent leechers in the swarm + * - "ratio": Torrent share ratio + * - "eta": Torrent ETA + * - "state": Torrent state + * - "seq_dl": Torrent sequential download state + * - "f_l_piece_prio": Torrent first last piece priority state + * Server state map may contain the following keys: + * - "connection_status": conection status + * - "dht_nodes": DHT nodes count + * - "dl_info_data": bytes downloaded + * - "dl_info_speed": download speed + * - "dl_rate_limit: downlaod rate limit + * - "up_info_data: bytes uploaded + * - "up_info_speed: upload speed + * - "up_rate_limit: upload speed limit + */ +QByteArray btjson::getSyncMainData(int acceptedResponseId, QVariantMap &lastData, QVariantMap &lastAcceptedData) +{ + QVariantMap data; + + QVariantHash torrents; + + std::vector torrentsList = QBtSession::instance()->getTorrents(); + std::vector::const_iterator it = torrentsList.begin(); + std::vector::const_iterator end = torrentsList.end(); + + for (; it != end; ++it) { + QTorrentHandle torrent = QTorrentHandle(*it); + QVariantMap map = toMap(torrent); + map.remove(KEY_TORRENT_HASH); + torrents[torrent.hash()] = map; + } + + data["torrents"] = torrents; + data["queueing"] = QBtSession::instance()->isQueueingEnabled(); + + QVariantList labels; + foreach (QString s, Preferences::instance()->getTorrentLabels()) + labels << s; + + data["labels"] = labels; + data["server_state"] = getTranserInfoMap(); + + return json::toJson(generateSyncData(acceptedResponseId, data, lastAcceptedData, lastData)); +} + /** * Returns the trackers for a torrent in JSON format. * @@ -331,7 +374,7 @@ QByteArray btjson::getTrackersForTorrent(const QString& hash) tracker_list.append(tracker_dict); } } - catch(const std::exception& e) { + catch (const std::exception& e) { qWarning() << Q_FUNC_INFO << "Invalid torrent: " << misc::toQStringU(e.what()); return QByteArray(); } @@ -393,7 +436,7 @@ QByteArray btjson::getPropertiesForTorrent(const QString& hash) const qreal ratio = QBtSession::instance()->getRealRatio(status); data[KEY_PROP_RATIO] = ratio > QBtSession::MAX_RATIO ? -1 : ratio; } - catch(const std::exception& e) { + catch (const std::exception& e) { qWarning() << Q_FUNC_INFO << "Invalid torrent: " << misc::toQStringU(e.what()); return QByteArray(); } @@ -463,23 +506,57 @@ QByteArray btjson::getFilesForTorrent(const QString& hash) */ QByteArray btjson::getTransferInfo() { - QVariantMap info; + return json::toJson(getTranserInfoMap()); +} + +QVariantMap getTranserInfoMap() +{ + QVariantMap map; session_status sessionStatus = QBtSession::instance()->getSessionStatus(); session_settings sessionSettings = QBtSession::instance()->getSession()->settings(); - info[KEY_TRANSFER_DLSPEED] = sessionStatus.payload_download_rate; - info[KEY_TRANSFER_DLDATA] = static_cast(sessionStatus.total_payload_download); - info[KEY_TRANSFER_UPSPEED] = sessionStatus.payload_upload_rate; - info[KEY_TRANSFER_UPDATA] = static_cast(sessionStatus.total_payload_upload); - if (sessionSettings.download_rate_limit) - info[KEY_TRANSFER_DLRATELIMIT] = sessionSettings.download_rate_limit; - if (sessionSettings.upload_rate_limit) - info[KEY_TRANSFER_UPRATELIMIT] = sessionSettings.upload_rate_limit; - info[KEY_TRANSFER_DHT_NODES] = sessionStatus.dht_nodes; + map[KEY_TRANSFER_DLSPEED] = sessionStatus.payload_download_rate; + map[KEY_TRANSFER_DLDATA] = static_cast(sessionStatus.total_payload_download); + map[KEY_TRANSFER_UPSPEED] = sessionStatus.payload_upload_rate; + map[KEY_TRANSFER_UPDATA] = static_cast(sessionStatus.total_payload_upload); + map[KEY_TRANSFER_DLRATELIMIT] = sessionSettings.download_rate_limit; + map[KEY_TRANSFER_UPRATELIMIT] = sessionSettings.upload_rate_limit; + map[KEY_TRANSFER_DHT_NODES] = sessionStatus.dht_nodes; if (!QBtSession::instance()->getSession()->is_listening()) - info[KEY_TRANSFER_CONNECTION_STATUS] = "disconnected"; + map[KEY_TRANSFER_CONNECTION_STATUS] = "disconnected"; else - info[KEY_TRANSFER_CONNECTION_STATUS] = sessionStatus.has_incoming_connections ? "connected" : "firewalled"; - return json::toJson(info); + map[KEY_TRANSFER_CONNECTION_STATUS] = sessionStatus.has_incoming_connections ? "connected" : "firewalled"; + return map; +} + +QVariantMap toMap(const QTorrentHandle& h) +{ + libtorrent::torrent_status status = h.status(torrent_handle::query_accurate_download_counters); + + QVariantMap ret; + ret[KEY_TORRENT_HASH] = h.hash(); + ret[KEY_TORRENT_NAME] = h.name(); + ret[KEY_TORRENT_SIZE] = static_cast(status.total_wanted); + ret[KEY_TORRENT_PROGRESS] = h.progress(status); + ret[KEY_TORRENT_DLSPEED] = status.download_payload_rate; + ret[KEY_TORRENT_UPSPEED] = status.upload_payload_rate; + if (QBtSession::instance()->isQueueingEnabled() && h.queue_position(status) >= 0) + ret[KEY_TORRENT_PRIORITY] = h.queue_position(status); + else + ret[KEY_TORRENT_PRIORITY] = -1; + ret[KEY_TORRENT_SEEDS] = status.num_seeds; + ret[KEY_TORRENT_NUM_COMPLETE] = status.num_complete; + ret[KEY_TORRENT_LEECHS] = status.num_peers - status.num_seeds; + ret[KEY_TORRENT_NUM_INCOMPLETE] = status.num_incomplete; + const qreal ratio = QBtSession::instance()->getRealRatio(status); + ret[KEY_TORRENT_RATIO] = (ratio > QBtSession::MAX_RATIO) ? -1 : ratio; + ret[KEY_TORRENT_STATE] = h.torrentState().toString(); + ret[KEY_TORRENT_ETA] = h.eta(); + ret[KEY_TORRENT_SEQUENTIAL_DOWNLOAD] = status.sequential_download; + if (h.has_metadata()) + ret[KEY_TORRENT_FIRST_LAST_PIECE_PRIO] = h.first_last_piece_first(); + ret[KEY_TORRENT_LABEL] = TorrentPersistentData::getLabel(h.hash()); + + return ret; } // Compare two structures (prevData, data) and calculate difference (syncData). @@ -639,4 +716,4 @@ QVariantMap generateSyncData(int acceptedResponseId, QVariantMap data, QVariantM syncData[KEY_RESPONSE_ID] = lastResponseId; return syncData; -} \ No newline at end of file +} diff --git a/src/webui/btjson.h b/src/webui/btjson.h index e8bf66896..2d5f7e8eb 100644 --- a/src/webui/btjson.h +++ b/src/webui/btjson.h @@ -33,6 +33,7 @@ #include #include +#include class QTorrentHandle; @@ -46,6 +47,7 @@ private: public: static QByteArray getTorrents(QString filter = "all", QString label = QString(), QString sortedColumn = "name", bool reverse = false, int limit = 0, int offset = 0); + static QByteArray getSyncMainData(int acceptedResponseId, QVariantMap &lastData, QVariantMap &lastAcceptedData); static QByteArray getTrackersForTorrent(const QString& hash); static QByteArray getPropertiesForTorrent(const QString& hash); static QByteArray getFilesForTorrent(const QString& hash); diff --git a/src/webui/requesthandler.cpp b/src/webui/requesthandler.cpp index bbb9cc436..ba893bf9b 100644 --- a/src/webui/requesthandler.cpp +++ b/src/webui/requesthandler.cpp @@ -48,6 +48,7 @@ #include "prefjson.h" #include "qbtsession.h" #include "requesthandler.h" +#include "webapplication.h" using namespace libtorrent; @@ -82,6 +83,7 @@ QMap > RequestHandler::initialize ADD_ACTION(json, propertiesGeneral); ADD_ACTION(json, propertiesTrackers); ADD_ACTION(json, propertiesFiles); + ADD_ACTION(sync, maindata); ADD_ACTION(command, shutdown); ADD_ACTION(command, download); ADD_ACTION(command, upload); @@ -261,6 +263,14 @@ void RequestHandler::action_json_propertiesFiles() print(btjson::getFilesForTorrent(args_.front()), CONTENT_TYPE_JS); } +// GET param: +// - rid (int): last response id +void RequestHandler::action_sync_maindata() +{ + CHECK_URI(0); + print(btjson::getSyncMainData(request().gets["rid"].toInt(), session()->syncMainDataLastResponse, session()->syncMainDataLastAcceptedResponse)); +} + void RequestHandler::action_version_api() { CHECK_URI(0); diff --git a/src/webui/requesthandler.h b/src/webui/requesthandler.h index 5597dc4bf..afa3564ff 100644 --- a/src/webui/requesthandler.h +++ b/src/webui/requesthandler.h @@ -56,6 +56,7 @@ private: void action_json_propertiesGeneral(); void action_json_propertiesTrackers(); void action_json_propertiesFiles(); + void action_sync_maindata(); void action_command_shutdown(); void action_command_download(); void action_command_upload(); diff --git a/src/webui/webapplication.h b/src/webui/webapplication.h index be03f6b17..f35f67009 100644 --- a/src/webui/webapplication.h +++ b/src/webui/webapplication.h @@ -33,11 +33,13 @@ #include #include #include "httptypes.h" +#include struct WebSession { const QString id; - + QVariantMap syncMainDataLastResponse; + QVariantMap syncMainDataLastAcceptedResponse; WebSession(const QString& id): id(id) {} };