#ifndef DB_MANAGER_H #define DB_MANAGER_H #include #include #include #include #include #include struct ChannelRow { QString channelId; QString name; quint64 ownerNodeId = 0; QByteArray x25519_pubkey; QByteArray x25519_privkey; QByteArray ed25519_pubkey; QByteArray ed25519_privkey; QByteArray signature; // Ed25519 подпись всех полей записи privkey канала qint64 lastReadMsgId = 0; qint64 lastPosMsgId = 0; qint64 createdAt = 0; int unreadCount = 0; }; struct MessageRow { qint64 id = 0; quint64 authorNodeId = 0; QString contentType; QByteArray data; qint64 timestamp = 0; uint64_t datahash = 0; QByteArray chainHash; QByteArray signature; bool isOutgoing = false; bool isRead = false; }; struct AccountRow { quint64 nodeId = 0; QString displayName; QString avatarColor; QString avatarLetter; bool isContact = true; }; struct ChannelMember { quint64 nodeId = 0; bool online = false; QString name; // from nodes.name, empty if not set QString localNick; // from peers.local_nick override, empty if not set }; struct NodeAddr { quint64 nodeId = 0; int family = 0; int protocol = 0; // битмаска: 1=UDP, 2=TCP, 3=TCP+UDP QByteArray address; quint16 port = 0; int rtt = 0; int addrType = 0; // ADDR_TYPE_* int socketId = 0; // socket_id из ETCP }; struct IntegrityResult { bool ok = false; QString message; QStringList errors; int elapsedMs = 0; }; class DbManager : public QObject { Q_OBJECT public: explicit DbManager(QObject* parent = nullptr); ~DbManager() override; bool isOpen() const { return m_db != nullptr; } void setDb(sqlite3* db) { m_db = db; } quint64 myNodeId() const { return m_myNodeId; } void setMyNodeId(quint64 nodeId) { m_myNodeId = nodeId; } /* ── Каналы ── */ QList getChannels() const; int getUnreadCount(const QString& channelId, qint64 lastReadMsgId) const; /* ── UI state for channel read/scroll ── */ qint64 getUiStateInt64(const QString& key, qint64 defaultVal = 0) const; /* ── Сообщения (UI) ── */ QList getMessages(const QString& chId, int limit = 50) const; QList getMessagesSince(const QString& chId, qint64 sinceId) const; /* ── Участники канала (UI) ── */ int getChannelMemberCount(const QString& chId) const; QList getChannelMembers(const QString& chId, int offset, int limit) const; void cleanOrphanedPeers(const QString& chId) const; QString getDisplayName(quint64 nodeId) const; QMap getLocalNicknames(const QString& chId) const; /* ── Узлы ── */ QByteArray loadNodeInfo(quint64 nodeId) const; QList getOnlinePeers() const; QByteArray getNodeEdPub(quint64 nodeId) const; QList getOnlinePeerAddresses(quint64 excludeNodeId) const; /* ── Аккаунты ── */ QList getAccounts(bool contactsOnly = false) const; AccountRow getAccount(quint64 nodeId) const; /* ── UI state (read-only используем QSettings, оставлен для совместимости) ── */ QString getUiState(const QString& key) const; int getUiStateInt(const QString& key, int defaultVal) const; /* ── Sync-операции (read-only, для gui_bridge/inline) ── */ QByteArray syncListChannels() const; QByteArray syncCount(const QString& chId) const; QByteArray syncChainHashAt(const QString& chId, uint32_t pos) const; QByteArray syncCursorOpen(const QString& chId); QByteArray syncCursorNext(uint32_t cursorId); void syncCursorClose(uint32_t cursorId); QByteArray syncListPeers(const QString& chId) const; sqlite3_stmt* prepareOrNull(const char* sql) const; static QString colText(sqlite3_stmt* stmt, int col); static QByteArray colBlob(sqlite3_stmt* stmt, int col); QString msgTableName(const QString& chId) const; QString peersTableName(const QString& chId) const; static QString sanitizeTableName(const QString& chId); static uint64_t computeDatahash(const QByteArray& data); static QByteArray computeChainHash(const QByteArray& prevChain, qint64 timestamp, uint64_t datahash); QByteArray getLastChainHash(const QString& chId) const; IntegrityResult integrityCheckQuick() const; IntegrityResult integrityCheckFull() const; IntegrityResult integrityOptimize() const; sqlite3* m_db = nullptr; quint64 m_myNodeId = 0; /* Кэш открытых курсоров для sync-операций */ mutable QMap m_cursors; mutable uint32_t m_nextCursorId = 1; }; #endif