From 229cdb8b47d118df2c3dae83412e24fafbeab005 Mon Sep 17 00:00:00 2001 From: jolavillette Date: Sat, 2 May 2026 10:21:17 +0200 Subject: [PATCH 1/4] fix several display issues --- RetroChessPlugin.cpp | 2 +- gui/NEMainpage.cpp | 10 +++---- gui/RetroChessChatWidgetHolder.cpp | 26 ++++++++++++++++-- gui/chess.cpp | 43 +++++++++++++++++++----------- services/p3RetroChess.cc | 5 ++++ services/rsRetroChessItems.h | 5 +++- 6 files changed, 67 insertions(+), 24 deletions(-) diff --git a/RetroChessPlugin.cpp b/RetroChessPlugin.cpp index 5bd9144..3029b09 100644 --- a/RetroChessPlugin.cpp +++ b/RetroChessPlugin.cpp @@ -181,7 +181,7 @@ std::string RetroChessPlugin::getPluginName() const return "RetroChess"; } -QTranslator* RetroChessPlugin::qt_translator(QApplication */*app*/, const QString& languageCode, const QString& externalDir) const +QTranslator* RetroChessPlugin::qt_translator(QApplication */*app*/, const QString& /*languageCode*/, const QString& /*externalDir*/) const { return NULL; } diff --git a/gui/NEMainpage.cpp b/gui/NEMainpage.cpp index 51f8a38..104e99d 100644 --- a/gui/NEMainpage.cpp +++ b/gui/NEMainpage.cpp @@ -42,8 +42,8 @@ NEMainpage::NEMainpage(QWidget *parent, RetroChessNotify *notify) : MainPage(parent), - mNotify(notify), - ui(new Ui::NEMainpage) + ui(new Ui::NEMainpage), + mNotify(notify) { ui->setupUi(this); setupMenuActions(); @@ -75,7 +75,7 @@ NEMainpage::~NEMainpage() void NEMainpage::chessStart(const RsPeerId &peer_id) { - create_chess_window(peer_id.toStdString(), 0); + create_chess_window(peer_id.toStdString(), 1); // Invited node plays Black (1) } // decode received message here @@ -137,7 +137,7 @@ void NEMainpage::NeMsgArrived(const RsPeerId &peer_id, QString str) { if (rsRetroChess->hasInviteTo(peer_id)) { - create_chess_window(peer_id.toStdString(), 1); + create_chess_window(peer_id.toStdString(), 0); // Inviter plays White (0) rsRetroChess->acceptedInvite(peer_id); } } @@ -201,7 +201,7 @@ void NEMainpage::on_inviteButton_clicked() if( fid != "") // selected a friend { //make_board(); - create_chess_window(fid, 1); + create_chess_window(fid, 0); // Inviter plays White (0) QVariantMap map; //map.insert("type", "chess_init"); diff --git a/gui/RetroChessChatWidgetHolder.cpp b/gui/RetroChessChatWidgetHolder.cpp index 29e7b8c..e8faa2d 100644 --- a/gui/RetroChessChatWidgetHolder.cpp +++ b/gui/RetroChessChatWidgetHolder.cpp @@ -32,23 +32,27 @@ #include #include +#include #define IMAGE_RetroChess ":/images/chess.png" RetroChessChatWidgetHolder::RetroChessChatWidgetHolder(ChatWidget *chatWidget, RetroChessNotify *notify) : QObject(), ChatWidgetHolder(chatWidget), mRetroChessNotify(notify) { + Q_INIT_RESOURCE(RetroChess_images); // <--- ASSURE LE CHARGEMENT DE L'ICONE + + RsDbg() << "CHESS: RetroChessChatWidgetHolder has been instantiated!" << std::endl; + QIcon icon ; icon.addPixmap(QPixmap(IMAGE_RetroChess)) ; - playChessButton = new QToolButton ; playChessButton->setIcon(icon) ; playChessButton->setToolTip(tr("Invite Friend to Chess")); playChessButton->setIconSize(QSize(28,28)) ; playChessButton->setAutoRaise(true) ; - mChatWidget->addChatBarWidget(playChessButton); + mChatWidget->addTitleBarWidget(playChessButton); // <--- PLACE LE BOUTON EN HAUT connect(playChessButton, SIGNAL(clicked()), this, SLOT(chessPressed())); connect(notify, SIGNAL(chessInvited(RsPeerId)), this, SLOT(chessnotify(RsPeerId))); @@ -90,6 +94,7 @@ void RetroChessChatWidgetHolder::chessnotify(RsPeerId from_peer_id) .append("font-size: 12pt; color: white;") .append("min-width: 128px; min-height: 24px;") .append("border-radius: 6px;") + .append("padding: 3px;") // <--- AJOUT DU PADDING .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " "stop: 0 #22c70d, stop: 1 #116a06);") @@ -132,6 +137,21 @@ void RetroChessChatWidgetHolder::chessStart() { RsPeerId peer_id = mChatWidget->getChatId().toPeerId();//TODO support GXSID + // Désactiver et détruire le bouton pour éviter d'ouvrir 2 fenêtres + RSButtonOnText *source = qobject_cast(QObject::sender()); + if (source) { + source->setEnabled(false); + button_map::iterator it = buttonMapTakeChess.begin(); + while (it != buttonMapTakeChess.end()) { + if (it.value() == source) { + it = buttonMapTakeChess.erase(it); + } else { + ++it; + } + } + source->deleteLater(); + } + rsRetroChess->acceptedInvite(peer_id); mRetroChessNotify->notifyChessStart(peer_id); return; @@ -146,6 +166,7 @@ void RetroChessChatWidgetHolder::botMouseEnter() .append("font-size: 12pt; color: white;") .append("min-width: 128px; min-height: 24px;") .append("border-radius: 6px;") + .append("padding: 3px;") // <--- AJOUT DU PADDING .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " "stop: 0 #444444, stop: 1 #222222);") @@ -163,6 +184,7 @@ void RetroChessChatWidgetHolder::botMouseLeave() .append("font-size: 12pt; color: white;") .append("min-width: 128px; min-height: 24px;") .append("border-radius: 6px;") + .append("padding: 3px;") // <--- AJOUT DU PADDING .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " "stop: 0 #22c70d, stop: 1 #116a06);") diff --git a/gui/chess.cpp b/gui/chess.cpp index 68277e0..ad928f2 100644 --- a/gui/chess.cpp +++ b/gui/chess.cpp @@ -68,17 +68,25 @@ RetroChessWindow::RetroChessWindow(std::string peerid, int player, QWidget *pare p1name = rsPeers->getPeerName(p1id); p2name = rsPeers->getPeerName(p2id); - QString title = QString::fromStdString(p2name); + // Correction du titre : Toujours "Local Playing Chess against Remote" + QString title = QString::fromStdString(rsPeers->getPeerName(rsPeers->getOwnId())); title += " Playing Chess against "; - title += QString::fromStdString(p1name); - title+=player_str; - + title += QString::fromStdString(rsPeers->getPeerName(RsPeerId(peerid))); this->setWindowTitle(title); this->initAccessories(); this->initChessBoard(); + // Si le joueur local joue les Noirs, on inverse les blocs d'information UI + // pour que ses informations soient en bas (comme son échiquier). + if (m_localplayer_turn == 0) { + m_ui->gridLayout_4->removeWidget(m_ui->frame); + m_ui->gridLayout_4->removeWidget(m_ui->frame_2); + m_ui->gridLayout_4->addWidget(m_ui->frame_2, 0, 0); // Les Blancs passent en haut + m_ui->gridLayout_4->addWidget(m_ui->frame, 5, 0); // Les Noirs passent en bas + } + this->playerTurnNotice(); } @@ -139,7 +147,7 @@ void RetroChessWindow::disOrange() } -void RetroChessWindow::validate_tile(int row, int col, int c) +void RetroChessWindow::validate_tile(int row, int col, int /*c*/) { Tile *clickedtile = tile[col][row]; //if (!click1)click1=clickedtile; @@ -152,7 +160,7 @@ void RetroChessWindow::initChessBoard() //QWidget *baseWidget, Tile *tile[8][8] QWidget *baseWidget = m_ui->m_chess_board; - int i,j,k = 0,hor,ver; + int i,j,k = 0; Border *border[4] = { NULL }; @@ -165,11 +173,8 @@ void RetroChessWindow::initChessBoard() } //Create 64 tiles (allocating memories to the objects of Tile class) - ver = 20; - for(i = 0; i < 8; i++) { - hor = 20; for(j=0; j<8; j++) { tile[i][j] = new Tile(baseWidget); @@ -180,12 +185,21 @@ void RetroChessWindow::initChessBoard() tile[i][j]->col=j; tile[i][j]->tileNum=k++; tile[i][j]->tileDisplay(); - tile[i][j]->setGeometry(hor,ver,64,64); - tile[i][j]->resize( 64, 64 ); - hor+=64; + // Flip the board visually if the local player plays Black (0) + int display_row = i; + int display_col = j; + if (m_localplayer_turn == 0) { + display_row = 7 - i; + display_col = 7 - j; + } + + int calc_hor = 20 + display_col * 64; + int calc_ver = 20 + display_row * 64; + + tile[i][j]->setGeometry(calc_hor, calc_ver, 64, 64); + tile[i][j]->resize( 64, 64 ); } - ver+=64; } //white pawns @@ -903,9 +917,8 @@ int RetroChessWindow::validateBishop(Tile *tile_p) // seems like "check" method is check "King"'s status in current situation. (alive or done) // for help player to make decition to keep "King" alive. -int RetroChessWindow::check(Tile *tile_p) +int RetroChessWindow::check(Tile * /*tile_p*/) { - int r,c,flag; retVal=0; return retVal; diff --git a/services/p3RetroChess.cc b/services/p3RetroChess.cc index 912ec51..16b5ae4 100644 --- a/services/p3RetroChess.cc +++ b/services/p3RetroChess.cc @@ -64,6 +64,7 @@ static double getCurrentTS() return cts; } +#if 0 static uint64_t convertTsTo64bits(double ts) { uint32_t secs = (uint32_t) ts; @@ -80,6 +81,7 @@ static double convert64bitsToTs(uint64_t bits) return ts; } +#endif p3RetroChess::p3RetroChess(RsPluginHandler *handler,RetroChessNotify *notifier) : RsPQIService(RS_SERVICE_TYPE_RetroChess_PLUGIN,0,handler), mRetroChessMtx("p3RetroChess"), mServiceControl(handler->getServiceControl()), mNotify(notifier) @@ -246,6 +248,7 @@ void p3RetroChess::msg_all(std::string msg) rsPeers->getOnlineList(onlineIds); double ts = getCurrentTS(); + (void) ts; #ifdef DEBUG_RetroChess std::cerr << "p3RetroChess::msg_all() @ts: " << ts; @@ -273,6 +276,7 @@ void p3RetroChess::broadcast_paint(int x, int y) rsPeers->getOnlineList(onlineIds); double ts = getCurrentTS(); + (void) ts; std::cout << "READY TO PAINT: " << onlineIds.size() << "\n"; @@ -384,6 +388,7 @@ bool p3RetroChess::loadList(std::list& load) assert(item!=NULL) ; #endif RsConfigKeyValueSet *vitem = dynamic_cast(*it) ; + (void) vitem; /* if(vitem != NULL) for(std::list::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit) diff --git a/services/rsRetroChessItems.h b/services/rsRetroChessItems.h index 1e4a563..1419f16 100644 --- a/services/rsRetroChessItems.h +++ b/services/rsRetroChessItems.h @@ -55,7 +55,10 @@ /**************************************************************************/ -const uint16_t RS_SERVICE_TYPE_RetroChess_PLUGIN = 0xc4e55; +// 0xc4e55 était trop grand pour un uint16_t et causait un warning. +// Le compilateur le tronquait silencieusement à 0x4e55. Pour garder la +// compatibilité réseau sans warning, on utilise directement la valeur tronquée. +const uint16_t RS_SERVICE_TYPE_RetroChess_PLUGIN = 0x4e55; const uint8_t RS_PKT_SUBTYPE_RetroChess_DATA = 0x01; From 848a0326bce83d2dd194bd81293e3878f42ff165 Mon Sep 17 00:00:00 2001 From: jolavillette Date: Sat, 2 May 2026 15:41:10 +0200 Subject: [PATCH 2/4] RetroChess: full GXS tunnel integration --- RetroChessPlugin.cpp | 37 +++- RetroChessPlugin.h | 3 + gui/NEMainpage.cpp | 6 +- gui/NEMainpage.h | 2 +- gui/RetroChessChatWidgetHolder.cpp | 181 ++++++++++------ gui/RetroChessChatWidgetHolder.h | 1 + gui/RetroChessNotify.cpp | 6 +- gui/RetroChessNotify.h | 9 +- gui/chess.cpp | 6 +- interface/rsRetroChess.h | 10 + services/p3RetroChess.cc | 335 ++++++++++++++++++++++++++++- services/p3RetroChess.h | 48 ++++- 12 files changed, 562 insertions(+), 82 deletions(-) diff --git a/RetroChessPlugin.cpp b/RetroChessPlugin.cpp index 3029b09..1d87164 100644 --- a/RetroChessPlugin.cpp +++ b/RetroChessPlugin.cpp @@ -83,6 +83,9 @@ RetroChessPlugin::RetroChessPlugin() mPeers = NULL; config_page = NULL ; mIcon = NULL ; + mGxsTunnels = NULL; + mIdentity = NULL; + mChats = NULL; mRetroChessNotify = new RetroChessNotify; } @@ -90,6 +93,21 @@ RetroChessPlugin::RetroChessPlugin() void RetroChessPlugin::setInterfaces(RsPlugInInterfaces &interfaces) { mPeers = interfaces.mPeers; + mGxsTunnels = interfaces.mGxsTunnels; + mIdentity = interfaces.mIdentity; + mChats = interfaces.mChats; + + RsDbg() << "CHESS: setInterfaces: mChats=" << (mChats?"OK":"NULL") << " mGxsTunnels=" << (mGxsTunnels?"OK":"NULL"); + + if(mRetroChess) + { + RsDbg() << "CHESS: Plugin calling service connections..."; + mRetroChess->connectToGxsTunnelService(mGxsTunnels); + RsDbg() << "CHESS: Calling connectToIdentityService"; + mRetroChess->connectToIdentityService(mIdentity); + RsDbg() << "CHESS: Calling connectToChatService"; + mRetroChess->connectToChatService(mChats); + } } /*ConfigPage *RetroChessPlugin::qt_config_page() const @@ -124,10 +142,10 @@ ChatWidgetHolder *RetroChessPlugin::qt_get_chat_widget_holder(ChatWidget *chatWi switch (chatWidget->chatType()) { case ChatWidget::CHATTYPE_PRIVATE: + case ChatWidget::CHATTYPE_DISTANT: return new RetroChessChatWidgetHolder(chatWidget, mRetroChessNotify); case ChatWidget::CHATTYPE_UNKNOWN: case ChatWidget::CHATTYPE_LOBBY: - case ChatWidget::CHATTYPE_DISTANT: break; } @@ -137,7 +155,24 @@ ChatWidgetHolder *RetroChessPlugin::qt_get_chat_widget_holder(ChatWidget *chatWi p3Service *RetroChessPlugin::p3_service() const { if(mRetroChess == NULL) + { rsRetroChess = mRetroChess = new p3RetroChess(mPlugInHandler,mRetroChessNotify) ; // , 3600 * 24 * 30 * 6); // 6 Months + if(mGxsTunnels) + { + RsDbg() << "CHESS: p3_service: calling connectToGxsTunnelService"; + mRetroChess->connectToGxsTunnelService(mGxsTunnels); + } + if(mIdentity) + { + RsDbg() << "CHESS: p3_service: calling connectToIdentityService"; + mRetroChess->connectToIdentityService(mIdentity); + } + if(mChats) + { + RsDbg() << "CHESS: p3_service: calling connectToChatService"; + mRetroChess->connectToChatService(mChats); + } + } return mRetroChess ; } diff --git a/RetroChessPlugin.h b/RetroChessPlugin.h index c2e6fee..5417423 100644 --- a/RetroChessPlugin.h +++ b/RetroChessPlugin.h @@ -75,6 +75,9 @@ class RetroChessPlugin: public RsPlugin mutable ConfigPage *config_page ; mutable QIcon *mIcon; mutable MainPage* mainpage ; + mutable RsGxsTunnelService *mGxsTunnels; + mutable RsIdentity *mIdentity; + mutable RsChats *mChats; RetroChessNotify *mRetroChessNotify ; RetroChessGUIHandler *mRetroChessGUIHandler ; diff --git a/gui/NEMainpage.cpp b/gui/NEMainpage.cpp index 104e99d..fcbf821 100644 --- a/gui/NEMainpage.cpp +++ b/gui/NEMainpage.cpp @@ -49,7 +49,7 @@ NEMainpage::NEMainpage(QWidget *parent, RetroChessNotify *notify) : setupMenuActions(); connect(mNotify, SIGNAL(NeMsgArrived(RsPeerId,QString)), this, SLOT(NeMsgArrived(RsPeerId,QString))); - connect(mNotify, SIGNAL(chessStart(RsPeerId)), this, SLOT(chessStart(RsPeerId))); + connect(mNotify, SIGNAL(chessStart(RsPeerId,int)), this, SLOT(chessStart(RsPeerId,int))); connect(ui->friendSelectionWidget, SIGNAL(itemSelectionChanged()), this, SLOT(friendSelectionChanged())); // enable/disable the invite button @@ -73,9 +73,9 @@ NEMainpage::~NEMainpage() delete ui; } -void NEMainpage::chessStart(const RsPeerId &peer_id) +void NEMainpage::chessStart(const RsPeerId &peer_id, int player_id) { - create_chess_window(peer_id.toStdString(), 1); // Invited node plays Black (1) + create_chess_window(peer_id.toStdString(), player_id); } // decode received message here diff --git a/gui/NEMainpage.h b/gui/NEMainpage.h index cf6d72f..b06f2aa 100644 --- a/gui/NEMainpage.h +++ b/gui/NEMainpage.h @@ -57,7 +57,7 @@ private slots: void setupMenuActions(); void friendSelectionChanged(); void NeMsgArrived(const RsPeerId &peer_id, QString str); - void chessStart(const RsPeerId &peer_id); + void chessStart(const RsPeerId &peer_id, int player_id); void on_broadcastButton_clicked(); diff --git a/gui/RetroChessChatWidgetHolder.cpp b/gui/RetroChessChatWidgetHolder.cpp index e8faa2d..cbdd012 100644 --- a/gui/RetroChessChatWidgetHolder.cpp +++ b/gui/RetroChessChatWidgetHolder.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "interface/rsRetroChess.h" @@ -52,10 +53,58 @@ RetroChessChatWidgetHolder::RetroChessChatWidgetHolder(ChatWidget *chatWidget, R playChessButton->setIconSize(QSize(28,28)) ; playChessButton->setAutoRaise(true) ; + ChatId chatId = mChatWidget->getChatId(); + RsDbg() << "CHESS: chessnotify for " << chatId.toStdString() + << " From: " << rsRetroChess->hasInviteFrom_chat(chatId) + << " To: " << rsRetroChess->hasInviteTo_chat(chatId); + + if (rsRetroChess->hasInviteFrom_chat(chatId)) + { + // On évite les popups en boucle + static ChatId lastInviteChatId; + if (lastInviteChatId.toStdString() != chatId.toStdString()) { + lastInviteChatId = chatId; + + QString buttonName = "Unknown GXS Friend"; + DistantChatPeerInfo info; + if (rsChats->getDistantChatStatus(chatId.toDistantChatId(), info)) { + buttonName = QString::fromUtf8(rsRetroChess->getGxsName(info.to_id).c_str()); + } + + // POPUP RADICALE pour garantir le clic + QMessageBox::StandardButton reply; + reply = QMessageBox::question(mChatWidget, tr("Chess Invitation"), + tr("%1 is inviting you to a game of Chess. Accept?").arg(buttonName), + QMessageBox::Yes|QMessageBox::No); + + if (reply == QMessageBox::Yes) { + RsDbg() << "CHESS: User accepted via popup"; + chessStart(); + } else { + RsDbg() << "CHESS: User rejected via popup"; + } + } + playChessButton->setEnabled(true); + } + else if (rsRetroChess->hasInviteTo_chat(chatId)) + { + RsDbg() << "CHESS: Button DISABLED (Waiting for opponent)"; + playChessButton->setEnabled(false); + playChessButton->setToolTip(tr("Waiting for oponent...")); + } + else + { + RsDbg() << "CHESS: Button ENABLED (Ready to play)"; + playChessButton->setEnabled(true); + playChessButton->setToolTip(tr("Play Chess")); + } + mChatWidget->addTitleBarWidget(playChessButton); // <--- PLACE LE BOUTON EN HAUT connect(playChessButton, SIGNAL(clicked()), this, SLOT(chessPressed())); connect(notify, SIGNAL(chessInvited(RsPeerId)), this, SLOT(chessnotify(RsPeerId))); + // Vérifier immédiatement s'il y a une invitation en attente à l'ouverture de la fenêtre + chessnotify(mChatWidget->getChatId().toPeerId()); } RetroChessChatWidgetHolder::~RetroChessChatWidgetHolder() @@ -70,64 +119,69 @@ RetroChessChatWidgetHolder::~RetroChessChatWidgetHolder() void RetroChessChatWidgetHolder::chessnotify(RsPeerId from_peer_id) { - RsPeerId peer_id = mChatWidget->getChatId().toPeerId();//TODO support GXSID - //if (peer_id!=from_peer_id)return;//invite from another chat - if (rsRetroChess->hasInviteFrom(peer_id)) + ChatId chatId = mChatWidget->getChatId(); + + if (rsRetroChess->hasInviteFrom_chat(chatId)) { - if (mChatWidget) - { - QString buttonName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str()); - if (buttonName.isEmpty()) buttonName = "Chess";//TODO maybe change all with GxsId - //disable old buttons - button_map::iterator it = buttonMapTakeChess.begin(); - while (it != buttonMapTakeChess.end()) - { - it = buttonMapTakeChess.erase(it); + // On évite les popups en boucle + static ChatId lastInviteChatId; + if (lastInviteChatId.toStdString() != chatId.toStdString()) { + lastInviteChatId = chatId; + + QString buttonName = "Unknown GXS Friend"; + DistantChatPeerInfo info; + if (rsChats->getDistantChatStatus(chatId.toDistantChatId(), info)) { + buttonName = QString::fromUtf8(rsRetroChess->getGxsName(info.to_id).c_str()); } - //button_map::iterator it = buttonMapTakeChess.find(buttonName); - //if (it == buttonMapTakeChess.end()){ - mChatWidget->addChatMsg(true, tr("Chess Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() - , tr("%1 inviting you to start Chess. Do you want to accept or decline the invitation?").arg(buttonName), ChatWidget::MSGTYPE_SYSTEM); - RSButtonOnText *button = mChatWidget->getNewButtonOnTextBrowser(tr("Accept")); - button->setToolTip(tr("Accept")); - button->setStyleSheet(QString("border: 1px solid #199909;") - .append("font-size: 12pt; color: white;") - .append("min-width: 128px; min-height: 24px;") - .append("border-radius: 6px;") - .append("padding: 3px;") // <--- AJOUT DU PADDING - .append("background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 0.67, " - "stop: 0 #22c70d, stop: 1 #116a06);") - - ); - - button->updateImage(); - - connect(button,SIGNAL(clicked()),this,SLOT(chessStart())); - connect(button,SIGNAL(mouseEnter()),this,SLOT(botMouseEnter())); - connect(button,SIGNAL(mouseLeave()),this,SLOT(botMouseLeave())); - - buttonMapTakeChess.insert(buttonName, button); - //} - } - + RsDbg() << "CHESS: Showing popup for " << buttonName.toStdString(); + // POPUP RADICALE pour garantir le clic + QMessageBox::StandardButton reply; + reply = QMessageBox::question(mChatWidget, tr("Chess Invitation"), + tr("%1 is inviting you to a game of Chess. Accept?").arg(buttonName), + QMessageBox::Yes|QMessageBox::No); + + if (reply == QMessageBox::Yes) { + RsDbg() << "CHESS: User accepted via popup"; + chessStart(); + } else { + RsDbg() << "CHESS: User rejected via popup"; + } + } + playChessButton->setEnabled(true); + } + else if (rsRetroChess->hasInviteTo_chat(chatId)) + { + RsDbg() << "CHESS: Button DISABLED (Waiting for opponent)"; + playChessButton->setEnabled(false); + playChessButton->setToolTip(tr("Waiting for oponent...")); + } + else + { + RsDbg() << "CHESS: Button ENABLED (Ready to play)"; + playChessButton->setEnabled(true); + playChessButton->setToolTip(tr("Play Chess")); } } void RetroChessChatWidgetHolder::chessPressed() { - RsPeerId peer_id = mChatWidget->getChatId().toPeerId();//TODO support GXSID - if (rsRetroChess->hasInviteFrom(peer_id)) - { + ChatId chatId = mChatWidget->getChatId(); + RsDbg() << "CHESS: chessPressed() for chatId: " << chatId.toStdString(); - rsRetroChess->acceptedInvite(peer_id); - mRetroChessNotify->notifyChessStart(peer_id); + if (rsRetroChess->hasInviteFrom_chat(chatId)) + { + rsRetroChess->acceptedInvite_chat(chatId); + // Note: we might need to handle RsPeerId vs RsGxsId in notification + mRetroChessNotify->notifyChessStart(chatId.toPeerId(), 1); // Accept = Guest (1) return; - } - rsRetroChess->sendInvite(peer_id); + rsRetroChess->sendInvite_chat(chatId); + + QString peerName = chatId.isPeerId() ? + QString::fromUtf8(rsPeers->getPeerName(chatId.toPeerId()).c_str()) : + tr("GXS Friend"); - QString peerName = QString::fromUtf8(rsPeers->getPeerName(peer_id).c_str()); mChatWidget->addChatMsg(true, tr("Chess Status"), QDateTime::currentDateTime(), QDateTime::currentDateTime() , tr("You're now inviting %1 to play Chess").arg(peerName), ChatWidget::MSGTYPE_SYSTEM); @@ -135,26 +189,27 @@ void RetroChessChatWidgetHolder::chessPressed() void RetroChessChatWidgetHolder::chessStart() { - RsPeerId peer_id = mChatWidget->getChatId().toPeerId();//TODO support GXSID - - // Désactiver et détruire le bouton pour éviter d'ouvrir 2 fenêtres - RSButtonOnText *source = qobject_cast(QObject::sender()); - if (source) { - source->setEnabled(false); - button_map::iterator it = buttonMapTakeChess.begin(); - while (it != buttonMapTakeChess.end()) { - if (it.value() == source) { - it = buttonMapTakeChess.erase(it); - } else { - ++it; - } + RsDbg() << "CHESS: UI Accept button clicked!"; + ChatId chatId = mChatWidget->getChatId(); + RsPeerId targetId = chatId.toPeerId(); + + if (chatId.isDistantChatId()) { + RsDbg() << "CHESS: Handling GXS invite for " << chatId.toStdString(); + DistantChatPeerInfo info; + if (rsChats->getDistantChatStatus(chatId.toDistantChatId(), info)) { + targetId = RsPeerId(info.to_id.toStdString()); + RsDbg() << "CHESS: Using pseudo-ID for GXS start: " << targetId; } - source->deleteLater(); } - rsRetroChess->acceptedInvite(peer_id); - mRetroChessNotify->notifyChessStart(peer_id); - return; + rsRetroChess->acceptedInvite_chat(chatId); + mRetroChessNotify->notifyChessStart(targetId, 1); // Accept = Guest (1) +} + +void RetroChessChatWidgetHolder::chessReject() +{ + RsDbg() << "CHESS: UI Reject button clicked!"; + // Pour l'instant on se contente de logger, on pourra ajouter rsRetroChess->rejectInvite_chat plus tard } void RetroChessChatWidgetHolder::botMouseEnter() diff --git a/gui/RetroChessChatWidgetHolder.h b/gui/RetroChessChatWidgetHolder.h index 958ba88..fcebcd6 100644 --- a/gui/RetroChessChatWidgetHolder.h +++ b/gui/RetroChessChatWidgetHolder.h @@ -38,6 +38,7 @@ public slots: void chessPressed(); void chessStart(); void chessnotify(RsPeerId from_peer_id); + void chessReject(); private slots: diff --git a/gui/RetroChessNotify.cpp b/gui/RetroChessNotify.cpp index 8b2fb5a..d866c48 100644 --- a/gui/RetroChessNotify.cpp +++ b/gui/RetroChessNotify.cpp @@ -41,11 +41,11 @@ void RetroChessNotify::notifyReceivedMsg(const RsPeerId& peer_id, QString str) emit NeMsgArrived(peer_id, str) ; } -void RetroChessNotify::notifyChessStart(const RsPeerId &peer_id) +void RetroChessNotify::notifyChessStart(const RsPeerId &peer_id, int player_id) { - emit chessStart(peer_id) ; - + emit chessStart(peer_id, player_id) ; } + void RetroChessNotify::notifyChessInvite(const RsPeerId &peer_id) { emit chessInvited(peer_id) ; diff --git a/gui/RetroChessNotify.h b/gui/RetroChessNotify.h index 4fdd0fa..f35e3a4 100644 --- a/gui/RetroChessNotify.h +++ b/gui/RetroChessNotify.h @@ -38,14 +38,13 @@ class RetroChessNotify : public QObject explicit RetroChessNotify(QObject *parent = 0); void notifyReceivedPaint(const RsPeerId &peer_id, int x, int y) ; void notifyReceivedMsg(const RsPeerId &peer_id, QString str) ; - void notifyChessStart(const RsPeerId &peer_id) ; + void notifyChessStart(const RsPeerId &peer_id, int player_id); void notifyChessInvite(const RsPeerId &peer_id) ; signals: - void NeMsgArrived(const RsPeerId &peer_id, QString str) ; // emitted when the peer gets a msg - - void chessStart(const RsPeerId &peer_id) ; - void chessInvited(const RsPeerId &peer_id) ; + void NeMsgArrived(RsPeerId peer_id, QString str); + void chessStart(RsPeerId peer_id, int player_id); + void chessInvited(RsPeerId peer_id); public slots: }; diff --git a/gui/chess.cpp b/gui/chess.cpp index ad928f2..79bb2ed 100644 --- a/gui/chess.cpp +++ b/gui/chess.cpp @@ -65,13 +65,13 @@ RetroChessWindow::RetroChessWindow(std::string peerid, int player, QWidget *pare m_localplayer_turn = 1; } - p1name = rsPeers->getPeerName(p1id); - p2name = rsPeers->getPeerName(p2id); + p1name = rsRetroChess->getPeerName(p1id); + p2name = rsRetroChess->getPeerName(p2id); // Correction du titre : Toujours "Local Playing Chess against Remote" QString title = QString::fromStdString(rsPeers->getPeerName(rsPeers->getOwnId())); title += " Playing Chess against "; - title += QString::fromStdString(rsPeers->getPeerName(RsPeerId(peerid))); + title += QString::fromStdString(rsRetroChess->getPeerName(RsPeerId(peerid))); this->setWindowTitle(title); diff --git a/interface/rsRetroChess.h b/interface/rsRetroChess.h index 3e715d7..861c259 100644 --- a/interface/rsRetroChess.h +++ b/interface/rsRetroChess.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,15 @@ class RsRetroChess virtual void acceptedInvite(RsPeerId peerID) = 0; virtual void gotInvite(RsPeerId peerID) = 0; virtual void sendInvite(RsPeerId peerID) = 0; + + virtual void chess_click_chat(const ChatId& chatId, int col, int row, int count) = 0; + virtual void player_leave_chat(const ChatId& chatId) = 0; + virtual void sendInvite_chat(const ChatId& chatId) = 0; + virtual void acceptedInvite_chat(const ChatId& chatId) = 0; + virtual bool hasInviteFrom_chat(const ChatId& chatId) = 0; + virtual bool hasInviteTo_chat(const ChatId& chatId) = 0; + virtual std::string getPeerName(const RsPeerId& id) = 0; + virtual std::string getGxsName(const RsGxsId& id) = 0; }; diff --git a/services/p3RetroChess.cc b/services/p3RetroChess.cc index 16b5ae4..9cc7266 100644 --- a/services/p3RetroChess.cc +++ b/services/p3RetroChess.cc @@ -34,6 +34,7 @@ #include #include "gui/RetroChessNotify.h" +#include "util/rsdebug.h" //#define DEBUG_RetroChess 1 @@ -84,8 +85,9 @@ static double convert64bitsToTs(uint64_t bits) #endif p3RetroChess::p3RetroChess(RsPluginHandler *handler,RetroChessNotify *notifier) - : RsPQIService(RS_SERVICE_TYPE_RetroChess_PLUGIN,0,handler), mRetroChessMtx("p3RetroChess"), mServiceControl(handler->getServiceControl()), mNotify(notifier) + : RsPQIService(RS_SERVICE_TYPE_RetroChess_PLUGIN,0,handler), mRetroChessMtx("p3RetroChess"), mServiceControl(handler->getServiceControl()), mNotify(notifier), mGxsTunnels(NULL), mIdentity(NULL), mChats(NULL) { + RsDbg() << "CHESS: Initializing GXS Tunnel Client Service interface."; addSerialType(new RsRetroChessSerialiser()); @@ -215,6 +217,26 @@ void p3RetroChess::sendInvite(RsPeerId peerID) }*/ void p3RetroChess::raw_msg_peer(RsPeerId peerID, std::string msg) { + { + RsStackMutex stack(mRetroChessMtx); + if (mPseudoToRealGxsMap.count(peerID)) { + RsDbg() << "CHESS: Routing move via GXS tunnel for " << peerID; + RsGxsId targetGxsId = mPseudoToRealGxsMap[peerID]; + if (mTargetGxsToTunnelMap.count(targetGxsId)) { + RsGxsTunnelId tunnelId = mTargetGxsToTunnelMap[targetGxsId]; + RsGxsTunnelService::GxsTunnelInfo info; + if (mGxsTunnels->getTunnelInfo(tunnelId, info)) { + RsDbg() << "CHESS: Routing via tunnel " << tunnelId << " with real source " << info.source_gxs_id << " and target " << info.destination_gxs_id; + raw_msg_gxs(info.destination_gxs_id, info.source_gxs_id, msg); + return; + } + } + RsWarn() << "CHESS: Tunnel NOT FOUND for GXS " << targetGxsId; + RsWarn() << "CHESS: Could not find tunnel for pseudo-peer " << peerID; + return; + } + } + std::cout << "MSging: " << peerID.toStdString() << "\n"; std::cout << "MSging: " << msg << "\n"; /* create the packet */ @@ -422,3 +444,314 @@ RsSerialiser *p3RetroChess::setupSerialiser() return rsSerialiser ; } + +void p3RetroChess::raw_msg_gxs(const RsGxsId& targetId, const RsGxsId& sourceId, const std::string& msg) +{ + RsDbg() << "CHESS: Entering raw_msg_gxs (mutex should be locked). Target=" << targetId << " Source=" << sourceId; + // Suppression du lock ici pour éviter le deadlock si appelé depuis sendInvite_chat ou msg_chat + // RsStackMutex stack(mRetroChessMtx); + + if (!mGxsTunnels) { + RsErr() << "CHESS: mGxsTunnels is NULL, cannot send GXS message."; + return; + } + + TunnelKey key = { sourceId, targetId }; + + if (mGxsToTunnelMap.find(key) == mGxsToTunnelMap.end()) { + RsGxsTunnelId tunnelId; + uint32_t error_code = 0; + RsDbg() << "CHESS: Requesting tunnel from " << sourceId << " to " << targetId; + if (mGxsTunnels->requestSecuredTunnel(targetId, sourceId, tunnelId, RS_SERVICE_TYPE_RetroChess_PLUGIN, error_code)) { + mGxsToTunnelMap[key] = tunnelId; + mTargetGxsToTunnelMap[targetId] = tunnelId; + mTunnelToPeerGxsIdMap[tunnelId] = targetId; + RsDbg() << "CHESS: Tunnel requested successfully: " << tunnelId; + } else { + RsErr() << "CHESS: Failed to request tunnel, error=" << error_code; + return; + } + } + + RsGxsTunnelId tunnelId = mGxsToTunnelMap[key]; + RsGxsTunnelService::GxsTunnelInfo info; + if (mGxsTunnels->getTunnelInfo(tunnelId, info) && info.tunnel_status == RsGxsTunnelService::RS_GXS_TUNNEL_STATUS_CAN_TALK) { + RsDbg() << "CHESS: Tunnel is ready, sending data (" << msg.size() << " bytes)."; + mGxsTunnels->sendData(tunnelId, RS_SERVICE_TYPE_RetroChess_PLUGIN, (const uint8_t*)msg.c_str(), msg.size()); + } else { + RsDbg() << "CHESS: Tunnel not ready (status=" << (mGxsTunnels->getTunnelInfo(tunnelId, info) ? info.tunnel_status : 0) << "), queuing message."; + mPendingTunnelMessages[tunnelId].push_back(msg); + } +} + +void p3RetroChess::notifyTunnelStatus(const RsGxsTunnelId& tunnel_id, uint32_t tunnel_status) +{ + RsDbg() << "CHESS: notifyTunnelStatus: tunnel=" << tunnel_id << ", status=" << tunnel_status; + + RsStackMutex stack(mRetroChessMtx); + if (tunnel_status == RsGxsTunnelService::RS_GXS_TUNNEL_STATUS_CAN_TALK) { + std::list& pending = mPendingTunnelMessages[tunnel_id]; + if (!pending.empty()) { + RsDbg() << "CHESS: Tunnel CAN_TALK, flushing " << pending.size() << " pending messages."; + for (const std::string& msg : pending) { + mGxsTunnels->sendData(tunnel_id, RS_SERVICE_TYPE_RetroChess_PLUGIN, (const uint8_t*)msg.c_str(), msg.size()); + } + pending.clear(); + } + } +} + +void p3RetroChess::receiveData(const RsGxsTunnelId& tunnel_id, unsigned char *data, uint32_t data_size) +{ + RsDbg() << "CHESS: receiveData: tunnel=" << tunnel_id << ", size=" << data_size; + + std::string msg((const char*)data, data_size); + RsDbg() << "CHESS: Received message via tunnel: " << msg; + + RsGxsId peerGxsId; + RsPeerId pseudoPeerId; + bool tunnelFound = false; + + { + RsStackMutex stack(mRetroChessMtx); + if (mTunnelToPeerGxsIdMap.find(tunnel_id) != mTunnelToPeerGxsIdMap.end()) { + peerGxsId = mTunnelToPeerGxsIdMap[tunnel_id]; + pseudoPeerId = RsPeerId(peerGxsId.toStdString()); + tunnelFound = true; + } + } + + if (tunnelFound) { + // Décodage JSON pour déclencher les bons signaux + QJsonDocument jsondoc = QJsonDocument::fromJson(QByteArray::fromStdString(msg)); + QVariantMap map = jsondoc.toVariant().toMap(); + QString type = map.value("type").toString(); + + if (type == "chess_invite") { + RsDbg() << "CHESS: Handling incoming invitation from GXS " << peerGxsId; + { + RsStackMutex stack(mRetroChessMtx); + gxsInvitesFrom.insert(peerGxsId); + mPseudoToNameMap[pseudoPeerId] = getGxsName(peerGxsId); + mPseudoToRealGxsMap[pseudoPeerId] = peerGxsId; + RsDbg() << "CHESS: Mapped pseudo " << pseudoPeerId << " to name " << mPseudoToNameMap[pseudoPeerId]; + } + mNotify->notifyChessInvite(pseudoPeerId); + } else if (type == "chess_accept") { + RsDbg() << "CHESS: Handling incoming acceptance from GXS " << peerGxsId; + { + RsStackMutex stack(mRetroChessMtx); + gxsInvitesTo.erase(peerGxsId); + mPseudoToNameMap[pseudoPeerId] = getGxsName(peerGxsId); + mPseudoToRealGxsMap[pseudoPeerId] = peerGxsId; + RsDbg() << "CHESS: Mapped pseudo " << pseudoPeerId << " to name " << mPseudoToNameMap[pseudoPeerId]; + } + mNotify->notifyChessStart(pseudoPeerId, 0); // Inviteur = Blanc (0) + } else { + // Pour les autres messages (coups, etc.), on utilise la méthode générique + mNotify->notifyReceivedMsg(pseudoPeerId, QString::fromStdString(msg)); + } + } else { + RsWarn() << "CHESS: Received data for unknown tunnel " << tunnel_id; + } + + // Important: RetroShare tunnel service transfers ownership of 'data', we must free it. + free(data); +} + +void p3RetroChess::connectToGxsTunnelService(RsGxsTunnelService *tunnel_service) +{ + RsDbg() << "CHESS: connectToGxsTunnelService: " << (tunnel_service ? "valid pointer" : "NULL"); + mGxsTunnels = tunnel_service; + + if(mGxsTunnels) + { + RsDbg() << "CHESS: Registering RetroChess as GXS Tunnel client (Service ID: " << RS_SERVICE_TYPE_RetroChess_PLUGIN << ")"; + if(!mGxsTunnels->registerClientService(RS_SERVICE_TYPE_RetroChess_PLUGIN, this)) + { + RsErr() << "CHESS: Failed to register RetroChess GXS Tunnel client!"; + } + } +} + +bool p3RetroChess::acceptDataFromPeer(const RsGxsId& gxs_id, const RsGxsTunnelId& tunnel_id, bool am_I_client_side) +{ + RsDbg() << "CHESS: acceptDataFromPeer: id=" << gxs_id << ", tunnel=" << tunnel_id << ", side=" << (am_I_client_side ? "client" : "server"); + + RsStackMutex stack(mRetroChessMtx); + mTunnelToPeerGxsIdMap[tunnel_id] = gxs_id; + + return true; +} + +void p3RetroChess::connectToIdentityService(RsIdentity *identity_service) +{ + RsDbg() << "CHESS: connectToIdentityService: " << (identity_service ? "valid pointer" : "NULL"); + mIdentity = identity_service; +} + +void p3RetroChess::connectToChatService(RsChats *chat_service) +{ + RsDbg() << "CHESS: connectToChatService: " << (chat_service ? "valid pointer" : "NULL"); + mChats = chat_service; +} + +void p3RetroChess::msg_chat(const ChatId& chatId, const std::string& msg) +{ + RsDbg() << "CHESS: msg_chat for chatId: " << chatId.toStdString(); + RsChats *chats = mChats ? mChats : rsChats; + + RsStackMutex stack(mRetroChessMtx); // On verrouille ici pour toute l'opération + if (chatId.isPeerId()) { + RsDbg() << "CHESS: msg_chat identified as PeerId"; + raw_msg_peer(chatId.toPeerId(), msg); + } else if (chatId.isDistantChatId()) { + RsDbg() << "CHESS: msg_chat identified as DistantChatId (using " << (mChats?"mChats":"rsChats") << ")"; + if (!chats) { + RsErr() << "CHESS: No chat service available, cannot send GXS message."; + return; + } + DistantChatPeerInfo info; + if (chats->getDistantChatStatus(chatId.toDistantChatId(), info)) { + RsDbg() << "CHESS: Found distant chat status: from=" << info.own_id << " to=" << info.to_id; + raw_msg_gxs(info.to_id, info.own_id, msg); + } else { + RsErr() << "CHESS: Could not get distant chat status for " << chatId.toStdString(); + } + } else { + RsWarn() << "CHESS: msg_chat: unknown ChatId type for " << chatId.toStdString(); + } +} + +void p3RetroChess::chess_click_chat(const ChatId& chatId, int col, int row, int count) +{ + QVariantMap map; + map.insert("type", "chessclick"); + map.insert("col", col); + map.insert("row", row); + map.insert("count", count); + + QJsonDocument jsondoc = QJsonDocument::fromVariant(map); + std::string msg = jsondoc.toJson().toStdString(); + msg_chat(chatId, msg); +} + +void p3RetroChess::player_leave_chat(const ChatId& chatId) +{ + std::string msg = "{\"type\":\"player_status_message\",\"player_status\":\"leave\"}"; + msg_chat(chatId, msg); +} + +void p3RetroChess::sendInvite_chat(const ChatId& chatId) +{ + RsDbg() << "CHESS: sendInvite_chat for: " << chatId.toStdString(); + RsChats *chats = mChats ? mChats : rsChats; + + if (chatId.isPeerId()) { + RsDbg() << "CHESS: Identified as PeerId"; + sendInvite(chatId.toPeerId()); + } else if (chatId.isDistantChatId()) { + RsDbg() << "CHESS: Identified as DistantChatId (using " << (mChats?"mChats":"rsChats") << ")"; + DistantChatPeerInfo info; + if (chats && chats->getDistantChatStatus(chatId.toDistantChatId(), info)) { + RsPeerId pseudoPeerId(info.to_id.toStdString()); + + { + RsStackMutex stack(mRetroChessMtx); + gxsInvitesTo.insert(info.to_id); + mPseudoToRealGxsMap[pseudoPeerId] = info.to_id; + mPseudoToNameMap[pseudoPeerId] = getGxsName(info.to_id); + RsDbg() << "CHESS: Sending invite to GXS " << info.to_id << " (pseudo=" << pseudoPeerId << ")"; + } + raw_msg_gxs(info.to_id, info.own_id, "{\"type\":\"chess_invite\"}"); + } else { + RsWarn() << "CHESS: Failed to get distant chat status for " << chatId.toStdString() << " (chats=" << (chats?"OK":"NULL") << ")"; + } + } else { + RsWarn() << "CHESS: sendInvite_chat: unknown ID type for " << chatId.toStdString(); + } +} + +void p3RetroChess::acceptedInvite_chat(const ChatId& chatId) +{ + RsDbg() << "CHESS: acceptedInvite_chat for: " << chatId.toStdString(); + RsChats *chats = mChats ? mChats : rsChats; + + if (chatId.isPeerId()) { + acceptedInvite(chatId.toPeerId()); + } else if (chatId.isDistantChatId()) { + DistantChatPeerInfo info; + if (chats && chats->getDistantChatStatus(chatId.toDistantChatId(), info)) { + RsPeerId pseudoPeerId(info.to_id.toStdString()); + + { + RsStackMutex stack(mRetroChessMtx); + gxsInvitesTo.erase(info.to_id); + gxsInvitesFrom.erase(info.to_id); + + // On mémorise le nom et l'ID réel avant d'ouvrir la fenêtre + mPseudoToNameMap[pseudoPeerId] = getGxsName(info.to_id); + mPseudoToRealGxsMap[pseudoPeerId] = info.to_id; + RsDbg() << "CHESS: Mapped pseudo " << pseudoPeerId << " to name " << mPseudoToNameMap[pseudoPeerId]; + } + + raw_msg_gxs(info.to_id, info.own_id, "{\"type\":\"chess_accept\"}"); + + // On ne notifie plus ici, c'est l'UI qui le fait pour éviter le double échiquier + // mNotify->notifyChessStart(pseudoPeerId, 1); + } + } +} + +std::string p3RetroChess::getGxsName(const RsGxsId& gxs_id) +{ + if (mIdentity) { + RsIdentityDetails details; + if (mIdentity->getIdDetails(gxs_id, details)) { + return details.mNickname; + } + } + return "GXS Friend"; +} + +std::string p3RetroChess::getPeerName(const RsPeerId& id) +{ + RsStackMutex stack(mRetroChessMtx); + RsDbg() << "CHESS: getPeerName lookup for: " << id; + if (mPseudoToNameMap.count(id)) { + RsDbg() << "CHESS: Found name in pseudo map: " << mPseudoToNameMap[id]; + return mPseudoToNameMap[id]; + } + return rsPeers->getPeerName(id); +} + +bool p3RetroChess::hasInviteFrom_chat(const ChatId& chatId) +{ + RsChats *chats = mChats ? mChats : rsChats; + if (chatId.isPeerId()) { + return hasInviteFrom(chatId.toPeerId()); + } else if (chatId.isDistantChatId()) { + DistantChatPeerInfo info; + if (chats && chats->getDistantChatStatus(chatId.toDistantChatId(), info)) { + RsStackMutex stack(mRetroChessMtx); + return gxsInvitesFrom.find(info.to_id) != gxsInvitesFrom.end(); + } + } + return false; +} + +bool p3RetroChess::hasInviteTo_chat(const ChatId& chatId) +{ + RsChats *chats = mChats ? mChats : rsChats; + if (chatId.isPeerId()) { + return hasInviteTo(chatId.toPeerId()); + } else if (chatId.isDistantChatId()) { + DistantChatPeerInfo info; + if (chats && chats->getDistantChatStatus(chatId.toDistantChatId(), info)) { + RsStackMutex stack(mRetroChessMtx); + return gxsInvitesTo.find(info.to_id) != gxsInvitesTo.end(); + } + } + return false; +} + diff --git a/services/p3RetroChess.h b/services/p3RetroChess.h index 2ff1387..31ae6c0 100644 --- a/services/p3RetroChess.h +++ b/services/p3RetroChess.h @@ -31,6 +31,8 @@ #include "rsitems/rsconfigitems.h" #include "plugins/rspqiservice.h" #include +#include "retroshare/rsgxstunnel.h" +#include "retroshare/rsidentity.h" class p3LinkMgr; class RetroChessNotify ; @@ -43,7 +45,7 @@ class RetroChessNotify ; * This is only used to test Latency for the moment. */ -class p3RetroChess: public RsPQIService, public RsRetroChess +class p3RetroChess: public RsPQIService, public RsRetroChess, public RsGxsTunnelService::RsGxsTunnelClientService // Maybe we inherit from these later - but not needed for now. //, public p3Config, public pqiMonitor { @@ -84,12 +86,24 @@ class p3RetroChess: public RsPQIService, public RsRetroChess virtual RsServiceInfo getServiceInfo() ; + /***** overloaded from RsGxsTunnelClientService *****/ + virtual void notifyTunnelStatus(const RsGxsTunnelId& tunnel_id, uint32_t tunnel_status) override; + virtual void receiveData(const RsGxsTunnelId& id, unsigned char *data, uint32_t data_size) override; + virtual void connectToGxsTunnelService(RsGxsTunnelService *tunnel_service) override; + virtual bool acceptDataFromPeer(const RsGxsId& gxs_id, const RsGxsTunnelId& tunnel_id, bool am_I_client_side) override; + + void connectToIdentityService(RsIdentity *identity_service); + void connectToChatService(RsChats *chat_service); + virtual std::string getPeerName(const RsPeerId& id) override; + virtual std::string getGxsName(const RsGxsId& gxs_id) override; + void ping_all(); void broadcast_paint(int x, int y); void msg_all(std::string msg); void str_msg_peer(RsPeerId peerID, QString strdata); void raw_msg_peer(RsPeerId peerID, std::string msg); + void raw_msg_gxs(const RsGxsId& targetId, const RsGxsId& sourceId, const std::string& msg); void qvm_msg_peer(RsPeerId peerID, QVariantMap data); void chess_click(std::string peer_id, int col, int row, int count); @@ -100,13 +114,23 @@ class p3RetroChess: public RsPQIService, public RsRetroChess bool hasInviteTo(RsPeerId peerID); void gotInvite(RsPeerId peerID); void acceptedInvite(RsPeerId peerID); - void sendInvite(RsPeerId peerID); + virtual void sendInvite(RsPeerId peerID) override; + + virtual void chess_click_chat(const ChatId& chatId, int col, int row, int count) override; + virtual void player_leave_chat(const ChatId& chatId) override; + virtual void sendInvite_chat(const ChatId& chatId) override; + virtual void acceptedInvite_chat(const ChatId& chatId) override; + virtual bool hasInviteFrom_chat(const ChatId& chatId) override; + virtual bool hasInviteTo_chat(const ChatId& chatId) override; private: std::set invitesTo; std::set invitesFrom; + std::set gxsInvitesTo; + std::set gxsInvitesFrom; void handleData(RsRetroChessDataItem*) ; + void msg_chat(const ChatId& chatId, const std::string& msg); RsMutex mRetroChessMtx; @@ -114,10 +138,30 @@ class p3RetroChess: public RsPQIService, public RsRetroChess static RsTlvKeyValue push_int_value(const std::string& key,int value) ; + + struct TunnelKey { + RsGxsId toId; + RsGxsId ownId; + bool operator<(const TunnelKey& other) const { + if (toId != other.toId) return toId < other.toId; + return ownId < other.ownId; + } + }; + + std::map mGxsToTunnelMap; + std::map mTargetGxsToTunnelMap; + std::map mTunnelToPeerGxsIdMap; + std::map> mPendingTunnelMessages; + std::map mPseudoToNameMap; + std::map mPseudoToRealGxsMap; static int pop_int_value(const std::string& s) ; RsServiceControl *mServiceControl; RetroChessNotify *mNotify ; + RsGxsTunnelService *mGxsTunnels; + RsIdentity *mIdentity; + RsChats *mChats; + }; From bb850b336a596a0e036c874e3045efd0f785adfc Mon Sep 17 00:00:00 2001 From: jolavillette Date: Sun, 3 May 2026 09:57:27 +0200 Subject: [PATCH 3/4] RetroChess: use gxsid avatars --- gui/NEMainpage.cpp | 4 +- gui/chess.cpp | 83 ++++++++++++++++++++++------------------ interface/rsRetroChess.h | 4 ++ services/p3RetroChess.cc | 71 ++++++++++++++++++++++++++++++++++ services/p3RetroChess.h | 4 ++ 5 files changed, 126 insertions(+), 40 deletions(-) diff --git a/gui/NEMainpage.cpp b/gui/NEMainpage.cpp index fcbf821..3561ecb 100644 --- a/gui/NEMainpage.cpp +++ b/gui/NEMainpage.cpp @@ -137,7 +137,7 @@ void NEMainpage::NeMsgArrived(const RsPeerId &peer_id, QString str) { if (rsRetroChess->hasInviteTo(peer_id)) { - create_chess_window(peer_id.toStdString(), 0); // Inviter plays White (0) + create_chess_window(peer_id.toStdString(), 1); // Guest plays Black (1) rsRetroChess->acceptedInvite(peer_id); } } @@ -255,7 +255,7 @@ void NEMainpage::on_filterPeersButton_clicked() // get friend 's avatar QPixmap friend_avatar; - AvatarDefs::getAvatarFromSslId( id, friend_avatar); + rsRetroChess->getAvatar(id, friend_avatar); rsServiceControl->getServicesAllowed (*it, local_service_perms) ; rsServiceControl->getServicesProvided(*it,remote_service_perms) ; diff --git a/gui/chess.cpp b/gui/chess.cpp index 79bb2ed..4064e7b 100644 --- a/gui/chess.cpp +++ b/gui/chess.cpp @@ -47,27 +47,34 @@ RetroChessWindow::RetroChessWindow(std::string peerid, int player, QWidget *pare setGeometry(0,0,1370,700); - QString player_str; + QString player_str; p1id = RsPeerId(peerid); // Initial guess: Player 1 (Top) = Remote + p2id = rsRetroChess->getOwnId(p1id); // Initial guess: Player 2 (Bottom) = Local + + // CRITICAL CHECK: If Player 1 is actually US, swap them! + if (rsRetroChess->isLocalId(p1id)) { + std::swap(p1id, p2id); + } + + p1name = rsRetroChess->getPeerName(p1id); + p2name = rsRetroChess->getPeerName(p2id); + + RsDbg() << "CHESS: Final Assignment - TOP: " << p1name << " BOTTOM: " << p2name; + if (player ) // local player as black { - p1id = rsPeers->getOwnId(); - p2id = RsPeerId(peerid); player_str = " (1)"; - m_localplayer_turn = 0; + m_ui->m_black_title->setText(tr("White (Opponent):")); // Top label + m_ui->m_white_title->setText(tr("Black (You):")); // Bottom label } else // local player as white { - p1id = RsPeerId(peerid); - p2id = rsPeers->getOwnId(); player_str = " (2)"; - m_localplayer_turn = 1; + m_ui->m_black_title->setText(tr("Black (Opponent):")); // Top label + m_ui->m_white_title->setText(tr("White (You):")); // Bottom label } - p1name = rsRetroChess->getPeerName(p1id); - p2name = rsRetroChess->getPeerName(p2id); - // Correction du titre : Toujours "Local Playing Chess against Remote" QString title = QString::fromStdString(rsPeers->getPeerName(rsPeers->getOwnId())); title += " Playing Chess against "; @@ -75,18 +82,10 @@ RetroChessWindow::RetroChessWindow(std::string peerid, int player, QWidget *pare this->setWindowTitle(title); + this->mPeerId = peerid; this->initAccessories(); this->initChessBoard(); - // Si le joueur local joue les Noirs, on inverse les blocs d'information UI - // pour que ses informations soient en bas (comme son échiquier). - if (m_localplayer_turn == 0) { - m_ui->gridLayout_4->removeWidget(m_ui->frame); - m_ui->gridLayout_4->removeWidget(m_ui->frame_2); - m_ui->gridLayout_4->addWidget(m_ui->frame_2, 0, 0); // Les Blancs passent en haut - m_ui->gridLayout_4->addWidget(m_ui->frame, 5, 0); // Les Noirs passent en bas - } - this->playerTurnNotice(); } @@ -120,12 +119,22 @@ void RetroChessWindow::initAccessories() m_ui->m_player2_name->setText( p2name.c_str() ); QPixmap p1avatar; - AvatarDefs::getAvatarFromSslId(p1id, p1avatar); - m_ui->m_player1_avatar->setPixmap(p1avatar);//QPixmap(":/images/profile.png")); + if (rsRetroChess->getAvatar(p1id, p1avatar) && !p1avatar.isNull()) { + m_ui->m_player1_avatar->setPixmap(p1avatar.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + } else { + AvatarDefs::getAvatarFromSslId(p1id, p1avatar); + m_ui->m_player1_avatar->setPixmap(p1avatar.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + } + m_ui->m_player1_avatar->setAlignment(Qt::AlignCenter); QPixmap p2avatar; - AvatarDefs::getAvatarFromSslId(p2id, p2avatar); - m_ui->m_player2_avatar->setPixmap(p2avatar);//QPixmap(":/images/profile.png")); + if (rsRetroChess->getAvatar(p2id, p2avatar) && !p2avatar.isNull()) { + m_ui->m_player2_avatar->setPixmap(p2avatar.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + } else { + AvatarDefs::getAvatarFromSslId(p2id, p2avatar); + m_ui->m_player2_avatar->setPixmap(p2avatar.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + } + m_ui->m_player2_avatar->setAlignment(Qt::AlignCenter); //m_ui->m_move_record->setStyleSheet("QLabel {background-color: white;}"); } @@ -1020,26 +1029,24 @@ void RetroChessWindow::showPlayerLeaveMsg() void RetroChessWindow::playerTurnNotice() { - if( this->turn ) + // The bottom player (p2/You) gets the "Turn" notice only if it's their turn + if (m_localplayer_turn == turn) { - m_ui->m_player1_result->setText("Waiting for opponent"); - m_ui->m_player1_result->setStyleSheet("QLabel {font: 14pt; color: gray;}"); + m_ui->m_player2_result->setText(tr("Turn")); + m_ui->m_player2_result->setStyleSheet("QLabel {font: 14pt; color: green; font-weight: bold;}"); - m_ui->m_player2_result->setText("Turn"); - m_ui->m_player2_result->setStyleSheet("QLabel {font: 14pt; color: green; text:bold;}"); - - m_ui->m_player1_result->setVisible(true); - m_ui->m_player2_result->setVisible(true); + m_ui->m_player1_result->setText(tr("Waiting for opponent")); + m_ui->m_player1_result->setStyleSheet("QLabel {font: 14pt; color: gray;}"); } else { - m_ui->m_player1_result->setText("Turn"); - m_ui->m_player1_result->setStyleSheet("QLabel {font: 14pt;color: green;}"); - - m_ui->m_player2_result->setText("Waiting for opponent"); - m_ui->m_player2_result->setStyleSheet("QLabel {font: 14pt;color: gray; text:bold;}"); + m_ui->m_player1_result->setText(tr("Turn")); + m_ui->m_player1_result->setStyleSheet("QLabel {font: 14pt; color: green; font-weight: bold;}"); - m_ui->m_player1_result->setVisible(true); - m_ui->m_player2_result->setVisible(true); + m_ui->m_player2_result->setText(tr("Waiting for opponent")); + m_ui->m_player2_result->setStyleSheet("QLabel {font: 14pt; color: gray;}"); } + + m_ui->m_player1_result->setVisible(true); + m_ui->m_player2_result->setVisible(true); } diff --git a/interface/rsRetroChess.h b/interface/rsRetroChess.h index 861c259..0bb9d70 100644 --- a/interface/rsRetroChess.h +++ b/interface/rsRetroChess.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,9 @@ class RsRetroChess virtual bool hasInviteTo_chat(const ChatId& chatId) = 0; virtual std::string getPeerName(const RsPeerId& id) = 0; virtual std::string getGxsName(const RsGxsId& id) = 0; + virtual bool getAvatar(const RsPeerId& id, QPixmap& avatar) = 0; + virtual RsPeerId getOwnId(const RsPeerId& remoteId) = 0; + virtual bool isLocalId(const RsPeerId& id) = 0; }; diff --git a/services/p3RetroChess.cc b/services/p3RetroChess.cc index 9cc7266..89a8325 100644 --- a/services/p3RetroChess.cc +++ b/services/p3RetroChess.cc @@ -30,6 +30,7 @@ #include "services/p3RetroChess.h" #include "services/rsRetroChessItems.h" +#include "gui/common/AvatarDefs.h" #include @@ -215,6 +216,34 @@ void p3RetroChess::sendInvite(RsPeerId peerID) { mPeerID = peer; }*/ +RsPeerId p3RetroChess::getOwnId(const RsPeerId& remoteId) +{ + RsStackMutex stack(mRetroChessMtx); + if (mPseudoToRealGxsMap.count(remoteId)) { + RsGxsId targetId = mPseudoToRealGxsMap[remoteId]; + if (mTargetToOwnGxsIdMap.count(targetId)) { + return RsPeerId(mTargetToOwnGxsIdMap[targetId].toStdString()); + } + } + return rsPeers->getOwnId(); +} + +bool p3RetroChess::isLocalId(const RsPeerId& id) +{ + if (id == rsPeers->getOwnId()) return true; + + RsStackMutex stack(mRetroChessMtx); + RsGxsId gxsId(id.toStdString()); + if (mPseudoToRealGxsMap.count(id)) { + gxsId = mPseudoToRealGxsMap[id]; + } + + if (!gxsId.isNull() && mIdentity) { + return mIdentity->isOwnId(gxsId); + } + return false; +} + void p3RetroChess::raw_msg_peer(RsPeerId peerID, std::string msg) { { @@ -465,7 +494,13 @@ void p3RetroChess::raw_msg_gxs(const RsGxsId& targetId, const RsGxsId& sourceId, if (mGxsTunnels->requestSecuredTunnel(targetId, sourceId, tunnelId, RS_SERVICE_TYPE_RetroChess_PLUGIN, error_code)) { mGxsToTunnelMap[key] = tunnelId; mTargetGxsToTunnelMap[targetId] = tunnelId; + mTargetToOwnGxsIdMap[targetId] = sourceId; mTunnelToPeerGxsIdMap[tunnelId] = targetId; + + // On mémorise aussi notre propre ID pour que getAvatar fonctionne pour nous + mPseudoToRealGxsMap[RsPeerId(sourceId.toStdString())] = sourceId; + mPseudoToNameMap[RsPeerId(sourceId.toStdString())] = getGxsName(sourceId); + RsDbg() << "CHESS: Tunnel requested successfully: " << tunnelId; } else { RsErr() << "CHESS: Failed to request tunnel, error=" << error_code; @@ -703,6 +738,30 @@ void p3RetroChess::acceptedInvite_chat(const ChatId& chatId) } } +bool p3RetroChess::getAvatar(const RsPeerId& id, QPixmap& avatar) +{ + RsStackMutex stack(mRetroChessMtx); + RsGxsId gxsId; + + if (mPseudoToRealGxsMap.count(id)) { + gxsId = mPseudoToRealGxsMap[id]; + RsDbg() << "CHESS: getAvatar - Found GXS ID for pseudo " << id << " -> " << gxsId; + } else { + // Tentative de détection directe si l'ID est binaire mais compatible + gxsId = RsGxsId(id.toStdString()); + } + + if (!gxsId.isNull()) { + if (AvatarDefs::getAvatarFromGxsId(gxsId, avatar)) { + RsDbg() << "CHESS: getAvatar - Successfully loaded GXS avatar for " << gxsId; + return true; + } + } + + RsDbg() << "CHESS: getAvatar - Falling back to SSL avatar for " << id; + return AvatarDefs::getAvatarFromSslId(id, avatar); +} + std::string p3RetroChess::getGxsName(const RsGxsId& gxs_id) { if (mIdentity) { @@ -722,6 +781,18 @@ std::string p3RetroChess::getPeerName(const RsPeerId& id) RsDbg() << "CHESS: Found name in pseudo map: " << mPseudoToNameMap[id]; return mPseudoToNameMap[id]; } + + // Fallback : si c'est un pseudo-ID GXS, on tente une résolution directe + RsGxsId gxsId(id.toStdString()); + if (mPseudoToRealGxsMap.count(id)) { + gxsId = mPseudoToRealGxsMap[id]; + } + + if (!gxsId.isNull()) { + std::string name = getGxsName(gxsId); + if (!name.empty() && name != "GXS Friend") return name; + } + return rsPeers->getPeerName(id); } diff --git a/services/p3RetroChess.h b/services/p3RetroChess.h index 31ae6c0..e8050db 100644 --- a/services/p3RetroChess.h +++ b/services/p3RetroChess.h @@ -96,6 +96,9 @@ class p3RetroChess: public RsPQIService, public RsRetroChess, public RsGxsTunnel void connectToChatService(RsChats *chat_service); virtual std::string getPeerName(const RsPeerId& id) override; virtual std::string getGxsName(const RsGxsId& gxs_id) override; + virtual bool getAvatar(const RsPeerId& id, QPixmap& avatar) override; + virtual RsPeerId getOwnId(const RsPeerId& remoteId) override; + virtual bool isLocalId(const RsPeerId& id) override; void ping_all(); @@ -150,6 +153,7 @@ class p3RetroChess: public RsPQIService, public RsRetroChess, public RsGxsTunnel std::map mGxsToTunnelMap; std::map mTargetGxsToTunnelMap; + std::map mTargetToOwnGxsIdMap; std::map mTunnelToPeerGxsIdMap; std::map> mPendingTunnelMessages; std::map mPseudoToNameMap; From b9c4a33341671d5662ac4d544295a6317ecd88f0 Mon Sep 17 00:00:00 2001 From: jolavillette Date: Sun, 3 May 2026 12:49:19 +0200 Subject: [PATCH 4/4] RetroChess: add tooltip, implement handshake --- gui/RetroChessChatWidgetHolder.cpp | 24 ++++++++++---- interface/rsRetroChess.h | 2 ++ services/p3RetroChess.cc | 52 ++++++++++++++++++++++++++++-- services/p3RetroChess.h | 4 +++ 4 files changed, 72 insertions(+), 10 deletions(-) diff --git a/gui/RetroChessChatWidgetHolder.cpp b/gui/RetroChessChatWidgetHolder.cpp index cbdd012..ed7f2af 100644 --- a/gui/RetroChessChatWidgetHolder.cpp +++ b/gui/RetroChessChatWidgetHolder.cpp @@ -89,14 +89,17 @@ RetroChessChatWidgetHolder::RetroChessChatWidgetHolder(ChatWidget *chatWidget, R else if (rsRetroChess->hasInviteTo_chat(chatId)) { RsDbg() << "CHESS: Button DISABLED (Waiting for opponent)"; + playChessButton->setText(tr("Invite Sent...")); playChessButton->setEnabled(false); playChessButton->setToolTip(tr("Waiting for oponent...")); } else { - RsDbg() << "CHESS: Button ENABLED (Ready to play)"; - playChessButton->setEnabled(true); - playChessButton->setToolTip(tr("Play Chess")); + bool ready = rsRetroChess->isPeerReady_chat(chatId); + RsDbg() << "CHESS: isPeerReady_chat for " << chatId.toStdString() << " returned " << (ready?"TRUE":"FALSE"); + playChessButton->setText(tr("Play Chess")); + playChessButton->setEnabled(ready); + playChessButton->setToolTip(ready ? tr("Play Chess") : tr("Chess handshake is only possible if a message has been previously sent to the friend. Checking...")); } mChatWidget->addTitleBarWidget(playChessButton); // <--- PLACE LE BOUTON EN HAUT @@ -105,6 +108,9 @@ RetroChessChatWidgetHolder::RetroChessChatWidgetHolder(ChatWidget *chatWidget, R // Vérifier immédiatement s'il y a une invitation en attente à l'ouverture de la fenêtre chessnotify(mChatWidget->getChatId().toPeerId()); + + // POKER le tunnel GXS immédiatement pour déclencher le handshake + rsRetroChess->pokeTunnel_chat(mChatWidget->getChatId()); } RetroChessChatWidgetHolder::~RetroChessChatWidgetHolder() @@ -117,7 +123,7 @@ RetroChessChatWidgetHolder::~RetroChessChatWidgetHolder() } } -void RetroChessChatWidgetHolder::chessnotify(RsPeerId from_peer_id) +void RetroChessChatWidgetHolder::chessnotify(RsPeerId /*from_peer_id*/) { ChatId chatId = mChatWidget->getChatId(); @@ -148,19 +154,23 @@ void RetroChessChatWidgetHolder::chessnotify(RsPeerId from_peer_id) RsDbg() << "CHESS: User rejected via popup"; } } + playChessButton->setText(tr("Accept Invite")); playChessButton->setEnabled(true); } else if (rsRetroChess->hasInviteTo_chat(chatId)) { RsDbg() << "CHESS: Button DISABLED (Waiting for opponent)"; + playChessButton->setText(tr("Invite Sent...")); playChessButton->setEnabled(false); playChessButton->setToolTip(tr("Waiting for oponent...")); } else { - RsDbg() << "CHESS: Button ENABLED (Ready to play)"; - playChessButton->setEnabled(true); - playChessButton->setToolTip(tr("Play Chess")); + bool ready = rsRetroChess->isPeerReady_chat(chatId); + RsDbg() << "CHESS: isPeerReady_chat for " << chatId.toStdString() << " returned " << (ready?"TRUE":"FALSE"); + playChessButton->setText(tr("Play Chess")); + playChessButton->setEnabled(ready); + playChessButton->setToolTip(ready ? tr("Play Chess") : tr("Chess handshake is only possible if a message has been previously sent to the friend. Checking...")); } } diff --git a/interface/rsRetroChess.h b/interface/rsRetroChess.h index 0bb9d70..1e93a07 100644 --- a/interface/rsRetroChess.h +++ b/interface/rsRetroChess.h @@ -59,9 +59,11 @@ class RsRetroChess virtual void chess_click_chat(const ChatId& chatId, int col, int row, int count) = 0; virtual void player_leave_chat(const ChatId& chatId) = 0; virtual void sendInvite_chat(const ChatId& chatId) = 0; + virtual void pokeTunnel_chat(const ChatId& chatId) = 0; virtual void acceptedInvite_chat(const ChatId& chatId) = 0; virtual bool hasInviteFrom_chat(const ChatId& chatId) = 0; virtual bool hasInviteTo_chat(const ChatId& chatId) = 0; + virtual bool isPeerReady_chat(const ChatId& chatId) = 0; virtual std::string getPeerName(const RsPeerId& id) = 0; virtual std::string getGxsName(const RsGxsId& id) = 0; virtual bool getAvatar(const RsPeerId& id, QPixmap& avatar) = 0; diff --git a/services/p3RetroChess.cc b/services/p3RetroChess.cc index 89a8325..e37ae2c 100644 --- a/services/p3RetroChess.cc +++ b/services/p3RetroChess.cc @@ -178,13 +178,13 @@ bool p3RetroChess::hasInviteTo(RsPeerId peerID) void p3RetroChess::acceptedInvite(RsPeerId peerID) { - std::set::iterator it =invitesTo.find(peerID); + std::set::iterator it = invitesTo.find(peerID); if (it != invitesTo.end()) { invitesTo.erase(it); } - it =invitesFrom.find(peerID); + it = invitesFrom.find(peerID); if (it != invitesFrom.end()) { invitesFrom.erase(it); @@ -569,9 +569,28 @@ void p3RetroChess::receiveData(const RsGxsTunnelId& tunnel_id, unsigned char *da gxsInvitesFrom.insert(peerGxsId); mPseudoToNameMap[pseudoPeerId] = getGxsName(peerGxsId); mPseudoToRealGxsMap[pseudoPeerId] = peerGxsId; - RsDbg() << "CHESS: Mapped pseudo " << pseudoPeerId << " to name " << mPseudoToNameMap[pseudoPeerId]; } mNotify->notifyChessInvite(pseudoPeerId); + } else if (type == "chess_hello") { + RsDbg() << "CHESS: Received HELLO from GXS " << peerGxsId; + { + RsStackMutex stack(mRetroChessMtx); + gxsPeersReady.insert(peerGxsId); + } + // On répond par un ACK + RsGxsTunnelService::GxsTunnelInfo info; + if (mGxsTunnels->getTunnelInfo(tunnel_id, info)) { + std::string ack = "{\"type\":\"chess_hello_ack\"}"; + raw_msg_gxs(peerGxsId, info.source_gxs_id, ack); + } + mNotify->notifyChessInvite(pseudoPeerId); // Refresh UI + } else if (type == "chess_hello_ack") { + RsDbg() << "CHESS: Received HELLO_ACK from GXS " << peerGxsId; + { + RsStackMutex stack(mRetroChessMtx); + gxsPeersReady.insert(peerGxsId); + } + mNotify->notifyChessInvite(pseudoPeerId); // Refresh UI } else if (type == "chess_accept") { RsDbg() << "CHESS: Handling incoming acceptance from GXS " << peerGxsId; { @@ -707,6 +726,33 @@ void p3RetroChess::sendInvite_chat(const ChatId& chatId) } } +void p3RetroChess::pokeTunnel_chat(const ChatId& chatId) +{ + RsDbg() << "CHESS: pokeTunnel_chat for: " << chatId.toStdString(); + if (chatId.isDistantChatId()) { + RsChats *chats = mChats ? mChats : rsChats; + DistantChatPeerInfo info; + if (chats && chats->getDistantChatStatus(chatId.toDistantChatId(), info)) { + RsDbg() << "CHESS: Poking GXS tunnel with HELLO for " << info.to_id; + std::string hello = "{\"type\":\"chess_hello\"}"; + raw_msg_gxs(info.to_id, info.own_id, hello); + } + } +} + +bool p3RetroChess::isPeerReady_chat(const ChatId& chatId) +{ + RsChats *chats = mChats ? mChats : rsChats; + if (chatId.isDistantChatId()) { + DistantChatPeerInfo info; + if (chats && chats->getDistantChatStatus(chatId.toDistantChatId(), info)) { + RsStackMutex stack(mRetroChessMtx); + return gxsPeersReady.find(info.to_id) != gxsPeersReady.end(); + } + } + return false; +} + void p3RetroChess::acceptedInvite_chat(const ChatId& chatId) { RsDbg() << "CHESS: acceptedInvite_chat for: " << chatId.toStdString(); diff --git a/services/p3RetroChess.h b/services/p3RetroChess.h index e8050db..5b63ce1 100644 --- a/services/p3RetroChess.h +++ b/services/p3RetroChess.h @@ -122,9 +122,12 @@ class p3RetroChess: public RsPQIService, public RsRetroChess, public RsGxsTunnel virtual void chess_click_chat(const ChatId& chatId, int col, int row, int count) override; virtual void player_leave_chat(const ChatId& chatId) override; virtual void sendInvite_chat(const ChatId& chatId) override; + virtual void pokeTunnel_chat(const ChatId& chatId); virtual void acceptedInvite_chat(const ChatId& chatId) override; virtual bool hasInviteFrom_chat(const ChatId& chatId) override; virtual bool hasInviteTo_chat(const ChatId& chatId) override; + virtual bool isPeerReady_chat(const ChatId& chatId); + private: @@ -132,6 +135,7 @@ class p3RetroChess: public RsPQIService, public RsRetroChess, public RsGxsTunnel std::set invitesFrom; std::set gxsInvitesTo; std::set gxsInvitesFrom; + std::set gxsPeersReady; void handleData(RsRetroChessDataItem*) ; void msg_chat(const ChatId& chatId, const std::string& msg);