|
|
|
@ -154,6 +154,10 @@ QImage AvatarManager::fetch(const Ref& ref, bool original, bool gallery) { |
|
|
|
Job job; job.ref = ref; job.original = original; job.gallery = gallery; job.generation = m_generation; |
|
|
|
Job job; job.ref = ref; job.original = original; job.gallery = gallery; job.generation = m_generation; |
|
|
|
const auto record = m_records.value(ref.hash); |
|
|
|
const auto record = m_records.value(ref.hash); |
|
|
|
job.file = record.original.isEmpty() ? ref.hash + ".json" : (original ? record.original : record.preview); |
|
|
|
job.file = record.original.isEmpty() ? ref.hash + ".json" : (original ? record.original : record.preview); |
|
|
|
|
|
|
|
if (record.original.isEmpty()) { |
|
|
|
|
|
|
|
for (const auto& active : m_jobs) if (!active.upload && active.ref.hash == ref.hash && active.file == job.file) return {}; |
|
|
|
|
|
|
|
for (const auto& queued : m_queue) if (!queued.upload && queued.ref.hash == ref.hash && queued.file == job.file) return {}; |
|
|
|
|
|
|
|
} |
|
|
|
enqueue(job); pump(); return {}; |
|
|
|
enqueue(job); pump(); return {}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -168,20 +172,41 @@ void AvatarManager::openGallery(const QString& channel, quint64 owner) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void AvatarManager::closeGallery() { |
|
|
|
void AvatarManager::closeGallery() { |
|
|
|
|
|
|
|
m_galleryEpoch++; |
|
|
|
if (m_listId && gui_bridge_is_uasync_ready()) { |
|
|
|
if (m_listId && gui_bridge_is_uasync_ready()) { |
|
|
|
auto* q = (mf_cancel_request*)u_calloc(1, sizeof(mf_cancel_request)); |
|
|
|
auto* q = (mf_cancel_request*)u_calloc(1, sizeof(mf_cancel_request)); |
|
|
|
if (q) { q->inst = gui_bridge_get_inst(); q->id = m_listId; gui_bridge_post_uasync_fn(member_files_gui_cancel, q); } |
|
|
|
if (q) { q->inst = gui_bridge_get_inst(); q->id = m_listId; gui_bridge_post_uasync_fn(member_files_gui_cancel, q); } |
|
|
|
else DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "avatar: gallery cancel allocation failed"); |
|
|
|
else DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "avatar: gallery cancel allocation failed"); |
|
|
|
} |
|
|
|
} |
|
|
|
m_listId = 0; m_galleryRef = {}; m_gallery.clear(); m_catalog.clear(); m_listRetries = 0; |
|
|
|
m_listId = 0; m_galleryRef = {}; m_gallery.clear(); m_catalog.clear(); m_listRetries = 0; |
|
|
|
QQueue<Job> keep; while (!m_queue.isEmpty()) { const auto job = m_queue.dequeue(); if (!job.gallery) keep.enqueue(job); } |
|
|
|
auto needed = [this](const Job& job) { |
|
|
|
|
|
|
|
const QString context = key(job.ref.group, job.ref.owner); |
|
|
|
|
|
|
|
return !job.original && m_wanted.contains(context) && m_refs.value(context).hash == job.ref.hash; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
for (auto id : m_jobs.keys()) { |
|
|
|
|
|
|
|
auto& job = m_jobs[id]; |
|
|
|
|
|
|
|
if (!job.gallery) continue; |
|
|
|
|
|
|
|
if (needed(job)) { job.gallery = false; continue; } |
|
|
|
|
|
|
|
if (gui_bridge_is_uasync_ready()) { |
|
|
|
|
|
|
|
auto* q = (mf_cancel_request*)u_calloc(1, sizeof(mf_cancel_request)); |
|
|
|
|
|
|
|
if (q) { q->inst = gui_bridge_get_inst(); q->id = id; gui_bridge_post_uasync_fn(member_files_gui_cancel, q); } |
|
|
|
|
|
|
|
else DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "avatar: cancel allocation failed id=%llu", (unsigned long long)id); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
finish(id, MF_CANCELLED); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
QQueue<Job> keep; while (!m_queue.isEmpty()) { |
|
|
|
|
|
|
|
auto job = m_queue.dequeue(); if (job.gallery && needed(job)) job.gallery = false; |
|
|
|
|
|
|
|
if (!job.gallery) keep.enqueue(job); |
|
|
|
|
|
|
|
} |
|
|
|
m_queue = keep; |
|
|
|
m_queue = keep; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void AvatarManager::listGallery(quint64 cursor, const QByteArray& version) { |
|
|
|
void AvatarManager::listGallery(quint64 cursor, const QByteArray& version) { |
|
|
|
|
|
|
|
if (!gui_bridge_is_uasync_ready() || !m_galleryRef.server) return; |
|
|
|
auto* q = (mf_gui_request*)u_calloc(1, sizeof(mf_gui_request)); |
|
|
|
auto* q = (mf_gui_request*)u_calloc(1, sizeof(mf_gui_request)); |
|
|
|
if (!q) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "avatar: catalog allocation failed"); emit galleryError(text("Cannot load avatars")); return; } |
|
|
|
if (!q) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "avatar: catalog allocation failed"); emit galleryError(text("Cannot load avatars")); return; } |
|
|
|
do { m_listId = QRandomGenerator::global()->generate64(); } while (!m_listId || m_jobs.contains(m_listId)); |
|
|
|
do { m_listId = QRandomGenerator::global()->generate64(); } while (!m_listId || m_jobs.contains(m_listId)); |
|
|
|
|
|
|
|
m_listCursor = cursor; |
|
|
|
q->inst = gui_bridge_get_inst(); q->group = m_galleryRef.group; q->server = m_galleryRef.server; |
|
|
|
q->inst = gui_bridge_get_inst(); q->group = m_galleryRef.group; q->server = m_galleryRef.server; |
|
|
|
q->message.kind = MF_REQUEST; q->message.command = MF_LIST; q->message.request_id = m_listId; |
|
|
|
q->message.kind = MF_REQUEST; q->message.command = MF_LIST; q->message.request_id = m_listId; |
|
|
|
q->message.owner = m_galleryRef.owner; q->message.cursor = cursor; memcpy(q->message.path, "avatars", 8); |
|
|
|
q->message.owner = m_galleryRef.owner; q->message.cursor = cursor; memcpy(q->message.path, "avatars", 8); |
|
|
|
@ -312,7 +337,7 @@ void AvatarManager::enqueue(const Job& job) { |
|
|
|
for (const auto& old : m_queue) if ((old.upload == job.upload && old.ref.group == job.ref.group && old.ref.owner == job.ref.owner && |
|
|
|
for (const auto& old : m_queue) if ((old.upload == job.upload && old.ref.group == job.ref.group && old.ref.owner == job.ref.owner && |
|
|
|
(job.upload || (old.ref.hash == job.ref.hash && old.original == job.original))) || |
|
|
|
(job.upload || (old.ref.hash == job.ref.hash && old.original == job.original))) || |
|
|
|
(!job.upload && !old.upload && old.ref.hash == job.ref.hash && old.original == job.original)) return; |
|
|
|
(!job.upload && !old.upload && old.ref.hash == job.ref.hash && old.original == job.original)) return; |
|
|
|
if (job.upload) m_queue.prepend(job); else m_queue.enqueue(job); |
|
|
|
if (job.upload || job.original) m_queue.prepend(job); else m_queue.enqueue(job); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void AvatarManager::pump() { |
|
|
|
void AvatarManager::pump() { |
|
|
|
@ -378,9 +403,9 @@ void AvatarManager::onResponse(const uint8_t* data, int length) { |
|
|
|
response.owner != m_galleryRef.owner || response.command != MF_LIST || strcmp(response.path, "avatars")) return; |
|
|
|
response.owner != m_galleryRef.owner || response.command != MF_LIST || strcmp(response.path, "avatars")) return; |
|
|
|
m_listId = 0; |
|
|
|
m_listId = 0; |
|
|
|
if ((response.status == MF_STALE || response.status == MF_BUSY) && m_listRetries++ < 3) { |
|
|
|
if ((response.status == MF_STALE || response.status == MF_BUSY) && m_listRetries++ < 3) { |
|
|
|
m_catalog.clear(); const Ref source = m_galleryRef; |
|
|
|
m_catalog.clear(); const quint64 epoch = m_galleryEpoch; |
|
|
|
QTimer::singleShot(1000, this, [this, source] { |
|
|
|
QTimer::singleShot(1000, this, [this, epoch] { |
|
|
|
if (source.group == m_galleryRef.group && source.owner == m_galleryRef.owner && source.server == m_galleryRef.server) listGallery(); |
|
|
|
if (epoch == m_galleryEpoch) listGallery(); |
|
|
|
}); return; |
|
|
|
}); return; |
|
|
|
} |
|
|
|
} |
|
|
|
if (response.status) { |
|
|
|
if (response.status) { |
|
|
|
@ -400,7 +425,13 @@ void AvatarManager::onResponse(const uint8_t* data, int length) { |
|
|
|
m_catalog[QString::fromLatin1(file).left(64)] = mf_get64(p + 11); |
|
|
|
m_catalog[QString::fromLatin1(file).left(64)] = mf_get64(p + 11); |
|
|
|
at += MF_ENTRY_HEADER + n; |
|
|
|
at += MF_ENTRY_HEADER + n; |
|
|
|
} |
|
|
|
} |
|
|
|
if (response.more) { listGallery(response.cursor, QByteArray((const char*)response.version, 16)); return; } |
|
|
|
if (response.more) { |
|
|
|
|
|
|
|
if (response.cursor <= m_listCursor) { |
|
|
|
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "avatar: catalog cursor stalled=%llu", (unsigned long long)response.cursor); |
|
|
|
|
|
|
|
emit galleryError(text("Invalid directory response")); return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
listGallery(response.cursor, QByteArray((const char*)response.version, 16)); return; |
|
|
|
|
|
|
|
} |
|
|
|
m_gallery = m_catalog.keys(); |
|
|
|
m_gallery = m_catalog.keys(); |
|
|
|
std::sort(m_gallery.begin(), m_gallery.end(), [this](const QString& a, const QString& b) { |
|
|
|
std::sort(m_gallery.begin(), m_gallery.end(), [this](const QString& a, const QString& b) { |
|
|
|
return m_catalog[a] != m_catalog[b] ? m_catalog[a] > m_catalog[b] : a < b; |
|
|
|
return m_catalog[a] != m_catalog[b] ? m_catalog[a] > m_catalog[b] : a < b; |
|
|
|
@ -445,7 +476,7 @@ void AvatarManager::onTransfer(const uint8_t* data, int length) { |
|
|
|
if (snapshot.file.endsWith(".json")) { |
|
|
|
if (snapshot.file.endsWith(".json")) { |
|
|
|
m_records[snapshot.ref.hash] = result.record; |
|
|
|
m_records[snapshot.ref.hash] = result.record; |
|
|
|
auto& job = m_jobs[snapshot.id]; job.file = snapshot.original ? result.record.original : result.record.preview; |
|
|
|
auto& job = m_jobs[snapshot.id]; job.file = snapshot.original ? result.record.original : result.record.preview; |
|
|
|
transfer(job); return; |
|
|
|
transfer(job); notify(snapshot.ref.hash); return; |
|
|
|
} |
|
|
|
} |
|
|
|
const QString cacheKey = snapshot.ref.hash + (snapshot.original ? ":original" : ""); |
|
|
|
const QString cacheKey = snapshot.ref.hash + (snapshot.original ? ":original" : ""); |
|
|
|
m_images.insert(cacheKey, new QImage(result.image), qMax(1, int(result.image.sizeInBytes() / 1024))); |
|
|
|
m_images.insert(cacheKey, new QImage(result.image), qMax(1, int(result.image.sizeInBytes() / 1024))); |
|
|
|
|