Handle multiple identities in a bcmr

This commit is contained in:
2025-04-10 16:25:43 +02:00
parent cf07797350
commit 831589ef2a
2 changed files with 69 additions and 37 deletions
+59 -34
View File
@@ -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<MetaBCMR*>(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;
}
+10 -3
View File
@@ -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<struct MetaCategory*> tokens;
QSet<QString> resources;
};
struct MetaBCMR {
QString hash;
QString origFilename;
std::vector<MetaIdentity*> identities;
MetaIdentity* idForCategory(const QString &category) const;
};
struct MetaCategory {
QString category;