feat: add "table" format in torrent-get RPC (#1049)
* feat: add optional "format" arg to torrent-get RPC If the "format" request was "objects" (default), "torrents" will be an array of objects, each of which contains the key/value pairs matching the request's "fields" arg. This is unchanged from previous versions. If the format was "table", then "torrents" will be an array of arrays. The first row holds the keys and each remaining row holds a torrent's values for those keys. This format is more efficient in terms of JSON generation and JSON parsing.
This commit is contained in:
parent
d857a5821a
commit
96f76999aa
|
@ -148,11 +148,25 @@
|
|||
|
||||
(1) An optional "ids" array as described in 3.1.
|
||||
(2) A required "fields" array of keys. (see list below)
|
||||
(3) An optional "format" string specifying how to format the
|
||||
"torrents" response field. Allowed values are "objects" (default)
|
||||
and "table". (see "Response arguments" below)
|
||||
|
||||
Response arguments:
|
||||
|
||||
(1) A "torrents" array of objects, each of which contains
|
||||
the key/value pairs matching the request's "fields" argument.
|
||||
(1) A "torrents" array.
|
||||
|
||||
If the "format" request was "objects" (default), "torrents" will
|
||||
be an array of objects, each of which contains the key/value
|
||||
pairs matching the request's "fields" arg. This was the only
|
||||
format before Transmission 3 and has some obvious programmer
|
||||
conveniences, such as parsing directly into Javascript objects.
|
||||
|
||||
If the format was "table", then "torrents" will be an array of
|
||||
arrays. The first row holds the keys and each remaining row holds
|
||||
a torrent's values for those keys. This format is more efficient
|
||||
in terms of JSON generation and JSON parsing.
|
||||
|
||||
(2) If the request's "ids" field was "recently-active",
|
||||
a "removed" array of torrent-id numbers of recently-removed
|
||||
torrents.
|
||||
|
@ -792,6 +806,7 @@
|
|||
| | yes | session-get | new arg "session-id"
|
||||
| | yes | torrent-get | new arg "labels"
|
||||
| | yes | torrent-set | new arg "labels"
|
||||
| | yes | torrent-get | new arg "format"
|
||||
|
||||
|
||||
5.1. Upcoming Breakage
|
||||
|
|
|
@ -125,6 +125,7 @@ static struct tr_key_struct const my_static[] =
|
|||
Q("filter-trackers"),
|
||||
Q("flagStr"),
|
||||
Q("flags"),
|
||||
Q("format"),
|
||||
Q("fromCache"),
|
||||
Q("fromDht"),
|
||||
Q("fromIncoming"),
|
||||
|
|
|
@ -125,6 +125,7 @@ enum
|
|||
TR_KEY_filter_trackers,
|
||||
TR_KEY_flagStr,
|
||||
TR_KEY_flags,
|
||||
TR_KEY_format,
|
||||
TR_KEY_fromCache,
|
||||
TR_KEY_fromDht,
|
||||
TR_KEY_fromIncoming,
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "stats.h"
|
||||
#include "torrent.h"
|
||||
#include "tr-assert.h"
|
||||
#include "tr-macros.h"
|
||||
#include "utils.h"
|
||||
#include "variant.h"
|
||||
#include "version.h"
|
||||
|
@ -45,6 +46,13 @@
|
|||
#define dbgmsg(...) tr_logAddDeepNamed("RPC", __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TR_FORMAT_OBJECT = 0,
|
||||
TR_FORMAT_TABLE
|
||||
}
|
||||
tr_format;
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
@ -532,183 +540,185 @@ static void addPeers(tr_torrent* tor, tr_variant* list)
|
|||
tr_torrentPeersFree(peers, peerCount);
|
||||
}
|
||||
|
||||
static void addField(tr_torrent* const tor, tr_info const* const inf, tr_stat const* const st, tr_variant* const d,
|
||||
tr_quark const key)
|
||||
static void initField(tr_torrent* const tor, tr_info const* const inf, tr_stat const* const st, tr_variant* const initme,
|
||||
tr_quark key)
|
||||
{
|
||||
char* str;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case TR_KEY_activityDate:
|
||||
tr_variantDictAddInt(d, key, st->activityDate);
|
||||
tr_variantInitInt(initme, st->activityDate);
|
||||
break;
|
||||
|
||||
case TR_KEY_addedDate:
|
||||
tr_variantDictAddInt(d, key, st->addedDate);
|
||||
tr_variantInitInt(initme, st->addedDate);
|
||||
break;
|
||||
|
||||
case TR_KEY_bandwidthPriority:
|
||||
tr_variantDictAddInt(d, key, tr_torrentGetPriority(tor));
|
||||
tr_variantInitInt(initme, tr_torrentGetPriority(tor));
|
||||
break;
|
||||
|
||||
case TR_KEY_comment:
|
||||
tr_variantDictAddStr(d, key, inf->comment != NULL ? inf->comment : "");
|
||||
tr_variantInitStr(initme, inf->comment != NULL ? inf->comment : "", TR_BAD_SIZE);
|
||||
break;
|
||||
|
||||
case TR_KEY_corruptEver:
|
||||
tr_variantDictAddInt(d, key, st->corruptEver);
|
||||
tr_variantInitInt(initme, st->corruptEver);
|
||||
break;
|
||||
|
||||
case TR_KEY_creator:
|
||||
tr_variantDictAddStr(d, key, inf->creator != NULL ? inf->creator : "");
|
||||
tr_variantInitStr(initme, inf->creator != NULL ? inf->creator : "", TR_BAD_SIZE);
|
||||
break;
|
||||
|
||||
case TR_KEY_dateCreated:
|
||||
tr_variantDictAddInt(d, key, inf->dateCreated);
|
||||
tr_variantInitInt(initme, inf->dateCreated);
|
||||
break;
|
||||
|
||||
case TR_KEY_desiredAvailable:
|
||||
tr_variantDictAddInt(d, key, st->desiredAvailable);
|
||||
tr_variantInitInt(initme, st->desiredAvailable);
|
||||
break;
|
||||
|
||||
case TR_KEY_doneDate:
|
||||
tr_variantDictAddInt(d, key, st->doneDate);
|
||||
tr_variantInitInt(initme, st->doneDate);
|
||||
break;
|
||||
|
||||
case TR_KEY_downloadDir:
|
||||
tr_variantDictAddStr(d, key, tr_torrentGetDownloadDir(tor));
|
||||
tr_variantInitStr(initme, tr_torrentGetDownloadDir(tor), TR_BAD_SIZE);
|
||||
break;
|
||||
|
||||
case TR_KEY_downloadedEver:
|
||||
tr_variantDictAddInt(d, key, st->downloadedEver);
|
||||
tr_variantInitInt(initme, st->downloadedEver);
|
||||
break;
|
||||
|
||||
case TR_KEY_downloadLimit:
|
||||
tr_variantDictAddInt(d, key, tr_torrentGetSpeedLimit_KBps(tor, TR_DOWN));
|
||||
tr_variantInitInt(initme, tr_torrentGetSpeedLimit_KBps(tor, TR_DOWN));
|
||||
break;
|
||||
|
||||
case TR_KEY_downloadLimited:
|
||||
tr_variantDictAddBool(d, key, tr_torrentUsesSpeedLimit(tor, TR_DOWN));
|
||||
tr_variantInitBool(initme, tr_torrentUsesSpeedLimit(tor, TR_DOWN));
|
||||
break;
|
||||
|
||||
case TR_KEY_error:
|
||||
tr_variantDictAddInt(d, key, st->error);
|
||||
tr_variantInitInt(initme, st->error);
|
||||
break;
|
||||
|
||||
case TR_KEY_errorString:
|
||||
tr_variantDictAddStr(d, key, st->errorString);
|
||||
tr_variantInitStr(initme, st->errorString, TR_BAD_SIZE);
|
||||
break;
|
||||
|
||||
case TR_KEY_eta:
|
||||
tr_variantDictAddInt(d, key, st->eta);
|
||||
tr_variantInitInt(initme, st->eta);
|
||||
break;
|
||||
|
||||
case TR_KEY_files:
|
||||
addFiles(tor, tr_variantDictAddList(d, key, inf->fileCount));
|
||||
tr_variantInitList(initme, inf->fileCount);
|
||||
addFiles(tor, initme);
|
||||
break;
|
||||
|
||||
case TR_KEY_fileStats:
|
||||
addFileStats(tor, tr_variantDictAddList(d, key, inf->fileCount));
|
||||
tr_variantInitList(initme, inf->fileCount);
|
||||
addFileStats(tor, initme);
|
||||
break;
|
||||
|
||||
case TR_KEY_hashString:
|
||||
tr_variantDictAddStr(d, key, tor->info.hashString);
|
||||
tr_variantInitStr(initme, tor->info.hashString, TR_BAD_SIZE);
|
||||
break;
|
||||
|
||||
case TR_KEY_haveUnchecked:
|
||||
tr_variantDictAddInt(d, key, st->haveUnchecked);
|
||||
tr_variantInitInt(initme, st->haveUnchecked);
|
||||
break;
|
||||
|
||||
case TR_KEY_haveValid:
|
||||
tr_variantDictAddInt(d, key, st->haveValid);
|
||||
tr_variantInitInt(initme, st->haveValid);
|
||||
break;
|
||||
|
||||
case TR_KEY_honorsSessionLimits:
|
||||
tr_variantDictAddBool(d, key, tr_torrentUsesSessionLimits(tor));
|
||||
tr_variantInitBool(initme, tr_torrentUsesSessionLimits(tor));
|
||||
break;
|
||||
|
||||
case TR_KEY_id:
|
||||
tr_variantDictAddInt(d, key, st->id);
|
||||
tr_variantInitInt(initme, st->id);
|
||||
break;
|
||||
|
||||
case TR_KEY_isFinished:
|
||||
tr_variantDictAddBool(d, key, st->finished);
|
||||
tr_variantInitBool(initme, st->finished);
|
||||
break;
|
||||
|
||||
case TR_KEY_isPrivate:
|
||||
tr_variantDictAddBool(d, key, tr_torrentIsPrivate(tor));
|
||||
tr_variantInitBool(initme, tr_torrentIsPrivate(tor));
|
||||
break;
|
||||
|
||||
case TR_KEY_isStalled:
|
||||
tr_variantDictAddBool(d, key, st->isStalled);
|
||||
tr_variantInitBool(initme, st->isStalled);
|
||||
break;
|
||||
|
||||
case TR_KEY_labels:
|
||||
addLabels(tor, tr_variantDictAdd(d, key));
|
||||
addLabels(tor, initme);
|
||||
break;
|
||||
|
||||
case TR_KEY_leftUntilDone:
|
||||
tr_variantDictAddInt(d, key, st->leftUntilDone);
|
||||
tr_variantInitInt(initme, st->leftUntilDone);
|
||||
break;
|
||||
|
||||
case TR_KEY_manualAnnounceTime:
|
||||
tr_variantDictAddInt(d, key, st->manualAnnounceTime);
|
||||
tr_variantInitInt(initme, st->manualAnnounceTime);
|
||||
break;
|
||||
|
||||
case TR_KEY_maxConnectedPeers:
|
||||
tr_variantDictAddInt(d, key, tr_torrentGetPeerLimit(tor));
|
||||
tr_variantInitInt(initme, tr_torrentGetPeerLimit(tor));
|
||||
break;
|
||||
|
||||
case TR_KEY_magnetLink:
|
||||
str = tr_torrentGetMagnetLink(tor);
|
||||
tr_variantDictAddStr(d, key, str);
|
||||
tr_variantInitStr(initme, str, TR_BAD_SIZE);
|
||||
tr_free(str);
|
||||
break;
|
||||
|
||||
case TR_KEY_metadataPercentComplete:
|
||||
tr_variantDictAddReal(d, key, st->metadataPercentComplete);
|
||||
tr_variantInitReal(initme, st->metadataPercentComplete);
|
||||
break;
|
||||
|
||||
case TR_KEY_name:
|
||||
tr_variantDictAddStr(d, key, tr_torrentName(tor));
|
||||
tr_variantInitStr(initme, tr_torrentName(tor), TR_BAD_SIZE);
|
||||
break;
|
||||
|
||||
case TR_KEY_percentDone:
|
||||
tr_variantDictAddReal(d, key, st->percentDone);
|
||||
tr_variantInitReal(initme, st->percentDone);
|
||||
break;
|
||||
|
||||
case TR_KEY_peer_limit:
|
||||
tr_variantDictAddInt(d, key, tr_torrentGetPeerLimit(tor));
|
||||
tr_variantInitInt(initme, tr_torrentGetPeerLimit(tor));
|
||||
break;
|
||||
|
||||
case TR_KEY_peers:
|
||||
addPeers(tor, tr_variantDictAdd(d, key));
|
||||
addPeers(tor, initme);
|
||||
break;
|
||||
|
||||
case TR_KEY_peersConnected:
|
||||
tr_variantDictAddInt(d, key, st->peersConnected);
|
||||
tr_variantInitInt(initme, st->peersConnected);
|
||||
break;
|
||||
|
||||
case TR_KEY_peersFrom:
|
||||
{
|
||||
tr_variant* tmp = tr_variantDictAddDict(d, key, 7);
|
||||
tr_variantInitDict(initme, 7);
|
||||
int const* f = st->peersFrom;
|
||||
tr_variantDictAddInt(tmp, TR_KEY_fromCache, f[TR_PEER_FROM_RESUME]);
|
||||
tr_variantDictAddInt(tmp, TR_KEY_fromDht, f[TR_PEER_FROM_DHT]);
|
||||
tr_variantDictAddInt(tmp, TR_KEY_fromIncoming, f[TR_PEER_FROM_INCOMING]);
|
||||
tr_variantDictAddInt(tmp, TR_KEY_fromLpd, f[TR_PEER_FROM_LPD]);
|
||||
tr_variantDictAddInt(tmp, TR_KEY_fromLtep, f[TR_PEER_FROM_LTEP]);
|
||||
tr_variantDictAddInt(tmp, TR_KEY_fromPex, f[TR_PEER_FROM_PEX]);
|
||||
tr_variantDictAddInt(tmp, TR_KEY_fromTracker, f[TR_PEER_FROM_TRACKER]);
|
||||
tr_variantDictAddInt(initme, TR_KEY_fromCache, f[TR_PEER_FROM_RESUME]);
|
||||
tr_variantDictAddInt(initme, TR_KEY_fromDht, f[TR_PEER_FROM_DHT]);
|
||||
tr_variantDictAddInt(initme, TR_KEY_fromIncoming, f[TR_PEER_FROM_INCOMING]);
|
||||
tr_variantDictAddInt(initme, TR_KEY_fromLpd, f[TR_PEER_FROM_LPD]);
|
||||
tr_variantDictAddInt(initme, TR_KEY_fromLtep, f[TR_PEER_FROM_LTEP]);
|
||||
tr_variantDictAddInt(initme, TR_KEY_fromPex, f[TR_PEER_FROM_PEX]);
|
||||
tr_variantDictAddInt(initme, TR_KEY_fromTracker, f[TR_PEER_FROM_TRACKER]);
|
||||
break;
|
||||
}
|
||||
|
||||
case TR_KEY_peersGettingFromUs:
|
||||
tr_variantDictAddInt(d, key, st->peersGettingFromUs);
|
||||
tr_variantInitInt(initme, st->peersGettingFromUs);
|
||||
break;
|
||||
|
||||
case TR_KEY_peersSendingToUs:
|
||||
tr_variantDictAddInt(d, key, st->peersSendingToUs);
|
||||
tr_variantInitInt(initme, st->peersSendingToUs);
|
||||
break;
|
||||
|
||||
case TR_KEY_pieces:
|
||||
|
@ -717,148 +727,146 @@ static void addField(tr_torrent* const tor, tr_info const* const inf, tr_stat co
|
|||
size_t byte_count = 0;
|
||||
void* bytes = tr_torrentCreatePieceBitfield(tor, &byte_count);
|
||||
char* str = tr_base64_encode(bytes, byte_count, NULL);
|
||||
tr_variantDictAddStr(d, key, str != NULL ? str : "");
|
||||
tr_variantInitStr(initme, str != NULL ? str : "", TR_BAD_SIZE);
|
||||
tr_free(str);
|
||||
tr_free(bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_variantDictAddStr(d, key, "");
|
||||
tr_variantInitStr(initme, "", 0);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TR_KEY_pieceCount:
|
||||
tr_variantDictAddInt(d, key, inf->pieceCount);
|
||||
tr_variantInitInt(initme, inf->pieceCount);
|
||||
break;
|
||||
|
||||
case TR_KEY_pieceSize:
|
||||
tr_variantDictAddInt(d, key, inf->pieceSize);
|
||||
tr_variantInitInt(initme, inf->pieceSize);
|
||||
break;
|
||||
|
||||
case TR_KEY_priorities:
|
||||
tr_variantInitList(initme, inf->fileCount);
|
||||
for (tr_file_index_t i = 0; i < inf->fileCount; ++i)
|
||||
{
|
||||
tr_variant* p = tr_variantDictAddList(d, key, inf->fileCount);
|
||||
|
||||
for (tr_file_index_t i = 0; i < inf->fileCount; ++i)
|
||||
{
|
||||
tr_variantListAddInt(p, inf->files[i].priority);
|
||||
}
|
||||
|
||||
break;
|
||||
tr_variantListAddInt(initme, inf->files[i].priority);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TR_KEY_queuePosition:
|
||||
tr_variantDictAddInt(d, key, st->queuePosition);
|
||||
tr_variantInitInt(initme, st->queuePosition);
|
||||
break;
|
||||
|
||||
case TR_KEY_etaIdle:
|
||||
tr_variantDictAddInt(d, key, st->etaIdle);
|
||||
tr_variantInitInt(initme, st->etaIdle);
|
||||
break;
|
||||
|
||||
case TR_KEY_rateDownload:
|
||||
tr_variantDictAddInt(d, key, toSpeedBytes(st->pieceDownloadSpeed_KBps));
|
||||
tr_variantInitInt(initme, toSpeedBytes(st->pieceDownloadSpeed_KBps));
|
||||
break;
|
||||
|
||||
case TR_KEY_rateUpload:
|
||||
tr_variantDictAddInt(d, key, toSpeedBytes(st->pieceUploadSpeed_KBps));
|
||||
tr_variantInitInt(initme, toSpeedBytes(st->pieceUploadSpeed_KBps));
|
||||
break;
|
||||
|
||||
case TR_KEY_recheckProgress:
|
||||
tr_variantDictAddReal(d, key, st->recheckProgress);
|
||||
tr_variantInitReal(initme, st->recheckProgress);
|
||||
break;
|
||||
|
||||
case TR_KEY_seedIdleLimit:
|
||||
tr_variantDictAddInt(d, key, tr_torrentGetIdleLimit(tor));
|
||||
tr_variantInitInt(initme, tr_torrentGetIdleLimit(tor));
|
||||
break;
|
||||
|
||||
case TR_KEY_seedIdleMode:
|
||||
tr_variantDictAddInt(d, key, tr_torrentGetIdleMode(tor));
|
||||
tr_variantInitInt(initme, tr_torrentGetIdleMode(tor));
|
||||
break;
|
||||
|
||||
case TR_KEY_seedRatioLimit:
|
||||
tr_variantDictAddReal(d, key, tr_torrentGetRatioLimit(tor));
|
||||
tr_variantInitReal(initme, tr_torrentGetRatioLimit(tor));
|
||||
break;
|
||||
|
||||
case TR_KEY_seedRatioMode:
|
||||
tr_variantDictAddInt(d, key, tr_torrentGetRatioMode(tor));
|
||||
tr_variantInitInt(initme, tr_torrentGetRatioMode(tor));
|
||||
break;
|
||||
|
||||
case TR_KEY_sizeWhenDone:
|
||||
tr_variantDictAddInt(d, key, st->sizeWhenDone);
|
||||
tr_variantInitInt(initme, st->sizeWhenDone);
|
||||
break;
|
||||
|
||||
case TR_KEY_startDate:
|
||||
tr_variantDictAddInt(d, key, st->startDate);
|
||||
tr_variantInitInt(initme, st->startDate);
|
||||
break;
|
||||
|
||||
case TR_KEY_status:
|
||||
tr_variantDictAddInt(d, key, st->activity);
|
||||
tr_variantInitInt(initme, st->activity);
|
||||
break;
|
||||
|
||||
case TR_KEY_secondsDownloading:
|
||||
tr_variantDictAddInt(d, key, st->secondsDownloading);
|
||||
tr_variantInitInt(initme, st->secondsDownloading);
|
||||
break;
|
||||
|
||||
case TR_KEY_secondsSeeding:
|
||||
tr_variantDictAddInt(d, key, st->secondsSeeding);
|
||||
tr_variantInitInt(initme, st->secondsSeeding);
|
||||
break;
|
||||
|
||||
case TR_KEY_trackers:
|
||||
addTrackers(inf, tr_variantDictAddList(d, key, inf->trackerCount));
|
||||
tr_variantInitList(initme, inf->trackerCount);
|
||||
addTrackers(inf, initme);
|
||||
break;
|
||||
|
||||
case TR_KEY_trackerStats:
|
||||
{
|
||||
int n;
|
||||
tr_tracker_stat* s = tr_torrentTrackers(tor, &n);
|
||||
addTrackerStats(s, n, tr_variantDictAddList(d, key, n));
|
||||
tr_variantInitList(initme, n);
|
||||
addTrackerStats(s, n, initme);
|
||||
tr_torrentTrackersFree(s, n);
|
||||
break;
|
||||
}
|
||||
|
||||
case TR_KEY_torrentFile:
|
||||
tr_variantDictAddStr(d, key, inf->torrent);
|
||||
tr_variantInitStr(initme, inf->torrent, TR_BAD_SIZE);
|
||||
break;
|
||||
|
||||
case TR_KEY_totalSize:
|
||||
tr_variantDictAddInt(d, key, inf->totalSize);
|
||||
tr_variantInitInt(initme, inf->totalSize);
|
||||
break;
|
||||
|
||||
case TR_KEY_uploadedEver:
|
||||
tr_variantDictAddInt(d, key, st->uploadedEver);
|
||||
tr_variantInitInt(initme, st->uploadedEver);
|
||||
break;
|
||||
|
||||
case TR_KEY_uploadLimit:
|
||||
tr_variantDictAddInt(d, key, tr_torrentGetSpeedLimit_KBps(tor, TR_UP));
|
||||
tr_variantInitInt(initme, tr_torrentGetSpeedLimit_KBps(tor, TR_UP));
|
||||
break;
|
||||
|
||||
case TR_KEY_uploadLimited:
|
||||
tr_variantDictAddBool(d, key, tr_torrentUsesSpeedLimit(tor, TR_UP));
|
||||
tr_variantInitBool(initme, tr_torrentUsesSpeedLimit(tor, TR_UP));
|
||||
break;
|
||||
|
||||
case TR_KEY_uploadRatio:
|
||||
tr_variantDictAddReal(d, key, st->ratio);
|
||||
tr_variantInitReal(initme, st->ratio);
|
||||
break;
|
||||
|
||||
case TR_KEY_wanted:
|
||||
tr_variantInitList(initme, inf->fileCount);
|
||||
|
||||
for (tr_file_index_t i = 0; i < inf->fileCount; ++i)
|
||||
{
|
||||
tr_variant* w = tr_variantDictAddList(d, key, inf->fileCount);
|
||||
|
||||
for (tr_file_index_t i = 0; i < inf->fileCount; ++i)
|
||||
{
|
||||
tr_variantListAddInt(w, inf->files[i].dnd ? 0 : 1);
|
||||
}
|
||||
|
||||
break;
|
||||
tr_variantListAddInt(initme, inf->files[i].dnd ? 0 : 1);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TR_KEY_webseeds:
|
||||
addWebseeds(inf, tr_variantDictAddList(d, key, inf->webseedCount));
|
||||
tr_variantInitList(initme, inf->webseedCount);
|
||||
addWebseeds(inf, initme);
|
||||
break;
|
||||
|
||||
case TR_KEY_webseedsSendingToUs:
|
||||
tr_variantDictAddInt(d, key, st->webseedsSendingToUs);
|
||||
tr_variantInitInt(initme, st->webseedsSendingToUs);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -866,26 +874,29 @@ static void addField(tr_torrent* const tor, tr_info const* const inf, tr_stat co
|
|||
}
|
||||
}
|
||||
|
||||
static void addInfo(tr_torrent* tor, tr_variant* d, tr_variant* fields)
|
||||
static void addTorrentInfo(tr_torrent* tor, tr_format format, tr_variant* entry, tr_quark const* fields, size_t fieldCount)
|
||||
{
|
||||
int const n = tr_variantListSize(fields);
|
||||
if (format == TR_FORMAT_TABLE)
|
||||
{
|
||||
tr_variantInitList(entry, fieldCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_variantInitDict(entry, fieldCount);
|
||||
}
|
||||
|
||||
tr_variantInitDict(d, n);
|
||||
|
||||
if (n > 0)
|
||||
if (fieldCount > 0)
|
||||
{
|
||||
tr_info const* const inf = tr_torrentInfo(tor);
|
||||
tr_stat const* const st = tr_torrentStat((tr_torrent*)tor);
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
for (size_t i = 0; i < fieldCount; ++i)
|
||||
{
|
||||
size_t len;
|
||||
char const* str;
|
||||
tr_variant* child = format == TR_FORMAT_TABLE ?
|
||||
tr_variantListAdd(entry) :
|
||||
tr_variantDictAdd(entry, fields[i]);
|
||||
|
||||
if (tr_variantGetStr(tr_variantListChild(fields, i), &str, &len))
|
||||
{
|
||||
addField(tor, inf, st, d, tr_quark_new(str, len));
|
||||
}
|
||||
initField(tor, inf, st, child, fields[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -897,10 +908,20 @@ static char const* torrentGet(tr_session* session, tr_variant* args_in, tr_varia
|
|||
|
||||
int torrentCount;
|
||||
tr_torrent** torrents = getTorrents(session, args_in, &torrentCount);
|
||||
tr_variant* list = tr_variantDictAddList(args_out, TR_KEY_torrents, torrentCount);
|
||||
tr_variant* list = tr_variantDictAddList(args_out, TR_KEY_torrents, torrentCount + 1);
|
||||
tr_variant* fields;
|
||||
char const* strVal;
|
||||
char const* errmsg = NULL;
|
||||
tr_format format;
|
||||
|
||||
if (tr_variantDictFindStr(args_in, TR_KEY_format, &strVal, NULL) && strcmp(strVal, "table") == 0)
|
||||
{
|
||||
format = TR_FORMAT_TABLE;
|
||||
}
|
||||
else /* default value */
|
||||
{
|
||||
format = TR_FORMAT_OBJECT;
|
||||
}
|
||||
|
||||
if (tr_variantDictFindStr(args_in, TR_KEY_ids, &strVal, NULL) && strcmp(strVal, "recently-active") == 0)
|
||||
{
|
||||
|
@ -932,10 +953,35 @@ static char const* torrentGet(tr_session* session, tr_variant* args_in, tr_varia
|
|||
}
|
||||
else
|
||||
{
|
||||
/* make an array of property name quarks */
|
||||
size_t keyCount = 0;
|
||||
size_t const n = tr_variantListSize(fields);
|
||||
tr_quark* keys = tr_new(tr_quark, n);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
size_t len;
|
||||
if (tr_variantGetStr(tr_variantListChild(fields, i), &strVal, &len))
|
||||
{
|
||||
keys[keyCount++] = tr_quark_new(strVal, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (format == TR_FORMAT_TABLE)
|
||||
{
|
||||
/* first entry is an array of property names */
|
||||
tr_variant* names = tr_variantListAddList(list, keyCount);
|
||||
for (size_t i = 0; i < keyCount; ++i)
|
||||
{
|
||||
tr_variantListAddQuark(names, keys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < torrentCount; ++i)
|
||||
{
|
||||
addInfo(torrents[i], tr_variantListAdd(list), fields);
|
||||
addTorrentInfo(torrents[i], format, tr_variantListAdd(list), keys, keyCount);
|
||||
}
|
||||
|
||||
tr_free(keys);
|
||||
}
|
||||
|
||||
tr_free(torrents);
|
||||
|
@ -1704,19 +1750,20 @@ static void addTorrentImpl(struct tr_rpc_idle_data* data, tr_ctor* ctor)
|
|||
|
||||
if (tor != NULL && key != 0)
|
||||
{
|
||||
tr_variant fields;
|
||||
tr_variantInitList(&fields, 3);
|
||||
tr_variantListAddStr(&fields, "id");
|
||||
tr_variantListAddStr(&fields, "name");
|
||||
tr_variantListAddStr(&fields, "hashString");
|
||||
addInfo(tor, tr_variantDictAdd(data->args_out, key), &fields);
|
||||
tr_quark const fields[] =
|
||||
{
|
||||
TR_KEY_id,
|
||||
TR_KEY_name,
|
||||
TR_KEY_hashString
|
||||
};
|
||||
|
||||
addTorrentInfo(tor, TR_FORMAT_OBJECT, tr_variantDictAdd(data->args_out, key), fields, TR_N_ELEMENTS(fields));
|
||||
|
||||
if (result == NULL)
|
||||
{
|
||||
notify(data->session, TR_RPC_TORRENT_ADDED, tor);
|
||||
}
|
||||
|
||||
tr_variantFree(&fields);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,8 +50,8 @@ private slots:
|
|||
private:
|
||||
void maybeUpdateBlocklist();
|
||||
void loadTranslations();
|
||||
void quitLater();
|
||||
QStringList getNames(QSet<int> const& ids) const;
|
||||
void quitLater();
|
||||
|
||||
private:
|
||||
Prefs* myPrefs;
|
||||
|
|
|
@ -552,7 +552,8 @@ void Session::torrentRenamePath(QSet<int> const& ids, QString const& oldpath, QS
|
|||
void Session::refreshTorrents(QSet<int> const& ids, KeyList const& keys)
|
||||
{
|
||||
tr_variant args;
|
||||
tr_variantInitDict(&args, 2);
|
||||
tr_variantInitDict(&args, 3);
|
||||
tr_variantDictAddStr(&args, TR_KEY_format, "table");
|
||||
addList(tr_variantDictAddList(&args, TR_KEY_fields, 0), keys);
|
||||
addOptionalIds(&args, ids);
|
||||
|
||||
|
|
|
@ -541,7 +541,7 @@ void Torrent::updateMimeIcon()
|
|||
****
|
||||
***/
|
||||
|
||||
bool Torrent::update(tr_variant* d)
|
||||
bool Torrent::update(tr_quark const* keys, tr_variant** values, size_t n)
|
||||
{
|
||||
static bool lookup_initialized = false;
|
||||
static int key_to_property_index[TR_N_KEYS];
|
||||
|
@ -562,12 +562,11 @@ bool Torrent::update(tr_variant* d)
|
|||
}
|
||||
}
|
||||
|
||||
tr_quark key;
|
||||
tr_variant* child;
|
||||
size_t pos = 0;
|
||||
|
||||
while (tr_variantDictChild(d, pos++, &key, &child))
|
||||
for (size_t pos = 0; pos < n; ++pos)
|
||||
{
|
||||
tr_quark key = keys[pos];
|
||||
tr_variant* child = values[pos];
|
||||
|
||||
int const property_index = key_to_property_index[key];
|
||||
|
||||
if (property_index == -1) // we're not interested in this one
|
||||
|
@ -669,10 +668,10 @@ bool Torrent::update(tr_variant* d)
|
|||
}
|
||||
}
|
||||
|
||||
tr_variant* files;
|
||||
|
||||
if (tr_variantDictFindList(d, TR_KEY_files, &files))
|
||||
auto it = std::find(keys, keys + n, TR_KEY_files);
|
||||
if (it != keys + n)
|
||||
{
|
||||
tr_variant* files = values[std::distance(keys, it)];
|
||||
char const* str;
|
||||
int64_t intVal;
|
||||
int i = 0;
|
||||
|
@ -704,8 +703,10 @@ bool Torrent::update(tr_variant* d)
|
|||
changed = true;
|
||||
}
|
||||
|
||||
if (tr_variantDictFindList(d, TR_KEY_fileStats, &files))
|
||||
it = std::find(keys, keys + n, TR_KEY_fileStats);
|
||||
if (it != keys + n)
|
||||
{
|
||||
tr_variant* files = values[std::distance(keys, it)];
|
||||
int const n = tr_variantListSize(files);
|
||||
|
||||
for (int i = 0; i < n && i < myFiles.size(); ++i)
|
||||
|
@ -734,51 +735,50 @@ bool Torrent::update(tr_variant* d)
|
|||
changed = true;
|
||||
}
|
||||
|
||||
tr_variant* trackers;
|
||||
|
||||
if (tr_variantDictFindList(d, TR_KEY_trackers, &trackers))
|
||||
it = std::find(keys, keys + n, TR_KEY_trackers);
|
||||
if (it != keys + n)
|
||||
{
|
||||
size_t len;
|
||||
char const* str;
|
||||
int i = 0;
|
||||
QStringList list;
|
||||
tr_variant* child;
|
||||
tr_variant* v = values[std::distance(keys, it)];
|
||||
|
||||
while ((child = tr_variantListChild(trackers, i++)) != nullptr)
|
||||
// build the new tracker list
|
||||
QStringList trackers;
|
||||
trackers.reserve(tr_variantListSize(v));
|
||||
tr_variant* child;
|
||||
int i = 0;
|
||||
while ((child = tr_variantListChild(v, i++)) != nullptr)
|
||||
{
|
||||
char const* str;
|
||||
size_t len;
|
||||
if (tr_variantDictFindStr(child, TR_KEY_announce, &str, &len))
|
||||
{
|
||||
qApp->faviconCache().add(QUrl(QString::fromUtf8(str)));
|
||||
list.append(QString::fromUtf8(str, len));
|
||||
trackers.append(QString::fromUtf8(str, len));
|
||||
}
|
||||
}
|
||||
|
||||
if (myValues[TRACKERS] != list)
|
||||
// update the trackers
|
||||
if (myValues[TRACKERS] != trackers)
|
||||
{
|
||||
QStringList hosts;
|
||||
|
||||
for (QString const& tracker : list)
|
||||
for (auto const& tracker : trackers)
|
||||
{
|
||||
QString const host = FaviconCache::getHost(QUrl(tracker));
|
||||
|
||||
if (!host.isEmpty())
|
||||
{
|
||||
hosts.append(host);
|
||||
}
|
||||
auto const url = QUrl(tracker);
|
||||
qApp->faviconCache().add(url);
|
||||
hosts.append(FaviconCache::getHost(url));
|
||||
}
|
||||
|
||||
hosts.removeDuplicates();
|
||||
hosts.removeOne(QString());
|
||||
|
||||
myValues[TRACKERS].setValue(list);
|
||||
myValues[TRACKERS].setValue(trackers);
|
||||
myValues[HOSTS].setValue(hosts);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
tr_variant* trackerStats;
|
||||
|
||||
if (tr_variantDictFindList(d, TR_KEY_trackerStats, &trackerStats))
|
||||
it = std::find(keys, keys + n, TR_KEY_trackerStats);
|
||||
if (it != keys + n)
|
||||
{
|
||||
tr_variant* trackerStats = values[std::distance(keys, it)];
|
||||
tr_variant* child;
|
||||
TrackerStatsList trackerStatsList;
|
||||
int childNum = 0;
|
||||
|
@ -924,10 +924,10 @@ bool Torrent::update(tr_variant* d)
|
|||
changed = true;
|
||||
}
|
||||
|
||||
tr_variant* peers;
|
||||
|
||||
if (tr_variantDictFindList(d, TR_KEY_peers, &peers))
|
||||
it = std::find(keys, keys + n, TR_KEY_peers);
|
||||
if (it != keys + n)
|
||||
{
|
||||
tr_variant* peers = values[std::distance(keys, it)];
|
||||
tr_variant* child;
|
||||
PeerList peerList;
|
||||
int childNum = 0;
|
||||
|
|
|
@ -580,7 +580,7 @@ public:
|
|||
return isWaitingToDownload() || isWaitingToSeed();
|
||||
}
|
||||
|
||||
bool update(tr_variant* dict);
|
||||
bool update(tr_quark const* keys, tr_variant** values, size_t n);
|
||||
|
||||
QIcon getMimeTypeIcon() const
|
||||
{
|
||||
|
|
|
@ -168,13 +168,77 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool isCompleteList)
|
|||
return (date != 0) && (difftime(now, date) < max_age);
|
||||
};
|
||||
|
||||
size_t i = 0;
|
||||
tr_variant* child;
|
||||
while ((child = tr_variantListChild(torrents, i++)) != nullptr)
|
||||
// build a list of the property keys
|
||||
tr_variant* const firstChild = tr_variantListChild(torrents, 0);
|
||||
bool const table = tr_variantIsList(firstChild);
|
||||
std::vector<tr_quark> keys;
|
||||
if (table)
|
||||
{
|
||||
int64_t id;
|
||||
// In 'table' format, the first entry in 'torrents' is an array of keys.
|
||||
// All the other entries are an array of the values for one torrent.
|
||||
char const* str;
|
||||
size_t len;
|
||||
size_t i = 0;
|
||||
while (tr_variantGetStr(tr_variantListChild(firstChild, i++), &str, &len))
|
||||
{
|
||||
keys.push_back(tr_quark_new(str, len));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// In 'object' format, every entry is an object with the same set of properties
|
||||
size_t i = 0;
|
||||
tr_quark key;
|
||||
tr_variant* value;
|
||||
while (firstChild && tr_variantDictChild(firstChild, i++, &key, &value))
|
||||
{
|
||||
keys.push_back(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (!tr_variantDictFindInt(child, TR_KEY_id, &id))
|
||||
// Find the position of TR_KEY_id so we can do torrent lookup
|
||||
auto const id_it = std::find(std::begin(keys), std::end(keys), TR_KEY_id);
|
||||
if (id_it == std::end(keys)) // no ids provided; we can't proceed
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto const id_pos = std::distance(std::begin(keys), id_it);
|
||||
|
||||
// Loop through the torrent records...
|
||||
std::vector<tr_variant*> values;
|
||||
values.reserve(keys.size());
|
||||
size_t tor_index = table ? 1 : 0;
|
||||
tr_variant* v;
|
||||
while ((v = tr_variantListChild(torrents, tor_index++)))
|
||||
{
|
||||
// Build an array of values
|
||||
values.clear();
|
||||
if (table)
|
||||
{
|
||||
// In table mode, v is already a list of values
|
||||
size_t i = 0;
|
||||
tr_variant* val;
|
||||
while ((val = tr_variantListChild(v, i++)))
|
||||
{
|
||||
values.push_back(val);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// In object mode, v is an object of torrent property key/vals
|
||||
size_t i = 0;
|
||||
tr_quark key;
|
||||
tr_variant* value;
|
||||
while (tr_variantDictChild(v, i++, &key, &value))
|
||||
{
|
||||
values.push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Find the torrent id
|
||||
int64_t id;
|
||||
if (!tr_variantGetInt(values[id_pos], &id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -192,7 +256,7 @@ void TorrentModel::updateTorrents(tr_variant* torrents, bool isCompleteList)
|
|||
leftUntilDone = tor->leftUntilDone();
|
||||
}
|
||||
|
||||
if (tor->update(child))
|
||||
if (tor->update(keys.data(), values.data(), keys.size()))
|
||||
{
|
||||
changed.insert(id);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue