From c72b49c296d3228c1ce4431d4bcf49a7988c1183 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 15 Jun 2019 13:54:34 +0200 Subject: [PATCH] automaticall save/restore subscribed chat rooms. The advantage is that auto-subscribed is not needed anymore and chat rooms will survive automatically --- libretroshare/src/chat/distributedchat.cc | 93 ++++++++++++++++--- libretroshare/src/chat/rschatitems.cc | 7 ++ libretroshare/src/chat/rschatitems.h | 16 ++++ libretroshare/src/retroshare/rsmsgs.h | 2 + retroshare-gui/src/gui/ChatLobbyWidget.cpp | 19 +++- retroshare-gui/src/gui/MainWindow.cpp | 10 ++ .../src/gui/chat/ChatLobbyDialog.cpp | 5 +- 7 files changed, 136 insertions(+), 16 deletions(-) diff --git a/libretroshare/src/chat/distributedchat.cc b/libretroshare/src/chat/distributedchat.cc index aeb88b7f1..2a9993c37 100644 --- a/libretroshare/src/chat/distributedchat.cc +++ b/libretroshare/src/chat/distributedchat.cc @@ -39,12 +39,12 @@ //#define DEBUG_CHAT_LOBBIES 1 -static const int CONNECTION_CHALLENGE_MAX_COUNT = 20 ; // sends a connection challenge every 20 messages -static const rstime_t CONNECTION_CHALLENGE_MAX_MSG_AGE = 30 ; // maximum age of a message to be used in a connection challenge -static const int CONNECTION_CHALLENGE_MIN_DELAY = 15 ; // sends a connection at most every 15 seconds -static const int LOBBY_CACHE_CLEANING_PERIOD = 10 ; // clean lobby caches every 10 secs (remove old messages) +static const int CONNECTION_CHALLENGE_MAX_COUNT = 20 ; // sends a connection challenge every 20 messages +static const rstime_t CONNECTION_CHALLENGE_MAX_MSG_AGE = 30 ; // maximum age of a message to be used in a connection challenge +static const int CONNECTION_CHALLENGE_MIN_DELAY = 15 ; // sends a connection at most every 15 seconds +static const int LOBBY_CACHE_CLEANING_PERIOD = 10 ; // clean lobby caches every 10 secs (remove old messages) -static const rstime_t MAX_KEEP_MSG_RECORD = 1200 ; // keep msg record for 1200 secs max. +static const rstime_t MAX_KEEP_MSG_RECORD = 1200 ; // keep msg record for 1200 secs max. static const rstime_t MAX_KEEP_INACTIVE_NICKNAME = 180 ; // keep inactive nicknames for 3 mn max. static const rstime_t MAX_DELAY_BETWEEN_LOBBY_KEEP_ALIVE = 120 ; // send keep alive packet every 2 minutes. static const rstime_t MAX_KEEP_PUBLIC_LOBBY_RECORD = 60 ; // keep inactive lobbies records for 60 secs max. @@ -52,7 +52,7 @@ static const rstime_t MIN_DELAY_BETWEEN_PUBLIC_LOBBY_REQ = 20 ; // don't ask static const rstime_t LOBBY_LIST_AUTO_UPDATE_TIME = 121 ; // regularly ask for available lobbies every 5 minutes, to allow auto-subscribe to work static const uint32_t MAX_ALLOWED_LOBBIES_IN_LIST_WARNING = 50 ; -//static const uint32_t MAX_MESSAGES_PER_SECONDS_NUMBER = 5 ; // max number of messages from a given peer in a window for duration below +//static const uint32_t MAX_MESSAGES_PER_SECONDS_NUMBER = 5 ; // max number of messages from a given peer in a window for duration below static const uint32_t MAX_MESSAGES_PER_SECONDS_PERIOD = 10 ; // duration window for max number of messages before messages get dropped. #define IS_PUBLIC_LOBBY(flags) (flags & RS_CHAT_LOBBY_FLAGS_PUBLIC ) @@ -1629,6 +1629,8 @@ ChatLobbyId DistributedChatService::createChatLobby(const std::string& lobby_nam RsServer::notify()->notifyListChange(NOTIFY_LIST_CHAT_LOBBY_LIST, NOTIFY_TYPE_ADD) ; + triggerConfigSave(); + return lobby_id ; } @@ -1826,14 +1828,18 @@ bool DistributedChatService::setIdentityForChatLobby(const ChatLobbyId& lobby_id void DistributedChatService::setLobbyAutoSubscribe(const ChatLobbyId& lobby_id, const bool autoSubscribe) { - if(autoSubscribe){ - _known_lobbies_flags[lobby_id] |= RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE; - RsGxsId gxsId; - if (getIdentityForChatLobby(lobby_id, gxsId)) - _lobby_default_identity[lobby_id] = gxsId; - } else { - _known_lobbies_flags[lobby_id] &= ~RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE ; - _lobby_default_identity.erase(lobby_id); + { + RS_STACK_MUTEX(mDistributedChatMtx); + + if(autoSubscribe){ + _known_lobbies_flags[lobby_id] |= RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE; + RsGxsId gxsId; + if (getIdentityForChatLobby(lobby_id, gxsId)) + _lobby_default_identity[lobby_id] = gxsId; + } else { + _known_lobbies_flags[lobby_id] &= ~RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE ; + _lobby_default_identity.erase(lobby_id); + } } RsServer::notify()->notifyListChange(NOTIFY_LIST_CHAT_LOBBY_LIST, NOTIFY_TYPE_ADD) ; @@ -1966,6 +1972,15 @@ void DistributedChatService::addToSaveList(std::list& list) const list.push_back(clci) ; } + for(auto it(_chat_lobbys.begin());it!=_chat_lobbys.end();++it) + { + RsSubscribedChatLobbyConfigItem *scli = new RsSubscribedChatLobbyConfigItem; + + scli->info = it->second; // copies the ChatLobbyInfo part only + + list.push_back(scli); + } + /* Save Default Nick Name */ { RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet ; @@ -2061,6 +2076,56 @@ bool DistributedChatService::processLoadListItem(const RsItem *item) if(!own_ids.empty()) _default_identity = own_ids.front() ; } + + const RsSubscribedChatLobbyConfigItem *scli = dynamic_cast(item); + + if(scli != NULL) + { + if(_chat_lobbys.find(scli->info.lobby_id) != _chat_lobbys.end()) // do nothing if the lobby is already subscribed + return true; + + std::cerr << "Re-subscribing to chat lobby " << (void*)scli->info.lobby_id << ", flags = " << scli->info.lobby_flags << std::endl; + + rstime_t now = time(NULL); + + // Add the chat room into visible chat rooms + { + RS_STACK_MUTEX(mDistributedChatMtx); /********** STACK LOCKED MTX ******/ + + VisibleChatLobbyRecord& rec(_visible_lobbies[scli->info.lobby_id]) ; + + rec.lobby_id = scli->info.lobby_id ; + rec.lobby_name = scli->info.lobby_name ; + rec.lobby_topic = scli->info.lobby_topic ; + rec.participating_friends = scli->info.participating_friends; + rec.total_number_of_peers = 0; + rec.last_report_time = now ; + rec.lobby_flags = EXTRACT_PRIVACY_FLAGS(scli->info.lobby_flags) ; + + _known_lobbies_flags[scli->info.lobby_id] |= RS_CHAT_LOBBY_FLAGS_AUTO_SUBSCRIBE; + } + + // Add the chat room into subscribed chat rooms + + ChatLobbyEntry entry ; + (ChatLobbyInfo&)entry = scli->info; + + entry.virtual_peer_id = makeVirtualPeerId(entry.lobby_id) ; // not random, so we keep the same id at restart + entry.connexion_challenge_count = 0 ; + entry.last_activity = now ; + entry.last_connexion_challenge_time = now ; + entry.last_keep_alive_packet_time = now ; + + RS_STACK_MUTEX(mDistributedChatMtx); /********** STACK LOCKED MTX ******/ + _chat_lobbys[entry.lobby_id] = entry ; + + // make the UI aware of the existing chat room + + RsServer::notify()->notifyListChange(NOTIFY_LIST_CHAT_LOBBY_LIST, NOTIFY_TYPE_ADD) ; + return true; + } + + return false ; } diff --git a/libretroshare/src/chat/rschatitems.cc b/libretroshare/src/chat/rschatitems.cc index 55cd6cd88..d3a837b07 100644 --- a/libretroshare/src/chat/rschatitems.cc +++ b/libretroshare/src/chat/rschatitems.cc @@ -21,6 +21,7 @@ *******************************************************************************/ #include +#include "retroshare/rsmsgs.h" #include "util/rstime.h" #include "serialiser/rsbaseserial.h" #include "serialiser/rstlvbase.h" @@ -52,6 +53,7 @@ RsItem *RsChatSerialiser::create_item(uint16_t service_id,uint8_t item_sub_id) c case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_REQUEST: return new RsChatLobbyListRequestItem(); case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST: return new RsChatLobbyListItem(); case RS_PKT_SUBTYPE_CHAT_LOBBY_CONFIG: return new RsChatLobbyConfigItem(); + case RS_PKT_SUBTYPE_SUBSCRIBED_CHAT_LOBBY_CONFIG: return new RsSubscribedChatLobbyConfigItem(); case RS_PKT_SUBTYPE_OUTGOING_MAP: return new PrivateOugoingMapItem(); default: std::cerr << "Unknown packet type in chat!" << std::endl; @@ -172,6 +174,11 @@ void RsChatAvatarItem::serial_process(RsGenericSerializer::SerializeJob j,RsGene RsTypeSerializer::serial_process(j,ctx,b,"image data") ; } +void RsSubscribedChatLobbyConfigItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) +{ + info.serial_process(j,ctx); +} + void RsChatLobbyConfigItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) { RsTypeSerializer::serial_process(j,ctx,lobby_Id,"lobby_Id") ; diff --git a/libretroshare/src/chat/rschatitems.h b/libretroshare/src/chat/rschatitems.h index f2ca0731d..244be60b2 100644 --- a/libretroshare/src/chat/rschatitems.h +++ b/libretroshare/src/chat/rschatitems.h @@ -34,6 +34,7 @@ #include "serialiser/rstlvidset.h" #include "serialiser/rstlvfileitem.h" +#include "retroshare/rsmsgs.h" /* chat Flags */ const uint32_t RS_CHAT_FLAG_PRIVATE = 0x0001; @@ -82,6 +83,8 @@ const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE_DEPRECATED = 0x1A ; // to be remo const uint8_t RS_PKT_SUBTYPE_CHAT_LOBBY_INVITE = 0x1B ; const uint8_t RS_PKT_SUBTYPE_OUTGOING_MAP = 0x1C ; +const uint8_t RS_PKT_SUBTYPE_SUBSCRIBED_CHAT_LOBBY_CONFIG = 0x1D ; + typedef uint64_t ChatLobbyId ; typedef uint64_t ChatLobbyMsgId ; typedef std::string ChatLobbyNickName ; @@ -298,6 +301,19 @@ struct RsPrivateChatMsgConfigItem : RsChatItem uint32_t recvTime; }; +class RsSubscribedChatLobbyConfigItem: public RsChatItem +{ +public: + RsSubscribedChatLobbyConfigItem() :RsChatItem(RS_PKT_SUBTYPE_SUBSCRIBED_CHAT_LOBBY_CONFIG) {} + virtual ~RsSubscribedChatLobbyConfigItem() {} + + virtual void clear() { RsChatItem::clear(); info.clear(); } + + void serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx); + + ChatLobbyInfo info; +}; + class RsChatLobbyConfigItem: public RsChatItem { public: diff --git a/libretroshare/src/retroshare/rsmsgs.h b/libretroshare/src/retroshare/rsmsgs.h index 562a3ebaf..aeb52bb72 100644 --- a/libretroshare/src/retroshare/rsmsgs.h +++ b/libretroshare/src/retroshare/rsmsgs.h @@ -470,6 +470,8 @@ public: std::map gxs_ids ; // list of non direct friend who participate. Used to display only. rstime_t last_activity ; // last recorded activity. Useful for removing dead lobbies. + virtual void clear() { gxs_ids.clear(); lobby_id = 0; lobby_name.clear(); lobby_topic.clear(); participating_friends.clear(); } + // RsSerializable interface public: void serial_process(RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext &ctx) { diff --git a/retroshare-gui/src/gui/ChatLobbyWidget.cpp b/retroshare-gui/src/gui/ChatLobbyWidget.cpp index f93d9a501..4d229c730 100644 --- a/retroshare-gui/src/gui/ChatLobbyWidget.cpp +++ b/retroshare-gui/src/gui/ChatLobbyWidget.cpp @@ -331,10 +331,14 @@ void ChatLobbyWidget::lobbyTreeWidgetCustomPopupMenu(QPoint) } } +#ifdef TO_BE_REMOVED + // This code is not needed anymore because AutoSubscribe is now automatically handled with chat room subscription. + if (item->data(COLUMN_DATA, ROLE_AUTOSUBSCRIBE).toBool()) contextMnu.addAction(QIcon(IMAGE_AUTOSUBSCRIBE), tr("Remove Auto Subscribe"), this, SLOT(autoSubscribeItem())); else if(!own_identities.empty()) contextMnu.addAction(QIcon(IMAGE_SUBSCRIBE), tr("Add Auto Subscribe"), this, SLOT(autoSubscribeItem())); +#endif contextMnu.addAction(QIcon(IMAGE_COPYRSLINK), tr("Copy RetroShare Link"), this, SLOT(copyItemLink())); } @@ -603,9 +607,12 @@ void ChatLobbyWidget::updateDisplay() item->setIcon(COLUMN_NAME, subscribed ? icon : icon.pixmap(ui.lobbyTreeWidget->iconSize(), QIcon::Disabled)); } + // In the new model (after lobby save to disk) the auto-subscribe flag is used to automatically join lobbies that where + // previously being used when the software quits. + bool autoSubscribe = rsMsgs->getLobbyAutoSubscribe(lobby.lobby_id); - if (autoSubscribe && subscribed) + if (autoSubscribe && !subscribed) { if(_lobby_infos.find(lobby.lobby_id) == _lobby_infos.end()) { @@ -674,6 +681,16 @@ void ChatLobbyWidget::updateDisplay() bool autoSubscribe = rsMsgs->getLobbyAutoSubscribe(lobby.lobby_id); updateItem(ui.lobbyTreeWidget, item, lobby.lobby_id, lobby.lobby_name,lobby.lobby_topic, lobby.gxs_ids.size(), true, autoSubscribe,lobby_flags); + + std::map::iterator it = _lobby_infos.find(lobby.lobby_id) ; + + // look for chat rooms that are subscribed but not displayed as such + + if(it == _lobby_infos.end() && rsMsgs->joinVisibleChatLobby(lobby.lobby_id,lobby.gxs_id)) + { + std::cerr << "Adding back ChatLobbyDialog for subscribed lobby " << std::hex << lobby.lobby_id << std::dec << std::endl; + ChatDialog::chatFriend(ChatId(lobby.lobby_id),false) ; + } } publicSubLobbyItem->setHidden(publicSubLobbyItem->childCount()==0); publicSubLobbyItem->setText(COLUMN_NAME, tr("Public Subscribed chat rooms")+ QString(" (") + QString::number(publicSubLobbyItem->childCount())+QString(")")); diff --git a/retroshare-gui/src/gui/MainWindow.cpp b/retroshare-gui/src/gui/MainWindow.cpp index 3a81877ce..e28241bf9 100644 --- a/retroshare-gui/src/gui/MainWindow.cpp +++ b/retroshare-gui/src/gui/MainWindow.cpp @@ -172,6 +172,16 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags) ui = new Ui::MainWindow; trayIcon = NULL; + friendsDialog=NULL; + idDialog=NULL; + chatLobbyDialog=NULL; + settingsDialog=NULL; + transfersDialog=NULL; + messagesDialog=NULL; + gxschannelDialog=NULL; + gxsforumDialog=NULL; + postedDialog=NULL; + /* Invoke the Qt Designer generated QObject setup routine */ ui->setupUi(this); diff --git a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp index ec2994ced..84b579338 100644 --- a/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp +++ b/retroshare-gui/src/gui/chat/ChatLobbyDialog.cpp @@ -912,7 +912,10 @@ void ChatLobbyDialog::showDialog(uint chatflags) if (chatflags & RS_CHAT_FOCUS) { MainWindow::showWindow(MainWindow::ChatLobby); - dynamic_cast(MainWindow::getPage(MainWindow::ChatLobby))->setCurrentChatPage(this) ; + MainPage *p = MainWindow::getPage(MainWindow::ChatLobby); + + if(p != NULL) + dynamic_cast(p)->setCurrentChatPage(this) ; } }