1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

refactor(core): cleanup Core class

- use a factory method to create it
- make it handle its own thread
- remove dependency on GUI
This commit is contained in:
sudden6 2018-06-26 15:55:21 +02:00
parent 4921b8868f
commit 8574162949
No known key found for this signature in database
GPG Key ID: 279509B499E032B9
8 changed files with 259 additions and 281 deletions

View File

@ -28,7 +28,6 @@
#include "src/model/groupinvite.h" #include "src/model/groupinvite.h"
#include "src/nexus.h" #include "src/nexus.h"
#include "src/persistence/profile.h" #include "src/persistence/profile.h"
#include "src/widget/gui.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QRegularExpression> #include <QRegularExpression>
@ -40,209 +39,38 @@
#include <ctime> #include <ctime>
const QString Core::TOX_EXT = ".tox"; const QString Core::TOX_EXT = ".tox";
QThread* Core::coreThread{nullptr};
#define MAX_GROUP_MESSAGE_LEN 1024 #define MAX_GROUP_MESSAGE_LEN 1024
Core::Core(QThread* CoreThread, Profile& profile, const ICoreSettings* const settings) Core::Core(QThread* coreThread)
: tox(nullptr) : tox(nullptr)
, av(nullptr) , av(nullptr)
, profile(profile) , coreThread{coreThread}
, ready(false)
, s{settings}
{ {
coreThread = CoreThread; toxTimer.setSingleShot(true);
toxTimer = new QTimer(this); connect(&this->toxTimer, &QTimer::timeout, this, &Core::process);
toxTimer->setSingleShot(true);
connect(toxTimer, &QTimer::timeout, this, &Core::process);
s->connectTo_dhtServerListChanged([=](const QList<DhtServer>& servers){
process();
});
}
void Core::deadifyTox()
{
if (av) {
delete av;
av = nullptr;
}
if (tox) {
tox_kill(tox);
tox = nullptr;
}
} }
Core::~Core() Core::~Core()
{ {
if (coreThread->isRunning()) { if (QThread::currentThread() == coreThread) {
if (QThread::currentThread() == coreThread) { killTimers();
killTimers(false); } else {
} else { // ensure the timer is stopped, even if not called from this thread
QMetaObject::invokeMethod(this, "killTimers", Qt::BlockingQueuedConnection, QMetaObject::invokeMethod(this, "killTimers", Qt::BlockingQueuedConnection);
Q_ARG(bool, false));
}
} }
coreThread->exit(0); coreThread->exit(0);
if (QThread::currentThread() != coreThread) {
while (coreThread->isRunning()) {
qApp->processEvents();
coreThread->wait(500);
}
}
deadifyTox(); delete av;
tox_kill(tox);
} }
/** /**
* @brief Returns the global widget's Core instance * @brief Registers all toxcore callbacks
* @param tox Tox instance to register the callbacks on
*/ */
Core* Core::getInstance() void Core::registerCallbacks(Tox * tox) {
{
return Nexus::getCore();
}
const CoreAV* Core::getAv() const
{
return av;
}
CoreAV* Core::getAv()
{
return av;
}
/**
* @brief Creates Tox instance from previously saved data
* @param savedata Previously saved Tox data - null, if new profile was created
*/
void Core::makeTox(QByteArray savedata)
{
auto toxOptions = ToxOptions::makeToxOptions(savedata, s);
if (toxOptions == nullptr) {
qCritical() << "could not allocate Tox Options data structure";
emit failedToStart();
return;
}
TOX_ERR_NEW tox_err;
tox = tox_new(*toxOptions, &tox_err);
switch (tox_err) {
case TOX_ERR_NEW_OK:
break;
case TOX_ERR_NEW_LOAD_BAD_FORMAT:
qCritical() << "failed to parse Tox save data";
emit failedToStart();
return;
case TOX_ERR_NEW_PORT_ALLOC:
if (s->getEnableIPv6()) {
tox_options_set_ipv6_enabled(*toxOptions, false);
tox = tox_new(*toxOptions, &tox_err);
if (tox_err == TOX_ERR_NEW_OK) {
qWarning() << "Core failed to start with IPv6, falling back to IPv4. LAN discovery "
"may not work properly.";
break;
}
}
qCritical() << "can't to bind the port";
emit failedToStart();
return;
case TOX_ERR_NEW_PROXY_BAD_HOST:
case TOX_ERR_NEW_PROXY_BAD_PORT:
case TOX_ERR_NEW_PROXY_BAD_TYPE:
qCritical() << "bad proxy, error code:" << tox_err;
emit badProxy();
return;
case TOX_ERR_NEW_PROXY_NOT_FOUND:
qCritical() << "proxy not found";
emit badProxy();
return;
case TOX_ERR_NEW_LOAD_ENCRYPTED:
qCritical() << "attempted to load encrypted Tox save data";
emit failedToStart();
return;
case TOX_ERR_NEW_MALLOC:
qCritical() << "memory allocation failed";
emit failedToStart();
return;
case TOX_ERR_NEW_NULL:
qCritical() << "a parameter was null";
emit failedToStart();
return;
default:
qCritical() << "Tox core failed to start, unknown error code:" << tox_err;
emit failedToStart();
return;
}
}
/**
* @brief Initializes the core, must be called before anything else
*/
void Core::start(const QByteArray& savedata)
{
bool isNewProfile = profile.isNewProfile();
if (isNewProfile) {
qDebug() << "Creating a new profile";
makeTox(QByteArray());
setStatusMessage(tr("Toxing on qTox"));
setUsername(profile.getName());
} else {
qDebug() << "Loading user profile";
if (savedata.isEmpty()) {
emit failedToStart();
return;
}
makeTox(savedata);
}
qsrand(time(nullptr));
if (!tox) {
ready = true;
GUI::setEnabled(true);
return;
}
// toxcore is successfully created, create toxav
av = new CoreAV(tox);
if (!av->getToxAv()) {
qCritical() << "Toxav failed to start";
emit failedToStart();
deadifyTox();
return;
}
// set GUI with user and statusmsg
QString name = getUsername();
if (!name.isEmpty()) {
emit usernameSet(name);
}
QString msg = getStatusMessage();
if (!msg.isEmpty()) {
emit statusMessageSet(msg);
}
ToxId id = getSelfId();
// TODO: probably useless check, comes basically directly from toxcore
if (id.isValid()) {
emit idSet(id);
}
loadFriends();
tox_callback_friend_request(tox, onFriendRequest); tox_callback_friend_request(tox, onFriendRequest);
tox_callback_friend_message(tox, onFriendMessage); tox_callback_friend_message(tox, onFriendMessage);
tox_callback_friend_name(tox, onFriendNameChange); tox_callback_friend_name(tox, onFriendNameChange);
@ -264,22 +92,176 @@ void Core::start(const QByteArray& savedata)
tox_callback_file_recv(tox, CoreFile::onFileReceiveCallback); tox_callback_file_recv(tox, CoreFile::onFileReceiveCallback);
tox_callback_file_recv_chunk(tox, CoreFile::onFileRecvChunkCallback); tox_callback_file_recv_chunk(tox, CoreFile::onFileRecvChunkCallback);
tox_callback_file_recv_control(tox, CoreFile::onFileControlCallback); tox_callback_file_recv_control(tox, CoreFile::onFileControlCallback);
}
ready = true; /**
* @brief Factory method for the Core object
* @param savedata empty if new profile or saved data else
* @param settings Settings specific to Core
* @return nullptr or a Core object ready to start
*/
ToxCorePtr Core::makeToxCore(const QByteArray &savedata, const ICoreSettings * const settings)
{
QThread* thread = new QThread();
if (thread == nullptr) {
qCritical() << "could not allocate Core thread";
return {};
}
thread->setObjectName("qTox Core");
if (isNewProfile) { auto toxOptions = ToxOptions::makeToxOptions(savedata, settings);
profile.saveToxSave(); if (toxOptions == nullptr) {
qCritical() << "could not allocate Tox Options data structure";
return {};
} }
if (isReady()) { ToxCorePtr core(new Core(thread));
GUI::setEnabled(true); if(core == nullptr) {
return {};
} }
TOX_ERR_NEW tox_err;
core->tox = tox_new(*toxOptions, &tox_err);
switch (tox_err) {
case TOX_ERR_NEW_OK:
break;
case TOX_ERR_NEW_LOAD_BAD_FORMAT:
qCritical() << "failed to parse Tox save data";
return {};
case TOX_ERR_NEW_PORT_ALLOC:
if (toxOptions->getIPv6Enabled()) {
toxOptions->setIPv6Enabled(false);
core->tox = tox_new(*toxOptions, &tox_err);
if (tox_err == TOX_ERR_NEW_OK) {
qWarning() << "Core failed to start with IPv6, falling back to IPv4. LAN discovery "
"may not work properly.";
break;
}
}
qCritical() << "can't to bind the port";
return {};
case TOX_ERR_NEW_PROXY_BAD_HOST:
case TOX_ERR_NEW_PROXY_BAD_PORT:
case TOX_ERR_NEW_PROXY_BAD_TYPE:
qCritical() << "bad proxy, error code:" << tox_err;
//emit badProxy();
return {};
case TOX_ERR_NEW_PROXY_NOT_FOUND:
qCritical() << "proxy not found";
//emit badProxy();
return {};
case TOX_ERR_NEW_LOAD_ENCRYPTED:
qCritical() << "attempted to load encrypted Tox save data";
//emit failedToStart();
return {};
case TOX_ERR_NEW_MALLOC:
qCritical() << "memory allocation failed";
//emit failedToStart();
return {};
case TOX_ERR_NEW_NULL:
qCritical() << "a parameter was null";
//emit failedToStart();
return {};
default:
qCritical() << "Tox core failed to start, unknown error code:" << tox_err;
//emit failedToStart();
return {};
}
qsrand(time(nullptr)); // TODO(sudden6): needed?
// tox should be valid by now
assert(core->tox != nullptr);
// toxcore is successfully created, create toxav
core->av = new CoreAV(core->tox);
if (!core->av || !core->av->getToxAv()) {
qCritical() << "Toxav failed to start";
//emit failedToStart();
//deadifyTox();
return {};
}
registerCallbacks(core->tox);
// connect the thread with the Core
connect(thread, &QThread::started, core.get(), &Core::onStarted);
core->moveToThread(thread);
// since this is allocated in the constructor move it to the other thread too
core->toxTimer.moveToThread(thread);
// when leaving this function 'core' should be ready for it's start() action or
// a nullptr
return core;
}
void Core::onStarted()
{
// TODO(sudden6): this assert should hold?
//assert(QThread::currentThread() == coreThread);
// One time initialization stuff
// set GUI with user and statusmsg
QString name = getUsername();
if (!name.isEmpty()) {
emit usernameSet(name);
}
QString msg = getStatusMessage();
if (!msg.isEmpty()) {
emit statusMessageSet(msg);
}
ToxId id = getSelfId();
// TODO: probably useless check, comes basically directly from toxcore
if (id.isValid()) {
emit idSet(id);
}
loadFriends();
process(); // starts its own timer process(); // starts its own timer
av->start(); av->start();
emit avReady(); emit avReady();
} }
/**
* @brief Starts toxcore and it's event loop, must be run from the Core thread
* @return true on success, false otherwise
*/
bool Core::start()
{
coreThread->start();
return true;
}
/**
* @brief Returns the global widget's Core instance
*/
Core* Core::getInstance()
{
return Nexus::getCore();
}
const CoreAV* Core::getAv() const
{
return av;
}
CoreAV* Core::getAv()
{
return av;
}
/* Using the now commented out statements in checkConnection(), I watched how /* Using the now commented out statements in checkConnection(), I watched how
* many ticks disconnects-after-initial-connect lasted. Out of roughly 15 trials, * many ticks disconnects-after-initial-connect lasted. Out of roughly 15 trials,
* 5 disconnected; 4 were DCd for less than 20 ticks, while the 5th was ~50 ticks. * 5 disconnected; 4 were DCd for less than 20 ticks, while the 5th was ~50 ticks.
@ -294,19 +276,21 @@ void Core::start(const QByteArray& savedata)
*/ */
void Core::process() void Core::process()
{ {
assert(QThread::currentThread() == coreThread);
if (!isReady()) { if (!isReady()) {
av->stop(); av->stop();
return; return;
} }
static int tolerance = CORE_DISCONNECT_TOLERANCE; static int tolerance = CORE_DISCONNECT_TOLERANCE;
tox_iterate(tox, getInstance()); tox_iterate(tox, this);
#ifdef DEBUG #ifdef DEBUG
// we want to see the debug messages immediately // we want to see the debug messages immediately
fflush(stdout); fflush(stdout);
#endif #endif
// TODO(sudden6): recheck if this is still necessary
if (checkConnection()) { if (checkConnection()) {
tolerance = CORE_DISCONNECT_TOLERANCE; tolerance = CORE_DISCONNECT_TOLERANCE;
} else if (!(--tolerance)) { } else if (!(--tolerance)) {
@ -315,7 +299,7 @@ void Core::process()
} }
unsigned sleeptime = qMin(tox_iteration_interval(tox), CoreFile::corefileIterationInterval()); unsigned sleeptime = qMin(tox_iteration_interval(tox), CoreFile::corefileIterationInterval());
toxTimer->start(sleeptime); toxTimer.start(sleeptime);
} }
bool Core::checkConnection() bool Core::checkConnection()
@ -339,7 +323,8 @@ bool Core::checkConnection()
*/ */
void Core::bootstrapDht() void Core::bootstrapDht()
{ {
QList<DhtServer> dhtServerList = s->getDhtServerList(); // TODO(sudden6): fix bootstrapping
QList<DhtServer> dhtServerList{};// = s->getDhtServerList();
int listSize = dhtServerList.size(); int listSize = dhtServerList.size();
if (!listSize) { if (!listSize) {
qWarning() << "no bootstrap list?!?"; qWarning() << "no bootstrap list?!?";
@ -540,7 +525,8 @@ void Core::acceptFriendRequest(const ToxPk& friendPk)
if (friendId == std::numeric_limits<uint32_t>::max()) { if (friendId == std::numeric_limits<uint32_t>::max()) {
emit failedToAddFriend(friendPk); emit failedToAddFriend(friendPk);
} else { } else {
profile.saveToxSave(); // TODO(sudden6): emit save request
//profile.saveToxSave();
emit friendAdded(friendId, friendPk); emit friendAdded(friendId, friendPk);
} }
} }
@ -579,7 +565,8 @@ void Core::requestFriendship(const ToxId& friendId, const QString& message)
QString errorMessage = getFriendRequestErrorMessage(friendId, message); QString errorMessage = getFriendRequestErrorMessage(friendId, message);
if (!errorMessage.isNull()) { if (!errorMessage.isNull()) {
emit failedToAddFriend(friendPk, errorMessage); emit failedToAddFriend(friendPk, errorMessage);
profile.saveToxSave(); // TODO(sudden6): emit save request
// profile.saveToxSave();
return; return;
} }
@ -595,7 +582,8 @@ void Core::requestFriendship(const ToxId& friendId, const QString& message)
emit requestSent(friendPk, message); emit requestSent(friendPk, message);
} }
profile.saveToxSave(); // TODO(sudden6): emit save request
// profile.saveToxSave();
} }
int Core::sendMessage(uint32_t friendId, const QString& message) int Core::sendMessage(uint32_t friendId, const QString& message)
@ -757,8 +745,8 @@ void Core::removeFriend(uint32_t friendId, bool fake)
emit failedToRemoveFriend(friendId); emit failedToRemoveFriend(friendId);
return; return;
} }
// TODO(sudden6): emit save request
profile.saveToxSave(); // profile.saveToxSave();
emit friendRemoved(friendId); emit friendRemoved(friendId);
} }
@ -817,9 +805,8 @@ void Core::setUsername(const QString& username)
} }
emit usernameSet(username); emit usernameSet(username);
if (ready) {
profile.saveToxSave(); // TODO(sudden6): request saving
}
} }
/** /**
@ -900,9 +887,7 @@ void Core::setStatusMessage(const QString& message)
return; return;
} }
if (ready) { // TODO(sudden6): request saving
profile.saveToxSave();
}
emit statusMessageSet(message); emit statusMessageSet(message);
} }
@ -929,7 +914,8 @@ void Core::setStatus(Status status)
} }
tox_self_set_status(tox, userstatus); tox_self_set_status(tox, userstatus);
profile.saveToxSave(); // TODO(sudden6): emit save request
// profile.saveToxSave();
emit statusSet(status); emit statusSet(status);
} }
@ -1369,7 +1355,7 @@ QString Core::getPeerName(const ToxPk& id) const
*/ */
bool Core::isReady() const bool Core::isReady() const
{ {
return av && av->getToxAv() && tox && ready; return av && av->getToxAv() && tox;
} }
/** /**
@ -1383,32 +1369,13 @@ void Core::setNospam(uint32_t nospam)
} }
/** /**
* @brief Returns the unencrypted tox save data * @brief Stops the AV thread and the timer here
*/ */
void Core::killTimers(bool onlyStop) void Core::killTimers()
{ {
assert(QThread::currentThread() == coreThread); assert(QThread::currentThread() == coreThread);
if (av) { if (av) {
av->stop(); av->stop();
} }
toxTimer->stop(); toxTimer.stop();
if (!onlyStop) {
delete toxTimer;
toxTimer = nullptr;
}
}
/**
* @brief Reinitialized the core.
* @warning Must be called from the Core thread, with the GUI thread ready to process events.
*/
void Core::reset()
{
assert(QThread::currentThread() == coreThread);
QByteArray toxsave = getToxSaveData();
ready = false;
killTimers(true);
deadifyTox();
GUI::clearContacts();
start(toxsave);
} }

