#ifndef DB_MANAGER_H #define DB_MANAGER_H #include #include #include #include #include #include struct ChannelRow { QString channelId; QString name; quint64 ownerNodeId = 0; bool isDm = false; 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; }; 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 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; bool isNat = false; }; class DbManager : public QObject { Q_OBJECT public: explicit DbManager(const QString& path, QObject* parent = nullptr); ~DbManager() override; bool isOpen() const { return m_db != nullptr; } quint64 myNodeId() const { return m_myNodeId; } /* ── Каналы ── */ QList getChannels() const; bool createChannel(const QString& chId, const QString& name, quint64 ownerNodeId = 0, const QByteArray& x25519pub = {}, const QByteArray& x25519priv = {}, const QByteArray& ed25519pub = {}, const QByteArray& ed25519priv = {}); bool deleteChannel(const QString& chId); /* ── Сообщения (UI) ── */ QList getMessages(const QString& chId, int limit = 50) const; bool insertMessage(const QString& chId, quint64 nodeId, const QString& contentType, const QByteArray& data, qint64 timestamp, bool isOutgoing, uint64_t* outDatahash, QByteArray* outChainHash); /* ── Участники канала ── */ bool addPeer(const QString& chId, quint64 nodeId, const QByteArray& joinSig, const QByteArray& creatorSig, const QString& comment = {}); bool removePeer(const QString& chId, quint64 nodeId); /* ── Узлы ── */ bool upsertNode(quint64 nodeId, const QString& name, const QByteArray& x25519pub, const QByteArray& ed25519pub); bool addNodeAddress(quint64 nodeId, int family, int protocol, const QByteArray& addr, quint16 port, bool isNat); 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 ── */ QString getUiState(const QString& key) const; void setUiState(const QString& key, const QString& value); /* ── Sync-операции (вызываются gui_bridge, в GUI-потоке) ── */ QByteArray syncListChannels() const; QByteArray syncCount(const QString& chId) const; QByteArray syncChainHashAt(const QString& chId, uint32_t pos) const; QByteArray syncInsert(const QString& chId, const QByteArray& recData); QByteArray syncCursorOpen(const QString& chId); QByteArray syncCursorNext(uint32_t cursorId); void syncCursorClose(uint32_t cursorId); QByteArray syncMarkSent(const QString& chId, quint64 ts, quint64 dh, quint64 myNodeId); QByteArray syncTtlDelete(const QString& chId, quint64 myNodeId, quint64 cutoffUs); QByteArray syncListPeers(const QString& chId) const; /* ── Уведомления из uasync ── */ void onSyncMessageReceived(const QString& chId); void setNodeOnline(quint64 nodeId, bool online); void setUasyncInstance(void* ua) { m_ua = ua; } void* uasyncInstance() const { return m_ua; } /* ── seed ── */ void seedStubData(); private: void initTables(); 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; sqlite3* m_db = nullptr; quint64 m_myNodeId = 0; void* m_ua = nullptr; /* Кэш открытых курсоров для sync-операций */ mutable QMap m_cursors; mutable uint32_t m_nextCursorId = 1; }; #endif