Distinguish failed avatar reads from committed empty blobs
This commit is contained in:
1 parent
95e88ac66f
commit
905d30ceaf
2 files changed
+35
-8
No files matched your search
@@ -10,6 +10,7 @@
|
||||
#include <QJsonObject>
|
||||
#include <QCoreApplication>
|
||||
#include "chat/chat_poll.h"
|
||||
#include "chat/group_avatar.h"
|
||||
|
||||
/* ── helpers ── */
|
||||
|
||||
@@ -119,14 +120,37 @@ QList<ChannelRow> DbManager::getChannels(ChannelSortMode sort) const {
|
||||
return list;
|
||||
}
|
||||
|
||||
QByteArray DbManager::getChannelAvatar(const QString& channelId) const {
|
||||
sqlite3_stmt* st = prepareOrNull("SELECT avatar_data FROM channels WHERE channel_id=?"); if (!st) return {};
|
||||
const QByteArray id = channelId.toLatin1(); sqlite3_bind_text(st, 1, id.constData(), id.size(), SQLITE_TRANSIENT);
|
||||
QByteArray DbManager::getChannelAvatar(const QString& channelId, bool* ok) const {
|
||||
if (ok) *ok = false;
|
||||
if (!m_db) { GUI_WARN("group avatar: database unavailable channel=%s", qPrintable(channelId)); return {}; }
|
||||
sqlite3_stmt* st = nullptr;
|
||||
const char* stage = "prepare";
|
||||
int rc = sqlite3_prepare_v2(m_db, "SELECT avatar_data FROM channels WHERE channel_id=?", -1, &st, nullptr);
|
||||
const QByteArray id = channelId.toLatin1();
|
||||
if (rc == SQLITE_OK) { stage = "bind"; rc = sqlite3_bind_text(st, 1, id.constData(), id.size(), SQLITE_TRANSIENT); }
|
||||
if (rc == SQLITE_OK) { stage = "step"; rc = sqlite3_step(st); }
|
||||
QByteArray bytes;
|
||||
int rc = sqlite3_step(st);
|
||||
if (rc == SQLITE_ROW) bytes = colBlob(st, 0);
|
||||
else if (rc != SQLITE_DONE) GUI_ERROR("group avatar: database read failed channel=%s rc=%d", qPrintable(channelId), rc);
|
||||
sqlite3_finalize(st); return bytes;
|
||||
int type = -1, length = 0;
|
||||
if (rc == SQLITE_ROW) {
|
||||
stage = "blob"; type = sqlite3_column_type(st, 0); length = sqlite3_column_bytes(st, 0);
|
||||
if (type != SQLITE_BLOB) rc = SQLITE_CORRUPT;
|
||||
else if (length > GROUP_AVATAR_MAX) rc = SQLITE_TOOBIG;
|
||||
else {
|
||||
const char* blob = static_cast<const char*>(sqlite3_column_blob(st, 0));
|
||||
if (length && !blob) rc = SQLITE_NOMEM;
|
||||
else bytes = QByteArray(blob, length);
|
||||
}
|
||||
}
|
||||
const int final = sqlite3_finalize(st);
|
||||
if ((rc != SQLITE_ROW && rc != SQLITE_DONE) || final != SQLITE_OK) {
|
||||
GUI_ERROR("group avatar: read channel=%s stage=%s rc=%d finalize=%d type=%d bytes=%d: %s",
|
||||
qPrintable(channelId), stage, rc, final, type, length, sqlite3_errmsg(m_db)); return {};
|
||||
}
|
||||
if (rc == SQLITE_DONE) {
|
||||
GUI_DEBUG("group avatar: channel disappeared during read channel=%s", qPrintable(channelId)); return {};
|
||||
}
|
||||
if (ok) *ok = true;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
bool DbManager::isChannelMember(const QString& chId, quint64 nodeId) const {
|
||||
|
||||
@@ -101,7 +101,10 @@ public:
|
||||
|
||||
/* ── Каналы ── */
|
||||
QList<ChannelRow> getChannels(ChannelSortMode sort = ChannelSortMode::Alphabetical) const;
|
||||
QByteArray getChannelAvatar(const QString& channelId) const;
|
||||
/* Читает BLOB аватара канала <=16 KiB. Возвращает самостоятельные байты; при ошибке/нет строки — пустой массив.
|
||||
* Необязательный ok отличает успешный пустой BLOB (удаление) от отказа; bind/step/finalize проверяются.
|
||||
* Хеш/версию и формат JPEG проверяет GroupAvatarManager, запись не меняется. */
|
||||
QByteArray getChannelAvatar(const QString& channelId, bool* ok = nullptr) const;
|
||||
QString getChannelLastMessage(const QString& channelId) const;
|
||||
int getUnreadCount(const QString& channelId, qint64 lastReadMsgId) const;
|
||||
|
||||
|
||||
Reference in new issue
Block a user