View File

@ -28,8 +28,10 @@
#include <QMutex> #include <QMutex>
#include <QObject> #include <QObject>
#include <QTimer>
#include <functional> #include <functional>
#include <memory>
class CoreAV; class CoreAV;
class ICoreSettings; class ICoreSettings;
@ -45,11 +47,16 @@ enum class Status
Offline Offline
}; };
class Core;
using ToxCorePtr = std::unique_ptr<Core>;
class Core : public QObject class Core : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
Core(QThread* coreThread, Profile& profile, const ICoreSettings* const settings);
static ToxCorePtr makeToxCore(const QByteArray& savedata, const ICoreSettings* const settings);
static Core* getInstance(); static Core* getInstance();
const CoreAV* getAv() const; const CoreAV* getAv() const;
CoreAV* getAv(); CoreAV* getAv();
@ -85,10 +92,7 @@ public:
void sendFile(uint32_t friendId, QString filename, QString filePath, long long filesize); void sendFile(uint32_t friendId, QString filename, QString filePath, long long filesize);
public slots: public slots:
void start(const QByteArray& savedata); bool start();
void reset();
void process();
void bootstrapDht();
QByteArray getToxSaveData(); QByteArray getToxSaveData();
@ -189,6 +193,8 @@ signals:
void fileSendFailed(uint32_t friendId, const QString& fname); void fileSendFailed(uint32_t friendId, const QString& fname);
private: private:
Core(QThread* coreThread);
static void onFriendRequest(Tox* tox, const uint8_t* cUserId, const uint8_t* cMessage, static void onFriendRequest(Tox* tox, const uint8_t* cUserId, const uint8_t* cMessage,
size_t cMessageSize, void* core); size_t cMessageSize, void* core);
static void onFriendMessage(Tox* tox, uint32_t friendId, TOX_MESSAGE_TYPE type, static void onFriendMessage(Tox* tox, uint32_t friendId, TOX_MESSAGE_TYPE type,
@ -224,28 +230,28 @@ private:
bool checkConnection(); bool checkConnection();
void checkEncryptedHistory(); void checkEncryptedHistory();
void makeTox(QByteArray savedata); void makeTox(QByteArray savedata, ICoreSettings *s);
void makeAv(); void makeAv();
void loadFriends(); void loadFriends();
void bootstrapDht();
void checkLastOnline(uint32_t friendId); void checkLastOnline(uint32_t friendId);
void deadifyTox();
QString getFriendRequestErrorMessage(const ToxId& friendId, const QString& message) const; QString getFriendRequestErrorMessage(const ToxId& friendId, const QString& message) const;
static void registerCallbacks(Tox * tox);
private slots: private slots:
void killTimers(bool onlyStop); void killTimers();
void process();
void onStarted();
private: private:
Tox* tox; Tox* tox;
CoreAV* av; CoreAV* av;
QTimer* toxTimer; QTimer toxTimer;
Profile& profile;
QMutex messageSendMutex; QMutex messageSendMutex;
bool ready;
const ICoreSettings* const s;
static QThread* coreThread; QThread* coreThread = nullptr;
friend class Audio; ///< Audio can access our calls directly to reduce latency friend class Audio; ///< Audio can access our calls directly to reduce latency
friend class CoreFile; ///< CoreFile can access tox* and emit our signals friend class CoreFile; ///< CoreFile can access tox* and emit our signals

View File

@ -296,15 +296,17 @@ void CoreFile::onFileReceiveCallback(Tox*, uint32_t friendId, uint32_t fileId, u
qDebug() << QString("Received empty avatar request %1:%2").arg(friendId).arg(fileId); qDebug() << QString("Received empty avatar request %1:%2").arg(friendId).arg(fileId);
// Avatars of size 0 means explicitely no avatar // Avatars of size 0 means explicitely no avatar
emit core->friendAvatarRemoved(friendId); emit core->friendAvatarRemoved(friendId);
core->profile.removeAvatar(friendPk); // TODO(sudden6): use signal from above for that action
//core->profile.removeAvatar(friendPk);
return; return;
} else { } else {
static_assert(TOX_HASH_LENGTH <= TOX_FILE_ID_LENGTH, static_assert(TOX_HASH_LENGTH <= TOX_FILE_ID_LENGTH,
"TOX_HASH_LENGTH > TOX_FILE_ID_LENGTH!"); "TOX_HASH_LENGTH > TOX_FILE_ID_LENGTH!");
uint8_t avatarHash[TOX_FILE_ID_LENGTH]; uint8_t avatarHash[TOX_FILE_ID_LENGTH];
tox_file_get_file_id(core->tox, friendId, fileId, avatarHash, nullptr); tox_file_get_file_id(core->tox, friendId, fileId, avatarHash, nullptr);
if (core->profile.getAvatarHash(friendPk) // TODO(sudden6): fix that condition below
== QByteArray((char*)avatarHash, TOX_HASH_LENGTH)) { if (/*core->profile.getAvatarHash(friendPk)
== QByteArray((char*)avatarHash, TOX_HASH_LENGTH)*/ false) {
// If it's an avatar but we already have it cached, cancel // If it's an avatar but we already have it cached, cancel
qDebug() << QString( qDebug() << QString(
"Received avatar request %1:%2, reject, since we have it in cache.") "Received avatar request %1:%2, reject, since we have it in cache.")
@ -446,8 +448,10 @@ void CoreFile::onFileRecvChunkCallback(Tox* tox, uint32_t friendId, uint32_t fil
pic.loadFromData(file->avatarData); pic.loadFromData(file->avatarData);
if (!pic.isNull()) { if (!pic.isNull()) {
qDebug() << "Got" << file->avatarData.size() << "bytes of avatar data from" << friendId; qDebug() << "Got" << file->avatarData.size() << "bytes of avatar data from" << friendId;
// TODO(sudden6): handle the action below with the signal
/*
core->profile.saveAvatar(file->avatarData, core->profile.saveAvatar(file->avatarData,
core->getFriendPublicKey(friendId)); core->getFriendPublicKey(friendId));*/
emit core->friendAvatarChanged(friendId, pic); emit core->friendAvatarChanged(friendId, pic);
} }
} else { } else {

View File

@ -115,3 +115,14 @@ std::unique_ptr<ToxOptions> ToxOptions::makeToxOptions(const QByteArray& savedat
return toxOptions; return toxOptions;
} }
bool ToxOptions::getIPv6Enabled() const
{
return tox_options_get_ipv6_enabled(options);
}
void ToxOptions::setIPv6Enabled(bool enabled)
{
tox_options_set_ipv6_enabled(options, enabled);
}

View File

@ -16,6 +16,8 @@ public:
operator Tox_Options* (); operator Tox_Options* ();
const char* getProxyAddrData() const; const char* getProxyAddrData() const;
static std::unique_ptr<ToxOptions> makeToxOptions(const QByteArray &savedata, const ICoreSettings *s); static std::unique_ptr<ToxOptions> makeToxOptions(const QByteArray &savedata, const ICoreSettings *s);
bool getIPv6Enabled() const;
void setIPv6Enabled(bool enabled);
private: private:
ToxOptions(Tox_Options *options, const QByteArray& proxyAddrData); ToxOptions(Tox_Options *options, const QByteArray& proxyAddrData);

View File

@ -224,6 +224,8 @@ void Nexus::showMainGUI()
connect(widget, &Widget::friendRequestAccepted, core, &Core::acceptFriendRequest); connect(widget, &Widget::friendRequestAccepted, core, &Core::acceptFriendRequest);
profile->startCore(); profile->startCore();
GUI::setEnabled(true);
} }
/** /**

View File

@ -60,30 +60,22 @@ Profile::Profile(QString name, const QString& password, bool isNewProfile, const
s.setCurrentProfile(name); s.setCurrentProfile(name);
s.saveGlobal(); s.saveGlobal();
coreThread = new QThread(); core = Core::makeToxCore(toxsave, &s);
coreThread->setObjectName("qTox Core"); if(!core) {
core = new Core(coreThread, *this, &Settings::getInstance()); qDebug() << "failed to start ToxCore";
QObject::connect(core, &Core::idSet, this, return;
[this, password](const ToxId& id) { loadDatabase(id, password); }, }
Qt::QueuedConnection);
core->moveToThread(coreThread);
QObject::connect(coreThread, &QThread::started, core, [=]() {
core->start(toxsave);
// prevent segfault by checking if core started successfully const ToxId& selfId = core->getSelfId();
if(!core->isReady()) { loadDatabase(selfId, password);
qWarning() << "Core not ready, aborting"; const ToxPk& selfPk = selfId.getPublicKey();
return; QByteArray data = loadAvatarData(selfPk);
} if (data.isEmpty()) {
qDebug() << "Self avatar not found, will broadcast empty avatar to friends";
}
const ToxPk selfPk = core->getSelfPublicKey(); // TODO(sudden6): check if needed
QByteArray data = loadAvatarData(selfPk); //setAvatar(data, selfPk);
if (data.isEmpty()) {
qDebug() << "Self avatar not found, will broadcast empty avatar to friends";
}
setAvatar(data, selfPk);
});
} }
/** /**
@ -223,11 +215,6 @@ Profile::~Profile()
saveToxSave(); saveToxSave();
} }
core->deleteLater();
while (coreThread->isRunning())
qApp->processEvents();
delete coreThread;
if (!isRemoved) { if (!isRemoved) {
Settings::getInstance().savePersonal(this); Settings::getInstance().savePersonal(this);
Settings::getInstance().sync(); Settings::getInstance().sync();
@ -281,7 +268,8 @@ QStringList Profile::getProfiles()
Core* Profile::getCore() Core* Profile::getCore()
{ {
return core; // TODO(sudden6): this is evil
return core.get();
} }
QString Profile::getName() const QString Profile::getName() const
@ -294,7 +282,7 @@ QString Profile::getName() const
*/ */
void Profile::startCore() void Profile::startCore()
{ {
coreThread->start(); core->start();
} }
bool Profile::isNewProfile() bool Profile::isNewProfile()
@ -721,12 +709,13 @@ const ToxEncrypt* Profile::getPasskey() const
*/ */
void Profile::restartCore() void Profile::restartCore()
{ {
/* TODO(sudden6): rethink this
GUI::setEnabled(false); // Core::reset re-enables it GUI::setEnabled(false); // Core::reset re-enables it
if (!isRemoved && core->isReady()) { if (!isRemoved && core->isReady()) {
saveToxSave(); saveToxSave();
} }
QMetaObject::invokeMethod(core, "reset"); QMetaObject::invokeMethod(core, "reset");
*/
} }
/** /**

View File

@ -21,6 +21,7 @@
#ifndef PROFILE_H #ifndef PROFILE_H
#define PROFILE_H #define PROFILE_H
#include "src/core/core.h"
#include "src/core/toxencrypt.h" #include "src/core/toxencrypt.h"
#include "src/core/toxid.h" #include "src/core/toxid.h"
@ -33,9 +34,6 @@
#include <QVector> #include <QVector>
#include <memory> #include <memory>
class Core;
class QThread;
class Profile : public QObject class Profile : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -96,8 +94,7 @@ private:
QString avatarPath(const ToxPk& owner, bool forceUnencrypted = false); QString avatarPath(const ToxPk& owner, bool forceUnencrypted = false);
private: private:
Core* core; std::unique_ptr<Core> core = nullptr;
QThread* coreThread;
QString name; QString name;
std::unique_ptr<ToxEncrypt> passkey = nullptr; std::unique_ptr<ToxEncrypt> passkey = nullptr;
std::shared_ptr<RawDatabase> database; std::shared_ptr<RawDatabase> database;