mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Merge branch 'v1.17-dev'
This commit is contained in:
commit
6179250458
|
@ -68,18 +68,6 @@
|
|||
* deadlock.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Maps friend IDs to ToxFriendCall.
|
||||
* @note Need to use STL container here, because Qt containers need a copy constructor.
|
||||
*/
|
||||
std::map<uint32_t, CoreAV::ToxFriendCallPtr> CoreAV::calls;
|
||||
|
||||
/**
|
||||
* @brief Maps group IDs to ToxGroupCalls.
|
||||
* @note Need to use STL container here, because Qt containers need a copy constructor.
|
||||
*/
|
||||
std::map<int, CoreAV::ToxGroupCallPtr> CoreAV::groupCalls;
|
||||
|
||||
CoreAV::CoreAV(std::unique_ptr<ToxAV, ToxAVDeleter> toxav)
|
||||
: audio{nullptr}
|
||||
, toxav{std::move(toxav)}
|
||||
|
@ -788,12 +776,12 @@ void CoreAV::stateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t state, voi
|
|||
|
||||
if (state & TOXAV_FRIEND_CALL_STATE_ERROR) {
|
||||
qWarning() << "Call with friend" << friendNum << "died of unnatural causes!";
|
||||
calls.erase(friendNum);
|
||||
self->calls.erase(friendNum);
|
||||
// why not self->
|
||||
emit self->avEnd(friendNum, true);
|
||||
} else if (state & TOXAV_FRIEND_CALL_STATE_FINISHED) {
|
||||
qDebug() << "Call with friend" << friendNum << "finished quietly";
|
||||
calls.erase(friendNum);
|
||||
self->calls.erase(friendNum);
|
||||
// why not self->
|
||||
emit self->avEnd(friendNum);
|
||||
} else {
|
||||
|
@ -874,7 +862,7 @@ void CoreAV::audioFrameCallback(ToxAV*, uint32_t friendNum, const int16_t* pcm,
|
|||
uint8_t channels, uint32_t samplingRate, void* vSelf)
|
||||
{
|
||||
CoreAV* self = static_cast<CoreAV*>(vSelf);
|
||||
auto it = calls.find(friendNum);
|
||||
auto it = self->calls.find(friendNum);
|
||||
if (it == self->calls.end()) {
|
||||
return;
|
||||
}
|
||||
|
@ -890,10 +878,12 @@ void CoreAV::audioFrameCallback(ToxAV*, uint32_t friendNum, const int16_t* pcm,
|
|||
|
||||
void CoreAV::videoFrameCallback(ToxAV*, uint32_t friendNum, uint16_t w, uint16_t h,
|
||||
const uint8_t* y, const uint8_t* u, const uint8_t* v,
|
||||
int32_t ystride, int32_t ustride, int32_t vstride, void*)
|
||||
int32_t ystride, int32_t ustride, int32_t vstride, void* vSelf)
|
||||
{
|
||||
auto it = calls.find(friendNum);
|
||||
if (it == calls.end()) {
|
||||
auto self = static_cast<CoreAV*>(vSelf);
|
||||
|
||||
auto it = self->calls.find(friendNum);
|
||||
if (it == self->calls.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -132,9 +132,19 @@ private:
|
|||
std::unique_ptr<QThread> coreavThread;
|
||||
QTimer* iterateTimer = nullptr;
|
||||
using ToxFriendCallPtr = std::unique_ptr<ToxFriendCall>;
|
||||
static std::map<uint32_t, ToxFriendCallPtr> calls;
|
||||
/**
|
||||
* @brief Maps friend IDs to ToxFriendCall.
|
||||
* @note Need to use STL container here, because Qt containers need a copy constructor.
|
||||
*/
|
||||
std::map<uint32_t, ToxFriendCallPtr> calls;
|
||||
|
||||
|
||||
using ToxGroupCallPtr = std::unique_ptr<ToxGroupCall>;
|
||||
static std::map<int, ToxGroupCallPtr> groupCalls;
|
||||
/**
|
||||
* @brief Maps group IDs to ToxGroupCalls.
|
||||
* @note Need to use STL container here, because Qt containers need a copy constructor.
|
||||
*/
|
||||
std::map<int, ToxGroupCallPtr> groupCalls;
|
||||
std::atomic_flag threadSwitchLock;
|
||||
};
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "db/rawdatabase.h"
|
||||
|
||||
namespace {
|
||||
static constexpr int SCHEMA_VERSION = 2;
|
||||
static constexpr int SCHEMA_VERSION = 3;
|
||||
|
||||
bool createCurrentSchema(RawDatabase& db)
|
||||
{
|
||||
|
@ -150,6 +150,34 @@ bool dbSchema1to2(RawDatabase& db)
|
|||
return db.execNow(upgradeQueries);
|
||||
}
|
||||
|
||||
bool dbSchema2to3(RawDatabase& db)
|
||||
{
|
||||
// Any faux_offline_pending message with the content "/me " are action
|
||||
// messages that qTox previously let a user enter, but that will cause an
|
||||
// action type message to be sent to toxcore, with 0 length, which will
|
||||
// always fail. They must be be moved from faux_offline_pending to broken_messages
|
||||
// to avoid qTox from erroring trying to send them on every connect
|
||||
|
||||
const QString emptyActionMessageString = "/me ";
|
||||
|
||||
QVector<RawDatabase::Query> upgradeQueries;
|
||||
upgradeQueries += RawDatabase::Query{QString("INSERT INTO broken_messages "
|
||||
"SELECT faux_offline_pending.id FROM "
|
||||
"history JOIN faux_offline_pending "
|
||||
"ON faux_offline_pending.id = history.id "
|
||||
"WHERE history.message = ?;"),
|
||||
{emptyActionMessageString.toUtf8()}};
|
||||
|
||||
upgradeQueries += QString(
|
||||
"DELETE FROM faux_offline_pending "
|
||||
"WHERE id in ("
|
||||
"SELECT id FROM broken_messages);");
|
||||
|
||||
upgradeQueries += RawDatabase::Query(QStringLiteral("PRAGMA user_version = 3;"));
|
||||
|
||||
return db.execNow(upgradeQueries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Upgrade the db schema
|
||||
* @note On future alterations of the database all you have to do is bump the SCHEMA_VERSION
|
||||
|
@ -168,7 +196,8 @@ void dbSchemaUpgrade(std::shared_ptr<RawDatabase>& db)
|
|||
}
|
||||
|
||||
if (databaseSchemaVersion > SCHEMA_VERSION) {
|
||||
qWarning() << "Database version is newer than we currently support. Please upgrade qTox";
|
||||
qWarning().nospace() << "Database version (" << databaseSchemaVersion <<
|
||||
") is newer than we currently support (" << SCHEMA_VERSION << "). Please upgrade qTox";
|
||||
// We don't know what future versions have done, we have to disable db access until we re-upgrade
|
||||
db.reset();
|
||||
return;
|
||||
|
@ -216,6 +245,13 @@ void dbSchemaUpgrade(std::shared_ptr<RawDatabase>& db)
|
|||
}
|
||||
qDebug() << "Database upgraded incrementally to schema version 2";
|
||||
//fallthrough
|
||||
case 2:
|
||||
if (!dbSchema2to3(*db)) {
|
||||
qCritical() << "Failed to upgrade db to schema version 3, aborting";
|
||||
db.reset();
|
||||
return;
|
||||
}
|
||||
qDebug() << "Database upgraded incrementally to schema version 3";
|
||||
// etc.
|
||||
default:
|
||||
qInfo() << "Database upgrade finished (databaseSchemaVersion" << databaseSchemaVersion
|
||||
|
|
|
@ -524,6 +524,11 @@ void GenericChatForm::onSendTriggered()
|
|||
{
|
||||
auto msg = msgEdit->toPlainText();
|
||||
|
||||
bool isAction = msg.startsWith(ChatForm::ACTION_PREFIX, Qt::CaseInsensitive);
|
||||
if (isAction) {
|
||||
msg.remove(0, ChatForm::ACTION_PREFIX.length());
|
||||
}
|
||||
|
||||
if (msg.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -531,11 +536,6 @@ void GenericChatForm::onSendTriggered()
|
|||
msgEdit->setLastMessage(msg);
|
||||
msgEdit->clear();
|
||||
|
||||
bool isAction = msg.startsWith(ChatForm::ACTION_PREFIX, Qt::CaseInsensitive);
|
||||
if (isAction) {
|
||||
msg.remove(0, ChatForm::ACTION_PREFIX.length());
|
||||
}
|
||||
|
||||
messageDispatcher.sendMessage(isAction, msg);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ private slots:
|
|||
void testIsNewDb();
|
||||
void test0to1();
|
||||
void test1to2();
|
||||
void test2to3();
|
||||
void cleanupTestCase();
|
||||
private:
|
||||
bool initSucess{false};
|
||||
|
@ -48,7 +49,8 @@ const QString testFileList[] = {
|
|||
"testIsNewDbTrue.db",
|
||||
"testIsNewDbFalse.db",
|
||||
"test0to1.db",
|
||||
"test1to2.db"
|
||||
"test1to2.db",
|
||||
"test2to3.db"
|
||||
};
|
||||
|
||||
const QMap<QString, QString> schema0 {
|
||||
|
@ -77,6 +79,9 @@ const QMap<QString, QString> schema2 {
|
|||
{"broken_messages", "CREATE TABLE broken_messages (id INTEGER PRIMARY KEY)"}
|
||||
};
|
||||
|
||||
// move stuck 0-length action messages to the existing "broken_messages" table. Not a real schema upgrade.
|
||||
const auto schema3 = schema2;
|
||||
|
||||
void TestDbSchema::initTestCase()
|
||||
{
|
||||
for (const auto& path : testFileList) {
|
||||
|
@ -127,7 +132,7 @@ void TestDbSchema::testCreation()
|
|||
QVector<RawDatabase::Query> queries;
|
||||
auto db = std::shared_ptr<RawDatabase>{new RawDatabase{"testCreation.db", {}, {}}};
|
||||
QVERIFY(createCurrentSchema(*db));
|
||||
verifyDb(db, schema2);
|
||||
verifyDb(db, schema3);
|
||||
}
|
||||
|
||||
void TestDbSchema::testIsNewDb()
|
||||
|
@ -247,5 +252,67 @@ void TestDbSchema::test1to2()
|
|||
QVERIFY(totalHisoryCount == 6); // all messages should still be in history.
|
||||
}
|
||||
|
||||
void TestDbSchema::test2to3()
|
||||
{
|
||||
auto db = std::shared_ptr<RawDatabase>{new RawDatabase{"test2to3.db", {}, {}}};
|
||||
createSchemaAtVersion(db, schema2);
|
||||
|
||||
// since we don't enforce foreign key contraints in the db, we can stick in IDs to other tables
|
||||
// to avoid generating proper entries for peers and aliases tables, since they aren't actually
|
||||
// relevant for the test.
|
||||
|
||||
QVector<RawDatabase::Query> queries;
|
||||
// pending message, should be moved out
|
||||
queries += RawDatabase::Query{
|
||||
"INSERT INTO history (id, timestamp, chat_id, message, sender_alias) VALUES (1, 1, 0, ?, 0)",
|
||||
{"/me "}};
|
||||
queries += {"INSERT INTO faux_offline_pending (id) VALUES ("
|
||||
" last_insert_rowid()"
|
||||
");"};
|
||||
|
||||
// non pending message with the content "/me ". Maybe it was sent by a friend using a different client.
|
||||
queries += RawDatabase::Query{
|
||||
"INSERT INTO history (id, timestamp, chat_id, message, sender_alias) VALUES (2, 2, 0, ?, 2)",
|
||||
{"/me "}};
|
||||
|
||||
// non pending message sent by us
|
||||
queries += RawDatabase::Query{
|
||||
"INSERT INTO history (id, timestamp, chat_id, message, sender_alias) VALUES (3, 3, 0, ?, 1)",
|
||||
{"a normal message"}};
|
||||
|
||||
// pending normal message sent by us
|
||||
queries += RawDatabase::Query{
|
||||
"INSERT INTO history (id, timestamp, chat_id, message, sender_alias) VALUES (4, 3, 0, ?, 1)",
|
||||
{"a normal faux offline message"}};
|
||||
queries += {"INSERT INTO faux_offline_pending (id) VALUES ("
|
||||
" last_insert_rowid()"
|
||||
");"};
|
||||
QVERIFY(db->execNow(queries));
|
||||
QVERIFY(dbSchema2to3(*db));
|
||||
|
||||
long brokenCount = -1;
|
||||
RawDatabase::Query brokenCountQuery = {"SELECT COUNT(*) FROM broken_messages;", [&](const QVector<QVariant>& row) {
|
||||
brokenCount = row[0].toLongLong();
|
||||
}};
|
||||
QVERIFY(db->execNow(brokenCountQuery));
|
||||
QVERIFY(brokenCount == 1);
|
||||
|
||||
int fauxOfflineCount = -1;
|
||||
RawDatabase::Query fauxOfflineCountQuery = {"SELECT COUNT(*) FROM faux_offline_pending;", [&](const QVector<QVariant>& row) {
|
||||
fauxOfflineCount = row[0].toLongLong();
|
||||
}};
|
||||
QVERIFY(db->execNow(fauxOfflineCountQuery));
|
||||
QVERIFY(fauxOfflineCount == 1);
|
||||
|
||||
int totalHisoryCount = -1;
|
||||
RawDatabase::Query totalHistoryCountQuery = {"SELECT COUNT(*) FROM history;", [&](const QVector<QVariant>& row) {
|
||||
totalHisoryCount = row[0].toLongLong();
|
||||
}};
|
||||
QVERIFY(db->execNow(totalHistoryCountQuery));
|
||||
QVERIFY(totalHisoryCount == 4);
|
||||
|
||||
verifyDb(db, schema3);
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(TestDbSchema)
|
||||
#include "dbschema_test.moc"
|
||||
|
|
Loading…
Reference in New Issue
Block a user