Changeset View
Changeset View
Standalone View
Standalone View
plugins/htmlinterface/torrentlistgenerator.cpp
Show All 16 Lines | |||||
17 | * GNU General Public License for more details. * | 17 | * GNU General Public License for more details. * | ||
18 | * * | 18 | * * | ||
19 | * You should have received a copy of the GNU General Public License * | 19 | * You should have received a copy of the GNU General Public License * | ||
20 | * along with this program; if not, write to the * | 20 | * along with this program; if not, write to the * | ||
21 | * Free Software Foundation, Inc., * | 21 | * Free Software Foundation, Inc., * | ||
22 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * | 22 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * | ||
23 | ***************************************************************************/ | 23 | ***************************************************************************/ | ||
24 | 24 | | |||
25 | #include <QChar> | ||||
25 | #include <QJsonDocument> | 26 | #include <QJsonDocument> | ||
26 | #include <QJsonObject> | 27 | #include <QJsonObject> | ||
27 | #include <QJsonArray> | 28 | #include <QJsonArray> | ||
28 | #include <QJsonValue> | 29 | #include <QJsonValue> | ||
29 | #include <QMap> | 30 | #include <QMap> | ||
30 | #include <QString> | 31 | #include <QString> | ||
31 | #include <iostream> | 32 | #include <iostream> | ||
32 | 33 | | |||
33 | #include "torrentlistgenerator.h" | 34 | #include "torrentlistgenerator.h" | ||
34 | #include <util/sha1hash.h> | 35 | #include <util/sha1hash.h> | ||
35 | #include <torrent/queuemanager.h> | 36 | #include <torrent/queuemanager.h> | ||
37 | #include <torrent/magnetmanager.h> | ||||
36 | #include <interfaces/coreinterface.h> | 38 | #include <interfaces/coreinterface.h> | ||
37 | 39 | | |||
38 | using namespace bt; | 40 | using namespace bt; | ||
39 | using namespace std; | 41 | using namespace std; | ||
40 | 42 | | |||
41 | namespace kt | 43 | namespace kt | ||
42 | { | 44 | { | ||
43 | 45 | | |||
44 | TorrentListGenerator::TorrentListGenerator(CoreInterface* core): core(core) | 46 | TorrentListGenerator::TorrentListGenerator(CoreInterface* core): core(core) | ||
45 | { | 47 | { | ||
46 | } | 48 | } | ||
47 | 49 | | |||
48 | 50 | | |||
49 | TorrentListGenerator::~TorrentListGenerator() | 51 | TorrentListGenerator::~TorrentListGenerator() | ||
50 | { | 52 | { | ||
51 | } | 53 | } | ||
52 | 54 | | |||
53 | 55 | | |||
54 | void TorrentListGenerator::get(char ** str_p, int * size) | 56 | QByteArray TorrentListGenerator::get() | ||
55 | { | 57 | { | ||
56 | kt::QueueManager* qman = core->getQueueManager(); | 58 | kt::QueueManager* qman = core->getQueueManager(); | ||
pino: `QJsonArray array;` is enough (also for other variables in this file). | |||||
57 | kt::QueueManager::iterator i = qman->begin(); | 59 | kt::QueueManager::iterator i = qman->begin(); | ||
58 | QJsonArray array = QJsonArray(); | 60 | QJsonArray array; | ||
59 | while (i != qman->end()) | 61 | while (i != qman->end()) | ||
60 | { | 62 | { | ||
61 | bt::TorrentInterface* ti = *i; | 63 | bt::TorrentInterface* ti = *i; | ||
62 | const bt::TorrentStats& s = ti->getStats(); | 64 | const bt::TorrentStats& s = ti->getStats(); | ||
63 | 65 | | |||
64 | QJsonObject json = QJsonObject() ; | 66 | QJsonObject json; | ||
65 | json.insert(QString::fromLocal8Bit("name"), ti->getDisplayName()); | 67 | json.insert(QString::fromLatin1("name"), ti->getDisplayName()); | ||
66 | json.insert(QString::fromLocal8Bit("infoHash"), ti->getInfoHash().toString()); | 68 | json.insert(QString::fromLatin1("infoHash"), ti->getInfoHash().toString()); | ||
67 | json.insert(QString::fromLocal8Bit("status"), s.status); | 69 | json.insert(QString::fromLatin1("status"), s.status); | ||
68 | json.insert(QString::fromLocal8Bit("timeAdded"), s.time_added.toMSecsSinceEpoch()); | 70 | json.insert(QString::fromLatin1("timeAdded"), s.time_added.toMSecsSinceEpoch()); | ||
69 | json.insert(QString::fromLocal8Bit("bytesDownloaded"), (double) s.bytes_downloaded); | 71 | json.insert(QString::fromLatin1("bytesDownloaded"), (double) s.bytes_downloaded); | ||
70 | json.insert(QString::fromLocal8Bit("bytesUploaded"), (double) s.bytes_uploaded); | 72 | json.insert(QString::fromLatin1("bytesUploaded"), (double) s.bytes_uploaded); | ||
71 | json.insert(QString::fromLocal8Bit("totalBytes"), (double) s.total_bytes); | 73 | json.insert(QString::fromLatin1("totalBytes"), (double) s.total_bytes); | ||
72 | json.insert(QString::fromLocal8Bit("totalBytesToDownload"), (double) s.total_bytes_to_download); | 74 | json.insert(QString::fromLatin1("totalBytesToDownload"), (double) s.total_bytes_to_download); | ||
73 | json.insert(QString::fromLocal8Bit("downloadRate"), (double) s.download_rate); | 75 | json.insert(QString::fromLatin1("downloadRate"), (double) s.download_rate); | ||
74 | json.insert(QString::fromLocal8Bit("uploadRate"), (double) s.upload_rate); | 76 | json.insert(QString::fromLatin1("uploadRate"), (double) s.upload_rate); | ||
75 | json.insert(QString::fromLocal8Bit("numPeers"), (double) s.num_peers); | 77 | json.insert(QString::fromLatin1("numPeers"), (double) s.num_peers); | ||
76 | json.insert(QString::fromLocal8Bit("seeders"), (double) s.seeders_connected_to); | 78 | json.insert(QString::fromLatin1("seeders"), (double) s.seeders_connected_to); | ||
77 | json.insert(QString::fromLocal8Bit("seedersTotal"), (double) s.seeders_total); | 79 | json.insert(QString::fromLatin1("seedersTotal"), (double) s.seeders_total); | ||
78 | json.insert(QString::fromLocal8Bit("leechers"), (double) s.leechers_connected_to); | 80 | json.insert(QString::fromLatin1("leechers"), (double) s.leechers_connected_to); | ||
79 | json.insert(QString::fromLocal8Bit("leechersTotal"), (double) s.leechers_total); | 81 | json.insert(QString::fromLatin1("leechersTotal"), (double) s.leechers_total); | ||
80 | json.insert(QString::fromLocal8Bit("running"), s.running); | 82 | json.insert(QString::fromLatin1("running"), s.running); | ||
81 | json.insert(QString::fromLocal8Bit("numFiles"), (double) ti->getNumFiles()); | 83 | json.insert(QString::fromLatin1("numFiles"), (double) ti->getNumFiles()); | ||
82 | array.append(json); | 84 | array.append(json); | ||
83 | i++; | 85 | i++; | ||
84 | } | 86 | } | ||
85 | QJsonObject message = QJsonObject(); | 87 | QJsonObject message; | ||
86 | message.insert(QString::fromLocal8Bit("torrents"), array); | 88 | message.insert(QString::fromLatin1("torrents"), array); | ||
87 | QJsonDocument doc = QJsonDocument(message); | 89 | return QJsonDocument(message).toJson(); | ||
This converts the document to QByteArray twice. pino: This converts the document to QByteArray twice.
Also, when the scope of this block ends, the… | |||||
88 | *str_p = doc.toJson().data(); | | |||
89 | *size = doc.toJson().size(); | | |||
90 | } | 90 | } | ||
91 | 91 | | |||
92 | void TorrentListGenerator::post(char * json) { | 92 | void TorrentListGenerator::post(QString json) | ||
Since it does not modify its argument, make the json parameter of post as const char * (and remove the cast later on). pino: Since it does not modify its argument, make the `json` parameter of `post` as `const char *`… | |||||
93 | QJsonDocument doc = QJsonDocument::fromJson(QByteArray((const char *) json)); | 93 | { | ||
94 | QJsonDocument doc = QJsonDocument::fromJson(json.toLatin1()); | ||||
94 | QMap<QString, QVariant> qJson = doc.toVariant().toMap(); | 95 | QMap<QString, QVariant> qJson = doc.toVariant().toMap(); | ||
95 | 96 | | |||
96 | QString action = qJson[QString::fromLatin1("type")].toString(); | 97 | QString action = qJson[QString::fromLatin1("type")].toString(); | ||
97 | 98 | | |||
An null QString is also empty, so just check for isEmpty (also in other places in this file). pino: An null QString is also empty, so just check for `isEmpty` (also in other places in this file). | |||||
98 | if (action.isEmpty() || action.isNull()) { | 99 | if (action.isEmpty()) | ||
100 | { | ||||
99 | return; | 101 | return; | ||
100 | } | 102 | } | ||
101 | 103 | | |||
102 | if (action == QString::fromLatin1("magnet")) { | 104 | if (action == QString::fromLatin1("magnet")) | ||
105 | { | ||||
103 | QString magnet = qJson[QString::fromLatin1("magnet")].toString(); | 106 | QString magnet = qJson[QString::fromLatin1("magnet")].toString(); | ||
104 | if (magnet.isEmpty() || magnet.isNull()) { | 107 | if (magnet.isEmpty()) | ||
108 | { | ||||
109 | return; | ||||
110 | } | ||||
111 | QUrl url = QUrl(magnet); | ||||
112 | if (!url.isValid()) | ||||
113 | { | ||||
105 | return; | 114 | return; | ||
106 | } | 115 | } | ||
107 | core->loadSilently(QUrl(magnet), QString()); | 116 | core->loadSilently(url, QString()); | ||
108 | return; | 117 | return; | ||
109 | } | 118 | } | ||
110 | 119 | | |||
111 | QString hash = qJson[QString::fromLatin1("hash")].toString(); | 120 | QString hash = qJson[QString::fromLatin1("hash")].toString(); | ||
112 | if (hash.isEmpty() || hash.isNull()) { | 121 | if (hash.isEmpty()) | ||
122 | { | ||||
113 | return; | 123 | return; | ||
114 | } | 124 | } | ||
115 | 125 | | |||
116 | TorrentInterface * ti = getTorrentFromHash(hash); | 126 | TorrentInterface * ti = getTorrentFromHash(hash); | ||
117 | if (action == QString::fromLatin1("start")) { | 127 | if (action == QString::fromLatin1("start")) | ||
118 | if (ti->getStats().paused) { | 128 | { | ||
129 | if (ti->getStats().paused) | ||||
Chain the various if's together, so not all the checks will be performed every time: if (action == QLatin1String("start")) { ... } else if (action == QLatin1String("pause")) { ... } ... pino: Chain the various if's together, so not all the checks will be performed every time:
```if… | |||||
130 | { | ||||
119 | ti->unpause(); | 131 | ti->unpause(); | ||
120 | } else { | 132 | } | ||
133 | else | ||||
134 | { | ||||
121 | ti->start(); | 135 | ti->start(); | ||
122 | } | 136 | } | ||
123 | } | 137 | } | ||
124 | if (action == QString::fromLatin1("pause")) { | 138 | else if (action == QString::fromLatin1("stop")) | ||
125 | ti->pause(); | 139 | { | ||
140 | core->stop(ti); | ||||
pino: `hash` is leaked. Just return it by value in `QStringToSHA1Hash`. | |||||
126 | } | 141 | } | ||
127 | if (action == QString::fromLatin1("remove")) { | 142 | else if (action == QString::fromLatin1("remove")) | ||
143 | { | ||||
128 | core->remove(ti, false); | 144 | core->remove(ti, false); | ||
129 | } | 145 | } | ||
130 | } | 146 | } | ||
131 | 147 | | |||
132 | const SHA1Hash * TorrentListGenerator::QStringToSHA1Hash(QString qString) { | 148 | /** | ||
133 | Uint8 hashNum[20] = {}; | 149 | * From: https://github.com/KDE/libktorrent/blob/master/src/dht/tests/keytest.cpp | ||
134 | hex2bin((const char *) qString.toLatin1().data(), hashNum); | 150 | */ | ||
151 | static Uint8 HexCharToUint8(char c) | ||||
152 | { | ||||
153 | if (c >= 'a' && c <= 'f') | ||||
154 | return 10 + (c - 'a'); | ||||
155 | else if (c >= 'A' && c <= 'F') | ||||
156 | return 10 + (c - 'A'); | ||||
157 | else if (c >= '0' && c <= '9') | ||||
158 | return c - '0'; | ||||
159 | else | ||||
160 | return 0; | ||||
161 | } | ||||
162 | | ||||
163 | /** | ||||
164 | * Based on: https://github.com/KDE/libktorrent/blob/master/src/dht/tests/keytest.cpp | ||||
165 | */ | ||||
166 | static Uint8 * HashFromHexString(QString & str) | ||||
167 | { | ||||
168 | bt::Uint8 * result = new Uint8[20]; | ||||
169 | std::fill(result, result + 20, 0); | ||||
170 | | ||||
171 | QString s = str.toLower(); | ||||
172 | if (s.size() % 2 != 0) | ||||
173 | { | ||||
174 | s.prepend(QChar::fromLatin1('0')); | ||||
175 | } | ||||
176 | | ||||
177 | int j = 19; | ||||
178 | | ||||
179 | for (int i = s.size() - 1; i >= 0; i -= 2) | ||||
180 | { | ||||
181 | char left = s[i - 1].toLatin1(); | ||||
Instead of shamelessly copying code from stackoverflow, use at least code already written in libktorrent: in src/dht/tests/keytest.cpp, see HexCharToUint8 (usable as-is) and KeyFromHexString (mostly similar). pino: Instead of shamelessly copying code from stackoverflow, use at least code already written in… | |||||
182 | char right = s[i].toLatin1(); | ||||
183 | result[j--] = (HexCharToUint8(left) << 4) | HexCharToUint8(right); | ||||
184 | } | ||||
185 | return result; | ||||
186 | } | ||||
187 | | ||||
188 | static const SHA1Hash * QStringToSHA1Hash(QString qString) { | ||||
189 | Uint8 * hashNum = HashFromHexString(qString); | ||||
135 | const SHA1Hash * hash = new SHA1Hash(hashNum); | 190 | const SHA1Hash * hash = new SHA1Hash(hashNum); | ||
191 | delete hashNum; | ||||
136 | return hash; | 192 | return hash; | ||
137 | } | 193 | } | ||
138 | 194 | | |||
139 | TorrentInterface * TorrentListGenerator::getTorrentFromHash(QString qHash) { | 195 | TorrentInterface * TorrentListGenerator::getTorrentFromHash(QString qHash) | ||
196 | { | ||||
140 | const SHA1Hash * hash = QStringToSHA1Hash(qHash); | 197 | const SHA1Hash * hash = QStringToSHA1Hash(qHash); | ||
141 | kt::QueueManager* qman = core->getQueueManager(); | 198 | kt::QueueManager* qman = core->getQueueManager(); | ||
142 | kt::QueueManager::iterator i = qman->begin(); | 199 | kt::QueueManager::iterator i = qman->begin(); | ||
143 | while (i != qman->end()) | 200 | while (i != qman->end()) | ||
144 | { | 201 | { | ||
145 | bt::TorrentInterface* ti = *i; | 202 | bt::TorrentInterface* ti = *i; | ||
146 | const bt::TorrentStats& s = ti->getStats(); | 203 | if (ti->getInfoHash() == *hash) | ||
147 | if (ti->getInfoHash() == *hash) { | 204 | { | ||
205 | delete hash; | ||||
148 | return ti; | 206 | return ti; | ||
149 | } | 207 | } | ||
150 | i++; | 208 | i++; | ||
151 | } | 209 | } | ||
210 | delete hash; | ||||
152 | return NULL; | 211 | return NULL; | ||
153 | } | 212 | } | ||
154 | | ||||
155 | /** | | |||
156 | * Shameless ripped from: https://stackoverflow.com/a/17261928/313273 | | |||
157 | */ | | |||
158 | Uint8 TorrentListGenerator::char2int(char input) | | |||
159 | { | | |||
160 | if(input >= '0' && input <= '9') | | |||
161 | return (Uint8) input - '0'; | | |||
162 | if(input >= 'A' && input <= 'F') | | |||
163 | return (Uint8) input - 'A' + 10; | | |||
164 | if(input >= 'a' && input <= 'f') | | |||
165 | return (Uint8) input - 'a' + 10; | | |||
166 | throw std::invalid_argument("Invalid input string"); | | |||
167 | } | | |||
168 | | ||||
169 | /** | | |||
170 | * Shamelessly ripped from: https://stackoverflow.com/a/17261928/313273 | | |||
171 | * This function assumes src to be a zero terminated sanitized string with | | |||
172 | * an even number of [0-9a-f] characters, and target to be sufficiently large. | | |||
173 | */ | | |||
174 | void TorrentListGenerator::hex2bin(const char * src, Uint8 * target) | | |||
175 | { | | |||
176 | while(*src && src[1]) | | |||
177 | { | | |||
178 | *(target++) = char2int(*src) * 16 + char2int(src[1]); | | |||
179 | src += 2; | | |||
180 | } | | |||
181 | } | | |||
182 | } | 213 | } |
QJsonArray array; is enough (also for other variables in this file).