From 831589ef2aea78045aa1302bca4f77182d7cb257 Mon Sep 17 00:00:00 2001 From: TomZ Date: Thu, 10 Apr 2025 16:25:43 +0200 Subject: [PATCH] Handle multiple identities in a bcmr --- src/Processor.cpp | 93 ++++++++++++++++++++++++++++++----------------- src/Processor.h | 13 +++++-- 2 files changed, 69 insertions(+), 37 deletions(-) diff --git a/src/Processor.cpp b/src/Processor.cpp index d226a23..8ecaf71 100644 --- a/src/Processor.cpp +++ b/src/Processor.cpp @@ -52,33 +52,36 @@ bool Processor::run() for (auto *source : m_sources) { assert(source); + assert(source->identities.size() > 0); QString outPath = m_outDir + source->hash + ".json"; if (!QFile::exists(outPath)) { - logCritical() << "Placing BCMR " << source->name << "as" << source->hash; + logCritical() << "Placing BCMR " << source->identities.at(0)->name << "as" << source->hash; QFile::copy(source->origFilename, outPath); } - for (const auto &resource : std::as_const(source->resources)) { - QUrl url(resource); - if (!url.isValid()) - continue; - QString path = m_outDir + source->hash + "/" + url.host() + url.path(); - if (QFile::exists(path)) - continue; - if (url.scheme() == "ipfs") { - // use the main gateway for download - url = QUrl(QString("https://ipfs.io/ipfs/%1").arg(resource.mid(7))); - } - if (url.scheme() == "http" || url.scheme() == "https") { - // schedule for download. - DownloadJob *job = new DownloadJob(&m_network); - job->setTargetFilePath(path); - job->setSourceUrl(url); - connect (job, &DownloadJob::finished, this, [=]() { - m_downloadJobs.removeAll(job); - QTimer::singleShot(1, this, SLOT(runDownloadQueue())); - }); - m_downloadJobs.append(job); + for (auto *id : source->identities) { + for (const auto &resource : std::as_const(id->resources)) { + QUrl url(resource); + if (!url.isValid()) + continue; + QString path = m_outDir + source->hash + "/" + url.host() + url.path(); + if (QFile::exists(path)) + continue; + if (url.scheme() == "ipfs") { + // use the main gateway for download + url = QUrl(QString("https://ipfs.io/ipfs/%1").arg(resource.mid(7))); + } + if (url.scheme() == "http" || url.scheme() == "https") { + // schedule for download. + DownloadJob *job = new DownloadJob(&m_network); + job->setTargetFilePath(path); + job->setSourceUrl(url); + connect (job, &DownloadJob::finished, this, [=]() { + m_downloadJobs.removeAll(job); + QTimer::singleShot(1, this, SLOT(runDownloadQueue())); + }); + m_downloadJobs.append(job); + } } } } @@ -88,15 +91,22 @@ bool Processor::run() MetaCategory *mc = i->second; QJsonArray sources; auto owners = std::vector(mc->owners.begin(), mc->owners.end()); - std::sort(owners.begin(), owners.end(), [](MetaBCMR *a, MetaBCMR *b) { - return a->timestamp > b->timestamp; + std::sort(owners.begin(), owners.end(), [mc](MetaBCMR *a, MetaBCMR *b) { + // we're sorting the bcmr itself, but we only really care about a + // single identity inside each of them. THAT is what we'll compare. + MetaIdentity *ai = a->idForCategory(mc->category); + assert(ai); + MetaIdentity *bi = b->idForCategory(mc->category); + assert(bi); + return ai->timestamp > bi->timestamp; }); for (auto owner : owners) { QJsonObject o; o.insert("bcmr", owner->hash); - o.insert("name", owner->name); - o.insert("timestamp", owner->timestampStr); + MetaIdentity *id = owner->idForCategory(mc->category); + o.insert("name", id->name); + o.insert("timestamp", id->timestampStr); sources.append(o); } QJsonObject root; @@ -212,9 +222,6 @@ void Processor::parseBCMR(const QString &path) if (me == nullptr) { me = new MetaBCMR(); me->origFilename = path; - me->name = revision["name"].toString(); - me->timestampStr = revisionDates.back(); - me->timestamp = QDateTime::fromString(me->timestampStr, Qt::ISODate); // calc hash CSHA256 hasher; hasher.write(data.constData(), data.size()); @@ -224,13 +231,20 @@ void Processor::parseBCMR(const QString &path) m_sources.push_back(me); } - logInfo() << "Found BCMR" << me->name << identity.key(); + MetaIdentity *id = new MetaIdentity(); + id->name = revision["name"].toString(); + id->timestampStr = revisionDates.back(); + id->timestamp = QDateTime::fromString(id->timestampStr, Qt::ISODate); + id->identity = identity.key(); + me->identities.push_back(id); + + logInfo() << "Found BCMR" << id->name << identity.key(); const auto uris_ = revision["uris"]; if (uris_.isObject()) { const auto uris = uris_.toObject(); auto icon = uris["icon"]; if (icon.isString()) - me->resources.insert(icon.toString()); + id->resources.insert(icon.toString()); } const auto token_ = revision["token"]; @@ -240,8 +254,9 @@ void Processor::parseBCMR(const QString &path) if (cat.size() != 64) { logCritical() << "found token, but category is invalid length" << cat.size(); } else { + id->category = cat; MetaCategory *mc = fetchOrCreate(cat); - me->tokens.push_back(mc); + id->tokens.push_back(mc); mc->owners.insert(me); // walk all nfts and extract image and icon resource urls auto types = token; @@ -255,10 +270,10 @@ void Processor::parseBCMR(const QString &path) continue; auto image = uris["image"]; if (image.isString()) - me->resources.insert(image.toString()); + id->resources.insert(image.toString()); auto icon = uris["icon"]; if (icon.isString()) - me->resources.insert(icon.toString()); + id->resources.insert(icon.toString()); } } @@ -295,3 +310,13 @@ Processor::MetaCategory *Processor::fetchOrCreate(const QString &catId) return mc; } + +Processor::MetaIdentity *Processor::MetaBCMR::idForCategory(const QString &category) const +{ + for (auto *i : identities) { + if (i->category == category) { + return i; + } + } + return nullptr; +} diff --git a/src/Processor.h b/src/Processor.h index c86307a..94f3c70 100644 --- a/src/Processor.h +++ b/src/Processor.h @@ -30,15 +30,22 @@ private: struct MetaCategory; MetaCategory *fetchOrCreate(const QString &catId); - struct MetaBCMR { - QString hash; - QString origFilename; + struct MetaIdentity { QString name; QString timestampStr; + QString category; // the sha256 of the token category + QString identity; // the 'key' of the identity (typically an auth-base) QDateTime timestamp; std::vector tokens; QSet resources; }; + struct MetaBCMR { + QString hash; + QString origFilename; + std::vector identities; + + MetaIdentity* idForCategory(const QString &category) const; + }; struct MetaCategory { QString category;