Return attachment metadata as checked SQLite snapshots
This commit is contained in:
1 parent
034df2939c
commit
0d6fd63e8f
3 files changed
+40
-14
No files matched your search
@@ -328,6 +328,27 @@ MessageRow DbManager::getMessageById(const QString& chId, qint64 msgId) const {
|
||||
return finishRead(stmt, rc) ? m : MessageRow();
|
||||
}
|
||||
|
||||
/* Метаданные и состояние ключа читаются одним SELECT, курсор закрыт до передачи данных UI. */
|
||||
AttachmentRow DbManager::getAttachment(const QString& channel, const QByteArray& messageId) const {
|
||||
AttachmentRow row;
|
||||
if (messageId.size() != 32) { GUI_ERROR("attachment lookup: invalid key bytes=%d", int(messageId.size())); return row; }
|
||||
sqlite3_stmt* st = prepareOrNull("SELECT a.ready,a.downloaded,a.decrypting,a.error,a.plain_path,a.info,a.content_type,"
|
||||
"COALESCE(r.state,-1),length(a.key)=32 FROM attachment_keys a LEFT JOIN attachment_key_requests r"
|
||||
" ON r.channel=a.channel AND r.message_id=a.message_id AND r.incoming=0 WHERE a.channel=? AND a.message_id=?");
|
||||
if (!st) return row;
|
||||
const QByteArray bytes = channel.toUtf8();
|
||||
int rc = sqlite3_bind_text(st, 1, bytes.constData(), bytes.size(), SQLITE_TRANSIENT);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_blob(st, 2, messageId.constData(), messageId.size(), SQLITE_TRANSIENT);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_step(st);
|
||||
if (rc == SQLITE_ROW) {
|
||||
row.found = true; row.ready = sqlite3_column_int(st, 0); row.downloaded = sqlite3_column_int(st, 1);
|
||||
row.decrypting = sqlite3_column_int(st, 2); row.error = sqlite3_column_int(st, 3);
|
||||
row.path = colText(st, 4); row.info = colBlob(st, 5); row.contentType = colText(st, 6);
|
||||
row.requestState = sqlite3_column_int(st, 7); row.hasKey = sqlite3_column_int(st, 8);
|
||||
}
|
||||
return finishRead(st, rc) ? row : AttachmentRow();
|
||||
}
|
||||
|
||||
/* ── DM-беседы (UI, read-only) ── */
|
||||
|
||||
/* Поиск ограничен таблицей выбранного канала; отсутствие оригинала допустимо при неполной синхронизации. */
|
||||
|
||||
@@ -50,6 +50,16 @@ struct MessageRow {
|
||||
bool isRead = false;
|
||||
};
|
||||
|
||||
/* Самостоятельный снимок расшифровки вложения, без SQLite-указателей. */
|
||||
struct AttachmentRow {
|
||||
bool found = false; // Строка получена целиком без SQL-ошибок.
|
||||
bool ready = false, downloaded = false, decrypting = false, error = false; // Состояния подготовки plaintext.
|
||||
bool hasKey = false; // В БД имеется 32-байтный ключ.
|
||||
int requestState = -1; // Состояние исходящего запроса ключа; -1 — запроса нет.
|
||||
QString path, contentType; // Plaintext-файл и его MIME; существование файла проверяет UI.
|
||||
QByteArray info; // Кодированный attachment_info, валидируется attachment_decode.
|
||||
};
|
||||
|
||||
struct AccountRow {
|
||||
quint64 nodeId = 0;
|
||||
QString displayName;
|
||||
@@ -107,6 +117,7 @@ public:
|
||||
QList<MessageRow> getMessagesSince(const QString& chId, qint64 sinceId) const;
|
||||
MessageRow getMessageById(const QString& chId, qint64 msgId) const;
|
||||
MessageRow getMessageByKey(const QString& chId, const QByteArray& key) const;
|
||||
AttachmentRow getAttachment(const QString& channel, const QByteArray& messageId) const; // Ключ ровно 32 байта; ошибка → found=false.
|
||||
static QString messagePreview(const MessageRow& message);
|
||||
|
||||
/* ── DM-беседы (UI, read-only) ── */
|
||||
|
||||
@@ -167,22 +167,17 @@ static void setVoiceMessageRoles(QStandardItem* item, const QByteArray& data,
|
||||
item->setData(0, MsgFileDownloadStateRole);
|
||||
const auto parts = QString::fromUtf8(body).split('|');
|
||||
if (parts.size() > 3) { item->setData(parts[1].toLongLong(), MsgFileSizeRole); item->setData(parts[3].toInt(), MsgMediaNumBlocksRole); }
|
||||
sqlite3_stmt* st = db ? db->prepareOrNull("SELECT a.ready,a.downloaded,a.decrypting,a.error,a.plain_path,a.info,a.content_type,"
|
||||
"COALESCE(r.state,-1),length(a.key)=32 FROM attachment_keys a LEFT JOIN attachment_key_requests r"
|
||||
" ON r.channel=a.channel AND r.message_id=a.message_id AND r.incoming=0 WHERE a.channel=? AND a.message_id=?") : nullptr;
|
||||
if (!st) return;
|
||||
const QByteArray channel = channelId.toUtf8();
|
||||
sqlite3_bind_text(st, 1, channel.constData(), -1, SQLITE_STATIC); sqlite3_bind_blob(st, 2, messageId.constData(), messageId.size(), SQLITE_STATIC);
|
||||
if (sqlite3_step(st) == SQLITE_ROW) {
|
||||
const bool ready = sqlite3_column_int(st, 0), downloaded = sqlite3_column_int(st, 1), decrypting = sqlite3_column_int(st, 2);
|
||||
const bool error = sqlite3_column_int(st, 3), key = sqlite3_column_int(st, 8);
|
||||
const int state = sqlite3_column_int(st, 7);
|
||||
const QString path = DbManager::colText(st, 4);
|
||||
const AttachmentRow snapshot = db ? db->getAttachment(channelId, messageId) : AttachmentRow();
|
||||
if (snapshot.found) {
|
||||
const bool ready = snapshot.ready, downloaded = snapshot.downloaded, decrypting = snapshot.decrypting;
|
||||
const bool error = snapshot.error, key = snapshot.hasKey;
|
||||
const int state = snapshot.requestState;
|
||||
const QString path = snapshot.path;
|
||||
struct attachment_info info = {};
|
||||
const bool available = ready && QFile::exists(path) &&
|
||||
!attachment_decode((const uint8_t*)sqlite3_column_blob(st, 5), sqlite3_column_bytes(st, 5), &info);
|
||||
!attachment_decode((const uint8_t*)snapshot.info.constData(), snapshot.info.size(), &info);
|
||||
if (available) {
|
||||
item->setData(DbManager::colText(st, 6), MsgContentTypeRole);
|
||||
item->setData(snapshot.contentType, MsgContentTypeRole);
|
||||
item->setData(QString::fromUtf8(info.name), MsgFileDisplayNameRole);
|
||||
item->setData(QFileInfo(path).size(), MsgFileSizeRole); item->setData(QFileInfo(path).size(), MsgVoiceFileSizeRole);
|
||||
item->setData(path, MsgVoiceFileRole); item->setData(2, MsgFileDownloadStateRole);
|
||||
@@ -205,7 +200,6 @@ static void setVoiceMessageRoles(QStandardItem* item, const QByteArray& data,
|
||||
item->setData(downloaded && !error ? 1 : 0, MsgFileDownloadStateRole);
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(st);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user