mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-08-23 09:15:02 -05:00
Move impl to cpp, fix lifetime issues.
Took 11 minutes Took 2 minutes
This commit is contained in:
@@ -136,8 +136,11 @@ set(cockatrice_SOURCES
|
||||
src/interface/card_picture_loader/card_picture_loader_worker_work.cpp
|
||||
src/interface/card_picture_loader/card_picture_to_load.cpp
|
||||
src/interface/intents/intent.cpp
|
||||
src/interface/intents/intent.h
|
||||
src/interface/intents/intent_open_local_deck.cpp
|
||||
src/interface/intents/intent_open_local_deck.h
|
||||
src/interface/intents/intent_wait_for_database_load.cpp
|
||||
src/interface/intents/intent_wait_for_database_load.h
|
||||
src/interface/layouts/flow_layout.cpp
|
||||
src/interface/layouts/overlap_layout.cpp
|
||||
src/interface/widgets/utility/line_edit_completer.cpp
|
||||
@@ -364,7 +367,6 @@ set(cockatrice_SOURCES
|
||||
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h
|
||||
src/interface/widgets/utility/compact_push_button.cpp
|
||||
src/interface/widgets/utility/compact_push_button.h
|
||||
src/single_instance_manager.cpp
|
||||
src/single_instance_manager.h
|
||||
src/client/url_scheme_event_filter.h
|
||||
src/interface/intents/intent_connect_to_server.cpp
|
||||
@@ -372,12 +374,13 @@ set(cockatrice_SOURCES
|
||||
src/interface/intents/intent_disconnect_from_server.cpp
|
||||
src/interface/intents/intent_disconnect_from_server.h
|
||||
src/interface/intents/intent_join_server_game.cpp
|
||||
src/interface/intents/intent_join_server_game.h
|
||||
src/interface/intents/intent_join_server_room.cpp
|
||||
src/interface/intents/intent_join_server_room.h
|
||||
src/interface/intents/url_parser.cpp
|
||||
src/interface/intents/url_parser.h
|
||||
src/interface/intents/intent_login.cpp
|
||||
src/interface/intents/intent_login.h
|
||||
src/interface/intents/url_parser.cpp
|
||||
src/interface/intents/url_parser.h
|
||||
src/interface/widgets/server/user/user_info_popup.cpp
|
||||
src/interface/widgets/server/user/user_info_popup.h
|
||||
)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Version=1.0
|
||||
Type=Application
|
||||
Name=Cockatrice
|
||||
Exec=cockatrice
|
||||
Exec=cockatrice %U
|
||||
Icon=cockatrice
|
||||
Categories=Game;CardGame;
|
||||
MimeType=application/x-cockatrice;
|
||||
|
||||
@@ -1 +1,32 @@
|
||||
#include "intent.h"
|
||||
|
||||
Intent::Intent(QObject *parent) : QObject(parent)
|
||||
{
|
||||
// An intent is done as soon as it reports success or failure. Deleting it
|
||||
// also tears down its dependency chain and disconnects any signal wiring.
|
||||
connect(this, &Intent::finished, this, &QObject::deleteLater);
|
||||
connect(this, &Intent::failed, this, &QObject::deleteLater);
|
||||
}
|
||||
|
||||
Intent::~Intent() = default;
|
||||
|
||||
void Intent::execute()
|
||||
{
|
||||
if (checkPrecondition()) {
|
||||
onPreconditionSatisfied();
|
||||
} else {
|
||||
onPreconditionNotSatisfied();
|
||||
}
|
||||
}
|
||||
|
||||
void Intent::runDependency(Intent *dependency)
|
||||
{
|
||||
dependency->setParent(this);
|
||||
connect(dependency, &Intent::finished, this, [this]() {
|
||||
// Re-check after dependency finishes
|
||||
this->execute();
|
||||
});
|
||||
connect(dependency, &Intent::failed, this, &Intent::failed);
|
||||
|
||||
dependency->execute();
|
||||
}
|
||||
|
||||
@@ -8,19 +8,10 @@ class Intent : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Intent(QObject *parent = nullptr) : QObject(parent)
|
||||
{
|
||||
}
|
||||
virtual ~Intent() = default;
|
||||
explicit Intent(QObject *parent = nullptr);
|
||||
~Intent() override;
|
||||
|
||||
void execute()
|
||||
{
|
||||
if (checkPrecondition()) {
|
||||
onPreconditionSatisfied();
|
||||
} else {
|
||||
onPreconditionNotSatisfied();
|
||||
}
|
||||
}
|
||||
void execute();
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
@@ -33,17 +24,7 @@ protected:
|
||||
virtual void onPreconditionNotSatisfied() = 0;
|
||||
|
||||
// Helper to chain another intent
|
||||
void runDependency(Intent *dependency)
|
||||
{
|
||||
connect(dependency, &Intent::finished, this, [this]() {
|
||||
// Re-check after dependency finishes
|
||||
this->execute();
|
||||
});
|
||||
|
||||
connect(dependency, &Intent::failed, this, &Intent::failed);
|
||||
|
||||
dependency->execute();
|
||||
}
|
||||
void runDependency(Intent *dependency);
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTENT_H
|
||||
|
||||
@@ -1 +1,35 @@
|
||||
#include "intent_connect_to_server.h"
|
||||
|
||||
#include "intent_disconnect_from_server.h"
|
||||
|
||||
IntentConnectToServer::IntentConnectToServer(RemoteClient *_remoteClient, ContextConnectToServer *_context)
|
||||
: Intent(), remoteClient(_remoteClient), context(_context)
|
||||
{
|
||||
}
|
||||
|
||||
bool IntentConnectToServer::checkPrecondition() const
|
||||
{
|
||||
return remoteClient->getStatus() == ClientStatus::StatusDisconnected;
|
||||
}
|
||||
|
||||
void IntentConnectToServer::onPreconditionSatisfied()
|
||||
{
|
||||
remoteClient->connectToServer(context->hostname, context->port.toUInt(), context->username, context->password);
|
||||
connect(remoteClient, &RemoteClient::statusChanged, this, &IntentConnectToServer::onStatusChanged);
|
||||
connect(remoteClient, &RemoteClient::loginError, this,
|
||||
[this](Response::ResponseCode, const QString &reason, quint32, const QList<QString> &) {
|
||||
emit failed(reason);
|
||||
});
|
||||
}
|
||||
|
||||
void IntentConnectToServer::onPreconditionNotSatisfied()
|
||||
{
|
||||
runDependency(new IntentDisconnectFromServer(remoteClient));
|
||||
}
|
||||
|
||||
void IntentConnectToServer::onStatusChanged(ClientStatus status)
|
||||
{
|
||||
if (status == ClientStatus::StatusLoggedIn) {
|
||||
emit finished();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,52 +3,26 @@
|
||||
|
||||
#include "contexts/context_connect_to_server.h"
|
||||
#include "intent.h"
|
||||
#include "intent_disconnect_from_server.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
class IntentConnectToServer : public Intent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntentConnectToServer(RemoteClient *_remoteClient, ContextConnectToServer *_context)
|
||||
: Intent(), remoteClient(_remoteClient), context(_context)
|
||||
{
|
||||
}
|
||||
IntentConnectToServer(RemoteClient *_remoteClient, ContextConnectToServer *_context);
|
||||
|
||||
protected:
|
||||
bool checkPrecondition() const override
|
||||
{
|
||||
return remoteClient->getStatus() == ClientStatus::StatusDisconnected;
|
||||
}
|
||||
|
||||
void onPreconditionSatisfied() override
|
||||
{
|
||||
remoteClient->connectToServer(context->hostname, context->port.toUInt(), context->username, context->password);
|
||||
connect(remoteClient, &RemoteClient::statusChanged, this, &IntentConnectToServer::onStatusChanged);
|
||||
}
|
||||
|
||||
void onPreconditionNotSatisfied() override
|
||||
{
|
||||
runDependency(new IntentDisconnectFromServer(remoteClient));
|
||||
}
|
||||
bool checkPrecondition() const override;
|
||||
void onPreconditionSatisfied() override;
|
||||
void onPreconditionNotSatisfied() override;
|
||||
|
||||
private:
|
||||
RemoteClient *remoteClient;
|
||||
ContextConnectToServer *context;
|
||||
|
||||
private slots:
|
||||
void onStatusChanged(ClientStatus status)
|
||||
{
|
||||
if (status == ClientStatus::StatusLoggedIn) {
|
||||
auto timer = new QTimer(this);
|
||||
timer->setSingleShot(true);
|
||||
timer->setInterval(2000);
|
||||
connect(timer, &QTimer::timeout, this, &IntentConnectToServer::finished);
|
||||
timer->start();
|
||||
}
|
||||
}
|
||||
void onStatusChanged(ClientStatus status);
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTENT_CONNECT_TO_SERVER_H
|
||||
|
||||
@@ -1 +1,29 @@
|
||||
#include "intent_disconnect_from_server.h"
|
||||
|
||||
IntentDisconnectFromServer::IntentDisconnectFromServer(RemoteClient *_remoteClient)
|
||||
: Intent(), remoteClient(_remoteClient)
|
||||
{
|
||||
}
|
||||
|
||||
bool IntentDisconnectFromServer::checkPrecondition() const
|
||||
{
|
||||
return remoteClient->getStatus() == ClientStatus::StatusDisconnected;
|
||||
}
|
||||
|
||||
void IntentDisconnectFromServer::onPreconditionSatisfied()
|
||||
{
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void IntentDisconnectFromServer::onPreconditionNotSatisfied()
|
||||
{
|
||||
connect(remoteClient, &RemoteClient::statusChanged, this, &IntentDisconnectFromServer::onStatusChanged);
|
||||
remoteClient->disconnectFromServer();
|
||||
}
|
||||
|
||||
void IntentDisconnectFromServer::onStatusChanged(ClientStatus status)
|
||||
{
|
||||
if (status == ClientStatus::StatusDisconnected) {
|
||||
emit finished();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#ifndef COCKATRICE_INTENT_DISCONNECT_FROM_SERVER_H
|
||||
#define COCKATRICE_INTENT_DISCONNECT_FROM_SERVER_H
|
||||
|
||||
#include "intent.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
@@ -8,40 +9,18 @@ class IntentDisconnectFromServer : public Intent
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntentDisconnectFromServer(RemoteClient *_remoteClient) : Intent(), remoteClient(_remoteClient)
|
||||
{
|
||||
}
|
||||
IntentDisconnectFromServer(RemoteClient *_remoteClient);
|
||||
|
||||
protected:
|
||||
bool checkPrecondition() const override
|
||||
{
|
||||
return remoteClient->getStatus() == ClientStatus::StatusDisconnected;
|
||||
}
|
||||
|
||||
void onPreconditionSatisfied() override
|
||||
{
|
||||
qWarning() << "Client disconnected, disconnect is finished";
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void onPreconditionNotSatisfied() override
|
||||
{
|
||||
qWarning() << "Client not disconnected, hooking up signal and disconnecting." << remoteClient->getStatus();
|
||||
connect(remoteClient, &RemoteClient::statusChanged, this, &IntentDisconnectFromServer::onStatusChanged);
|
||||
remoteClient->disconnectFromServer();
|
||||
}
|
||||
bool checkPrecondition() const override;
|
||||
void onPreconditionSatisfied() override;
|
||||
void onPreconditionNotSatisfied() override;
|
||||
|
||||
private:
|
||||
RemoteClient *remoteClient;
|
||||
|
||||
private slots:
|
||||
void onStatusChanged(ClientStatus status)
|
||||
{
|
||||
qWarning() << "Client Status changed: " << status;
|
||||
if (status == ClientStatus::StatusDisconnected) {
|
||||
qWarning() << "Client disconnected, finished";
|
||||
emit finished();
|
||||
}
|
||||
}
|
||||
void onStatusChanged(ClientStatus status);
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTENT_DISCONNECT_FROM_SERVER_H
|
||||
|
||||
@@ -1 +1,78 @@
|
||||
#include "intent_join_server_game.h"
|
||||
|
||||
#include "../widgets/server/game_selector.h"
|
||||
#include "../widgets/tabs/tab_room.h"
|
||||
#include "../widgets/tabs/tab_supervisor.h"
|
||||
#include "intent_join_server_room.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
IntentJoinServerGame::IntentJoinServerGame(TabSupervisor *_tabSupervisor,
|
||||
RemoteClient *_remoteClient,
|
||||
ContextJoinGame *_context)
|
||||
: Intent(), tabSupervisor(_tabSupervisor), remoteClient(_remoteClient), context(_context)
|
||||
{
|
||||
}
|
||||
|
||||
bool IntentJoinServerGame::checkPrecondition() const
|
||||
{
|
||||
if (remoteClient->getStatus() != ClientStatus::StatusLoggedIn) {
|
||||
return false;
|
||||
}
|
||||
// peerPort() reflects the actual TCP peer, which may differ from the
|
||||
// configured server port (e.g. when connecting through a proxy), so only
|
||||
// the hostname is compared here.
|
||||
if (remoteClient->peerName() != context->roomContext.serverContext.hostname) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tabSupervisor->getRoomTabs().contains(context->roomContext.roomId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IntentJoinServerGame::onPreconditionSatisfied()
|
||||
{
|
||||
TabRoom *room = tabSupervisor->getRoomTabs().value(context->roomContext.roomId);
|
||||
if (!tryJoinGame(room)) {
|
||||
waitForGame(room);
|
||||
}
|
||||
}
|
||||
|
||||
void IntentJoinServerGame::onPreconditionNotSatisfied()
|
||||
{
|
||||
runDependency(new IntentJoinServerRoom(tabSupervisor, remoteClient, &context->roomContext));
|
||||
}
|
||||
|
||||
bool IntentJoinServerGame::tryJoinGame(TabRoom *room)
|
||||
{
|
||||
if (!room) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (room->getGameSelector()->joinGameById(context->gameId)) {
|
||||
joined = true;
|
||||
emit finished();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void IntentJoinServerGame::waitForGame(TabRoom *room)
|
||||
{
|
||||
connect(room, &TabRoom::gameListUpdated, this, [this]() {
|
||||
TabRoom *updatedRoom = tabSupervisor->getRoomTabs().value(context->roomContext.roomId);
|
||||
if (updatedRoom) {
|
||||
tryJoinGame(updatedRoom);
|
||||
}
|
||||
});
|
||||
|
||||
QTimer::singleShot(15000, this, [this]() {
|
||||
if (!joined) {
|
||||
emit failed(tr("Game %1 not found in the room").arg(context->gameId));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,63 +1,35 @@
|
||||
#ifndef COCKATRICE_INTENT_JOIN_SERVER_GAME_H
|
||||
#define COCKATRICE_INTENT_JOIN_SERVER_GAME_H
|
||||
|
||||
#include "../widgets/server/game_selector.h"
|
||||
#include "../widgets/tabs/tab_room.h"
|
||||
#include "../widgets/tabs/tab_server.h"
|
||||
#include "../widgets/tabs/tab_supervisor.h"
|
||||
#include "contexts/context_join_game.h"
|
||||
#include "contexts/context_join_room.h"
|
||||
#include "intent.h"
|
||||
#include "intent_join_server_room.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
#include <QScopedPointer>
|
||||
|
||||
class TabRoom;
|
||||
class TabSupervisor;
|
||||
|
||||
class IntentJoinServerGame : public Intent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntentJoinServerGame(TabSupervisor *_tabSupervisor, RemoteClient *_remoteClient, ContextJoinGame *_context)
|
||||
: Intent(), tabSupervisor(_tabSupervisor), remoteClient(_remoteClient), context(_context)
|
||||
{
|
||||
}
|
||||
IntentJoinServerGame(TabSupervisor *_tabSupervisor, RemoteClient *_remoteClient, ContextJoinGame *_context);
|
||||
|
||||
protected:
|
||||
bool checkPrecondition() const override
|
||||
{
|
||||
if (remoteClient->getStatus() != ClientStatus::StatusLoggedIn) {
|
||||
return false;
|
||||
}
|
||||
if (remoteClient->peerName() != context->roomContext.serverContext.hostname) {
|
||||
return false;
|
||||
}
|
||||
if (QString::number(remoteClient->peerPort()) != context->roomContext.serverContext.port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tabSupervisor->getRoomTabs()[context->roomContext.roomId]) {
|
||||
qWarning() << "No room tab";
|
||||
return false;
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void onPreconditionSatisfied() override
|
||||
{
|
||||
qWarning() << "All lights green, joining game";
|
||||
TabRoom *room = tabSupervisor->getRoomTabs()[context->roomContext.roomId];
|
||||
room->getGameSelector()->joinGameById(context->gameId);
|
||||
}
|
||||
|
||||
void onPreconditionNotSatisfied() override
|
||||
{
|
||||
runDependency(new IntentJoinServerRoom(tabSupervisor, remoteClient, &context->roomContext));
|
||||
}
|
||||
bool checkPrecondition() const override;
|
||||
void onPreconditionSatisfied() override;
|
||||
void onPreconditionNotSatisfied() override;
|
||||
|
||||
private:
|
||||
bool tryJoinGame(TabRoom *room);
|
||||
void waitForGame(TabRoom *room);
|
||||
|
||||
TabSupervisor *tabSupervisor;
|
||||
RemoteClient *remoteClient;
|
||||
ContextJoinGame *context;
|
||||
QScopedPointer<ContextJoinGame> context;
|
||||
bool joined = false;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTENT_JOIN_SERVER_GAME_H
|
||||
|
||||
@@ -1 +1,55 @@
|
||||
#include "intent_join_server_room.h"
|
||||
|
||||
#include "../widgets/tabs/tab_room.h"
|
||||
#include "../widgets/tabs/tab_server.h"
|
||||
#include "../widgets/tabs/tab_supervisor.h"
|
||||
#include "intent_connect_to_server.h"
|
||||
|
||||
IntentJoinServerRoom::IntentJoinServerRoom(TabSupervisor *_tabSupervisor,
|
||||
RemoteClient *_remoteClient,
|
||||
ContextJoinRoom *_context)
|
||||
: Intent(), tabSupervisor(_tabSupervisor), remoteClient(_remoteClient), context(_context)
|
||||
{
|
||||
}
|
||||
|
||||
bool IntentJoinServerRoom::checkPrecondition() const
|
||||
{
|
||||
if (remoteClient->getStatus() != ClientStatus::StatusLoggedIn) {
|
||||
return false;
|
||||
}
|
||||
// peerPort() reflects the actual TCP peer, which may differ from the
|
||||
// configured server port (e.g. when connecting through a proxy), so only
|
||||
// the hostname is compared here.
|
||||
if (remoteClient->peerName() != context->serverContext.hostname) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IntentJoinServerRoom::onPreconditionSatisfied()
|
||||
{
|
||||
if (tabSupervisor->getRoomTabs().contains(context->roomId)) {
|
||||
tabSupervisor->setCurrentWidget(tabSupervisor->getRoomTabs().value(context->roomId));
|
||||
emit finished();
|
||||
return;
|
||||
}
|
||||
|
||||
TabServer *tabServer = tabSupervisor->getTabServer();
|
||||
if (!tabServer) {
|
||||
tabSupervisor->openTabServer();
|
||||
tabServer = tabSupervisor->getTabServer();
|
||||
}
|
||||
if (!tabServer) {
|
||||
emit failed(tr("No server tab available"));
|
||||
return;
|
||||
}
|
||||
|
||||
tabServer->joinRoom(context->roomId, true);
|
||||
connect(tabServer, &TabServer::roomJoined, this, &IntentJoinServerRoom::finished);
|
||||
}
|
||||
|
||||
void IntentJoinServerRoom::onPreconditionNotSatisfied()
|
||||
{
|
||||
runDependency(new IntentConnectToServer(remoteClient, &context->serverContext));
|
||||
}
|
||||
|
||||
@@ -1,53 +1,23 @@
|
||||
#ifndef COCKATRICE_INTENT_JOIN_SERVER_ROOM_H
|
||||
#define COCKATRICE_INTENT_JOIN_SERVER_ROOM_H
|
||||
|
||||
#include "../widgets/tabs/tab_server.h"
|
||||
#include "../widgets/tabs/tab_supervisor.h"
|
||||
#include "contexts/context_connect_to_server.h"
|
||||
#include "contexts/context_join_room.h"
|
||||
#include "intent.h"
|
||||
#include "intent_connect_to_server.h"
|
||||
#include "intent_disconnect_from_server.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
class TabSupervisor;
|
||||
|
||||
class IntentJoinServerRoom : public Intent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntentJoinServerRoom(TabSupervisor *_tabSupervisor, RemoteClient *_remoteClient, ContextJoinRoom *_context)
|
||||
: Intent(), tabSupervisor(_tabSupervisor), remoteClient(_remoteClient), context(_context)
|
||||
{
|
||||
}
|
||||
IntentJoinServerRoom(TabSupervisor *_tabSupervisor, RemoteClient *_remoteClient, ContextJoinRoom *_context);
|
||||
|
||||
protected:
|
||||
bool checkPrecondition() const override
|
||||
{
|
||||
if (remoteClient->getStatus() != ClientStatus::StatusLoggedIn) {
|
||||
return false;
|
||||
}
|
||||
if (remoteClient->peerName() != context->serverContext.hostname) {
|
||||
return false;
|
||||
}
|
||||
if (QString::number(remoteClient->peerPort()) != context->serverContext.port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void onPreconditionSatisfied() override
|
||||
{
|
||||
auto tabServer = tabSupervisor->getTabServer();
|
||||
tabServer->joinRoom(context->roomId, true);
|
||||
|
||||
connect(tabServer, &TabServer::roomJoined, this, &IntentJoinServerRoom::finished);
|
||||
}
|
||||
|
||||
void onPreconditionNotSatisfied() override
|
||||
{
|
||||
runDependency(new IntentConnectToServer(remoteClient, &context->serverContext));
|
||||
}
|
||||
bool checkPrecondition() const override;
|
||||
void onPreconditionSatisfied() override;
|
||||
void onPreconditionNotSatisfied() override;
|
||||
|
||||
private:
|
||||
TabSupervisor *tabSupervisor;
|
||||
|
||||
@@ -1 +1,33 @@
|
||||
#include "intent_login.h"
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "libcockatrice/settings/servers_settings.h"
|
||||
|
||||
IntentGetLoginCredentials::IntentGetLoginCredentials(ContextConnectToServer *_context) : Intent(), context(_context)
|
||||
{
|
||||
}
|
||||
|
||||
bool IntentGetLoginCredentials::checkPrecondition() const
|
||||
{
|
||||
ServersSettings &servers = SettingsCache::instance().servers();
|
||||
return servers.hasLoginData(context->hostname, context->port);
|
||||
}
|
||||
|
||||
void IntentGetLoginCredentials::onPreconditionSatisfied()
|
||||
{
|
||||
ServersSettings &servers = SettingsCache::instance().servers();
|
||||
const int index = servers.findServerIndex(context->hostname, context->port);
|
||||
|
||||
if (index >= 0) {
|
||||
context->username = servers.getValue(QString("username%1").arg(index), "server", "server_details").toString();
|
||||
context->password = servers.getValue(QString("password%1").arg(index), "server", "server_details").toString();
|
||||
emit finished();
|
||||
} else {
|
||||
emit failed(tr("No saved credentials for this server"));
|
||||
}
|
||||
}
|
||||
|
||||
void IntentGetLoginCredentials::onPreconditionNotSatisfied()
|
||||
{
|
||||
emit failed(tr("No saved credentials for this server"));
|
||||
}
|
||||
|
||||
@@ -1,51 +1,22 @@
|
||||
#ifndef COCKATRICE_INTENT_LOGIN_H
|
||||
#define COCKATRICE_INTENT_LOGIN_H
|
||||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "contexts/context_connect_to_server.h"
|
||||
#include "intent.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
class IntentGetLoginCredentials : public Intent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntentGetLoginCredentials(RemoteClient *_remoteClient, ContextConnectToServer *_context)
|
||||
: Intent(), remoteClient(_remoteClient), context(_context)
|
||||
{
|
||||
}
|
||||
IntentGetLoginCredentials(ContextConnectToServer *_context);
|
||||
|
||||
protected:
|
||||
bool checkPrecondition() const override
|
||||
{
|
||||
ServersSettings &servers = SettingsCache::instance().servers();
|
||||
return servers.hasLoginData(context->hostname, context->port);
|
||||
}
|
||||
|
||||
void onPreconditionSatisfied() override
|
||||
{
|
||||
ServersSettings &servers = SettingsCache::instance().servers();
|
||||
auto index = servers.findServerIndex(context->hostname, context->port);
|
||||
|
||||
if (index >= 0) {
|
||||
context->username =
|
||||
servers.getValue(QString("username%1").arg(index), "server", "server_details").toString();
|
||||
context->password =
|
||||
servers.getValue(QString("password%1").arg(index), "server", "server_details").toString();
|
||||
emit finished();
|
||||
qWarning() << "Using saved credentials";
|
||||
} else {
|
||||
qWarning() << "No saved server entry";
|
||||
}
|
||||
}
|
||||
|
||||
void onPreconditionNotSatisfied() override
|
||||
{
|
||||
}
|
||||
bool checkPrecondition() const override;
|
||||
void onPreconditionSatisfied() override;
|
||||
void onPreconditionNotSatisfied() override;
|
||||
|
||||
private:
|
||||
RemoteClient *remoteClient;
|
||||
ContextConnectToServer *context;
|
||||
};
|
||||
|
||||
|
||||
@@ -1 +1,32 @@
|
||||
#include "intent_open_local_deck.h"
|
||||
|
||||
#include "../deck_loader/deck_file_format.h"
|
||||
#include "../deck_loader/deck_loader.h"
|
||||
#include "../widgets/tabs/tab_supervisor.h"
|
||||
#include "intent_wait_for_database_load.h"
|
||||
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
|
||||
IntentOpenLocalDeck::IntentOpenLocalDeck(TabSupervisor *_tabSupervisor, const QString &_file)
|
||||
: Intent(), tabSupervisor(_tabSupervisor), file(_file)
|
||||
{
|
||||
}
|
||||
|
||||
bool IntentOpenLocalDeck::checkPrecondition() const
|
||||
{
|
||||
return CardDatabaseManager::getInstance()->getLoadStatus() == LoadStatus::Ok;
|
||||
}
|
||||
|
||||
void IntentOpenLocalDeck::onPreconditionSatisfied()
|
||||
{
|
||||
std::optional<LoadedDeck> deckOpt = DeckLoader::loadFromFile(file, DeckFileFormat::getFormatFromName(file), true);
|
||||
if (deckOpt) {
|
||||
tabSupervisor->openDeckInNewTab(deckOpt.value());
|
||||
}
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void IntentOpenLocalDeck::onPreconditionNotSatisfied()
|
||||
{
|
||||
runDependency(new IntentWaitForDatabaseLoad);
|
||||
}
|
||||
|
||||
@@ -1,40 +1,23 @@
|
||||
#ifndef COCKATRICE_INTENT_OPEN_LOCAL_DECK_H
|
||||
#define COCKATRICE_INTENT_OPEN_LOCAL_DECK_H
|
||||
#include "../widgets/tabs/tab_supervisor.h"
|
||||
|
||||
#include "intent.h"
|
||||
#include "intent_wait_for_database_load.h"
|
||||
#include "libcockatrice/card/database/card_database_manager.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
class TabSupervisor;
|
||||
|
||||
class IntentOpenLocalDeck : public Intent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IntentOpenLocalDeck(TabSupervisor *_tabSupervisor, const QString &_file)
|
||||
: Intent(), tabSupervisor(_tabSupervisor), file(_file)
|
||||
{
|
||||
}
|
||||
IntentOpenLocalDeck(TabSupervisor *_tabSupervisor, const QString &_file);
|
||||
|
||||
protected:
|
||||
bool checkPrecondition() const override
|
||||
{
|
||||
return CardDatabaseManager::getInstance()->getLoadStatus() == LoadStatus::Ok;
|
||||
}
|
||||
|
||||
void onPreconditionSatisfied() override
|
||||
{
|
||||
std::optional<LoadedDeck> deckOpt =
|
||||
DeckLoader::loadFromFile(file, DeckFileFormat::getFormatFromName(file), true);
|
||||
if (deckOpt) {
|
||||
tabSupervisor->openDeckInNewTab(deckOpt.value());
|
||||
}
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void onPreconditionNotSatisfied() override
|
||||
{
|
||||
runDependency(new IntentWaitForDatabaseLoad);
|
||||
}
|
||||
bool checkPrecondition() const override;
|
||||
void onPreconditionSatisfied() override;
|
||||
void onPreconditionNotSatisfied() override;
|
||||
|
||||
private:
|
||||
TabSupervisor *tabSupervisor;
|
||||
|
||||
@@ -1 +1,19 @@
|
||||
#include "intent_wait_for_database_load.h"
|
||||
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
|
||||
bool IntentWaitForDatabaseLoad::checkPrecondition() const
|
||||
{
|
||||
return CardDatabaseManager::getInstance()->getLoadStatus() == LoadStatus::Ok;
|
||||
}
|
||||
|
||||
void IntentWaitForDatabaseLoad::onPreconditionSatisfied()
|
||||
{
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void IntentWaitForDatabaseLoad::onPreconditionNotSatisfied()
|
||||
{
|
||||
connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this,
|
||||
[this]() { emit finished(); });
|
||||
}
|
||||
|
||||
@@ -2,28 +2,15 @@
|
||||
#define COCKATRICE_INTENT_WAIT_FOR_DATABASE_LOAD_H
|
||||
|
||||
#include "intent.h"
|
||||
#include "libcockatrice/card/database/card_database_manager.h"
|
||||
|
||||
class IntentWaitForDatabaseLoad : public Intent
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
bool checkPrecondition() const override
|
||||
{
|
||||
return CardDatabaseManager::getInstance()->getLoadStatus() == LoadStatus::Ok;
|
||||
}
|
||||
|
||||
void onPreconditionSatisfied() override
|
||||
{
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void onPreconditionNotSatisfied() override
|
||||
{
|
||||
connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this,
|
||||
[this]() { emit finished(); });
|
||||
}
|
||||
bool checkPrecondition() const override;
|
||||
void onPreconditionSatisfied() override;
|
||||
void onPreconditionNotSatisfied() override;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_INTENT_WAIT_FOR_DATABASE_LOAD_H
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#include "url_parser.h"
|
||||
|
||||
#include "../window_main.h"
|
||||
#include "contexts/context_join_room.h"
|
||||
#include "contexts/context_join_game.h"
|
||||
#include "intent_join_server_game.h"
|
||||
#include "intent_join_server_room.h"
|
||||
#include "intent_login.h"
|
||||
|
||||
#include <QDebug>
|
||||
@@ -46,6 +45,7 @@ void IntentUrlParser::handleJoinGame(const QUrlQuery &query)
|
||||
|
||||
if (!ok) {
|
||||
qWarning() << "Invalid or missing roomId";
|
||||
delete ctx;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -54,15 +54,20 @@ void IntentUrlParser::handleJoinGame(const QUrlQuery &query)
|
||||
|
||||
if (!ok) {
|
||||
qWarning() << "Invalid or missing gameId";
|
||||
delete ctx;
|
||||
return;
|
||||
}
|
||||
|
||||
auto getLoginCredentialsIntent =
|
||||
new IntentGetLoginCredentials(mainWindow->getRemoteClient(), &ctx->roomContext.serverContext);
|
||||
|
||||
// The join game intent owns the context and the credential lookup; once the
|
||||
// chain finishes (or fails) it deletes the whole tree.
|
||||
auto joinGameIntent = new IntentJoinServerGame(mainWindow->getTabSupervisor(), mainWindow->getRemoteClient(), ctx);
|
||||
joinGameIntent->setParent(this);
|
||||
|
||||
auto getLoginCredentialsIntent = new IntentGetLoginCredentials(&ctx->roomContext.serverContext);
|
||||
getLoginCredentialsIntent->setParent(joinGameIntent);
|
||||
|
||||
connect(getLoginCredentialsIntent, &Intent::finished, joinGameIntent, &Intent::execute);
|
||||
connect(getLoginCredentialsIntent, &Intent::failed, joinGameIntent, &Intent::failed);
|
||||
|
||||
getLoginCredentialsIntent->execute();
|
||||
}
|
||||
|
||||
@@ -310,7 +310,6 @@ void GameSelector::customContextMenu(const QPoint &point)
|
||||
connect(&getGameInfo, &QAction::triggered, this, [=, this]() {
|
||||
const ServerInfo_Game &gameInfo = gameListModel->getGame(index.data(Qt::UserRole).toInt());
|
||||
const QMap<int, QString> &gameTypes = gameListModel->getGameTypes().value(gameInfo.room_id());
|
||||
qWarning() << "Game Id: " << gameInfo.game_id();
|
||||
|
||||
DlgCreateGame dlg(gameInfo, gameTypes, this);
|
||||
dlg.exec();
|
||||
|
||||
@@ -280,6 +280,7 @@ void TabRoom::processListGamesEvent(const Event_ListGames &event)
|
||||
for (int i = 0; i < gameListSize; ++i) {
|
||||
gameSelector->processGameInfo(event.game_list(i));
|
||||
}
|
||||
emit gameListUpdated();
|
||||
}
|
||||
|
||||
void TabRoom::processJoinRoomEvent(const Event_JoinRoom &event)
|
||||
|
||||
@@ -78,6 +78,7 @@ signals:
|
||||
void openMessageDialog(const QString &userName, bool focus);
|
||||
void maximizeClient();
|
||||
void notIdle();
|
||||
void gameListUpdated();
|
||||
private slots:
|
||||
void sendMessage();
|
||||
void sayFinished(const Response &response);
|
||||
|
||||
@@ -587,6 +587,10 @@ void TabSupervisor::actTabServer(bool checked)
|
||||
|
||||
void TabSupervisor::openTabServer()
|
||||
{
|
||||
if (tabServer) {
|
||||
return;
|
||||
}
|
||||
|
||||
tabServer = new TabServer(this, client);
|
||||
connect(tabServer, &TabServer::roomJoined, this, &TabSupervisor::addRoomTab);
|
||||
myAddTab(tabServer, aTabServer);
|
||||
|
||||
@@ -187,6 +187,7 @@ public slots:
|
||||
void maximizeMainWindow();
|
||||
void actTabVisualDeckStorage(bool checked);
|
||||
void actTabReplays(bool checked);
|
||||
void openTabServer();
|
||||
private slots:
|
||||
void refreshShortcuts();
|
||||
|
||||
@@ -199,7 +200,6 @@ private slots:
|
||||
|
||||
void openTabVisualDeckStorage();
|
||||
void openTabHome();
|
||||
void openTabServer();
|
||||
void openTabAccount();
|
||||
void openTabDeckStorage();
|
||||
void openTabReplays();
|
||||
|
||||
@@ -345,9 +345,10 @@ int main(int argc, char *argv[])
|
||||
// No primary instance → become server
|
||||
qInfo() << "No existing instance found, becoming primary instance";
|
||||
} else {
|
||||
// Plain launch: try to start server, but do not connect to any existing
|
||||
// Plain launch: if another instance is running, run independently
|
||||
// instead of handing off and exiting.
|
||||
if (!instance.tryRun(QStringList())) {
|
||||
// Server already exists → just run independently
|
||||
// Another instance is already running → just run independently
|
||||
qInfo() << "Another instance exists, running independently";
|
||||
} else {
|
||||
qInfo() << "No existing instance found, starting server";
|
||||
|
||||
@@ -8,53 +8,74 @@ bool SingleInstanceManager::tryRun(const QStringList &filesToSend)
|
||||
{
|
||||
serverName = "CockatriceSingleInstance";
|
||||
|
||||
// Attempt to connect only if we have files to send
|
||||
if (!filesToSend.isEmpty()) {
|
||||
QLocalSocket socket;
|
||||
socket.connectToServer(serverName);
|
||||
if (socket.waitForConnected(200)) {
|
||||
// Serialize payload with length prefix
|
||||
QByteArray payload;
|
||||
QDataStream out(&payload, QIODevice::WriteOnly);
|
||||
out << filesToSend;
|
||||
|
||||
QByteArray message;
|
||||
QDataStream msgStream(&message, QIODevice::WriteOnly);
|
||||
msgStream << quint32(payload.size());
|
||||
message.append(payload);
|
||||
|
||||
socket.write(message);
|
||||
socket.flush();
|
||||
socket.waitForBytesWritten(1000);
|
||||
|
||||
return false; // Sent successfully → exit
|
||||
}
|
||||
// Hand off to an already-running primary instance if one exists.
|
||||
if (forwardToPrimary(filesToSend)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, start server
|
||||
// No primary instance is currently reachable, so become the primary.
|
||||
server = new QLocalServer(this);
|
||||
connect(server, &QLocalServer::newConnection, this, &SingleInstanceManager::handleNewConnection);
|
||||
|
||||
if (!server->listen(serverName)) {
|
||||
QLocalServer::removeServer(serverName);
|
||||
server->listen(serverName);
|
||||
if (server->listen(serverName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return true; // This process is now primary server
|
||||
// Another instance may have started while we were probing; hand off to it
|
||||
// instead of stealing its socket.
|
||||
if (forwardToPrimary(filesToSend)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The socket is stale (left over by a crashed instance): remove it and
|
||||
// retry. If that still fails, another instance just took the name.
|
||||
QLocalServer::removeServer(serverName);
|
||||
if (server->listen(serverName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
forwardToPrimary(filesToSend);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SingleInstanceManager::forwardToPrimary(const QStringList &filesToSend)
|
||||
{
|
||||
QLocalSocket socket;
|
||||
socket.connectToServer(serverName);
|
||||
if (!socket.waitForConnected(200)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Serialize payload with length prefix
|
||||
QByteArray payload;
|
||||
QDataStream out(&payload, QIODevice::WriteOnly);
|
||||
out << filesToSend;
|
||||
|
||||
QByteArray message;
|
||||
QDataStream msgStream(&message, QIODevice::WriteOnly);
|
||||
msgStream << quint32(payload.size());
|
||||
message.append(payload);
|
||||
|
||||
socket.write(message);
|
||||
socket.flush();
|
||||
socket.waitForBytesWritten(1000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SingleInstanceManager::handleNewConnection()
|
||||
{
|
||||
QLocalSocket *socket = server->nextPendingConnection();
|
||||
|
||||
// Per-connection state
|
||||
auto buffer = new QByteArray();
|
||||
auto expectedSize = new quint32(0);
|
||||
// Per-connection state. QSharedPointer keeps the buffers alive for as long
|
||||
// as the connection handler is attached to the socket.
|
||||
auto buffer = QSharedPointer<QByteArray>::create();
|
||||
auto expectedSize = QSharedPointer<quint32>::create(0);
|
||||
|
||||
connect(socket, &QLocalSocket::readyRead, this, [this, socket, buffer, expectedSize]() {
|
||||
buffer->append(socket->readAll());
|
||||
|
||||
QDataStream stream(buffer, QIODevice::ReadOnly);
|
||||
QDataStream stream(buffer.data(), QIODevice::ReadOnly);
|
||||
|
||||
while (true) {
|
||||
// Step 1: read size
|
||||
@@ -90,4 +111,4 @@ void SingleInstanceManager::handleNewConnection()
|
||||
});
|
||||
|
||||
connect(socket, &QLocalSocket::disconnected, socket, &QLocalSocket::deleteLater);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ class SingleInstanceManager : public QObject
|
||||
public:
|
||||
explicit SingleInstanceManager(QObject *parent = nullptr);
|
||||
|
||||
// Returns true if this process became the primary instance, false if
|
||||
// another instance is already running (and received our files).
|
||||
bool tryRun(const QStringList &initialFiles);
|
||||
|
||||
signals:
|
||||
@@ -21,8 +23,10 @@ private slots:
|
||||
void handleNewConnection();
|
||||
|
||||
private:
|
||||
bool forwardToPrimary(const QStringList &filesToSend);
|
||||
|
||||
QString serverName;
|
||||
QLocalServer *server = nullptr;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_SINGLE_INSTANCE_MANAGER_H
|
||||
#endif // COCKATRICE_SINGLE_INSTANCE_MANAGER_H
|
||||
|
||||
Reference in New Issue
Block a user