You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
5.4 KiB
151 lines
5.4 KiB
#ifndef DB_MANAGER_H |
|
#define DB_MANAGER_H |
|
|
|
#include <sqlite3.h> |
|
#include <QString> |
|
#include <QList> |
|
#include <QMap> |
|
#include <QObject> |
|
#include <cstdint> |
|
|
|
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<ChannelRow> 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<MessageRow> 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<quint64> getOnlinePeers() const; |
|
QByteArray getNodeEdPub(quint64 nodeId) const; |
|
QList<NodeAddr> getOnlinePeerAddresses(quint64 excludeNodeId) const; |
|
|
|
/* ── Аккаунты ── */ |
|
QList<AccountRow> 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<uint32_t, sqlite3_stmt*> m_cursors; |
|
mutable uint32_t m_nextCursorId = 1; |
|
}; |
|
|
|
#endif
|
|
|