From 1c571f196af0013e1b0ad1c9e075ed9c711e915b Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 11 May 2013 11:04:47 +0900 Subject: [PATCH] Refactor Notifier interface to accept DownloadEventListener interface WebSocketSessionMan now implements DownloadEventListener and is added to Notifier. It becomes member variable of DownloadEngine. The event constant for download event is defined in aria2.h so that we can add event callback API later. --- src/DefaultPieceStorage.cc | 2 +- src/DownloadEngine.cc | 11 ++++++++ src/DownloadEngine.h | 18 ++++++++++++ src/MultiUrlRequestInfo.cc | 14 ++++++---- src/Notifier.cc | 38 ++++++------------------- src/Notifier.h | 36 ++++++++++-------------- src/RequestGroupMan.cc | 16 +++++------ src/WebSocketInteractionCommand.cc | 5 ++-- src/WebSocketSessionMan.cc | 45 ++++++++++++++++++++++++++++++ src/WebSocketSessionMan.h | 5 ++-- src/includes/aria2/aria2.h | 33 ++++++++++++++++++++++ 11 files changed, 153 insertions(+), 70 deletions(-) diff --git a/src/DefaultPieceStorage.cc b/src/DefaultPieceStorage.cc index 954765ef..baba8be8 100644 --- a/src/DefaultPieceStorage.cc +++ b/src/DefaultPieceStorage.cc @@ -494,7 +494,7 @@ void DefaultPieceStorage::completePiece(const SharedHandle& piece) util::executeHookByOptName(downloadContext_->getOwnerRequestGroup(), option_, PREF_ON_BT_DOWNLOAD_COMPLETE); SingletonHolder::instance()-> - notifyDownloadEvent(Notifier::ON_BT_DOWNLOAD_COMPLETE, + notifyDownloadEvent(EVENT_ON_BT_DOWNLOAD_COMPLETE, downloadContext_->getOwnerRequestGroup()); } } diff --git a/src/DownloadEngine.cc b/src/DownloadEngine.cc index c014eb80..71607ca0 100644 --- a/src/DownloadEngine.cc +++ b/src/DownloadEngine.cc @@ -69,6 +69,9 @@ #ifdef ENABLE_BITTORRENT # include "BtRegistry.h" #endif // ENABLE_BITTORRENT +#ifdef ENABLE_WEBSOCKET +# include "WebSocketSessionMan.h" +#endif // ENABLE_WEBSOCKET namespace aria2 { @@ -596,4 +599,12 @@ void DownloadEngine::setAsyncDNSServers(ares_addr_node* asyncDNSServers) } #endif // HAVE_ARES_ADDR_NODE +#ifdef ENABLE_WEBSOCKET +void DownloadEngine::setWebSocketSessionMan +(const SharedHandle& wsman) +{ + webSocketSessionMan_ = wsman; +} +#endif // ENABLE_WEBSOCKET + } // namespace aria2 diff --git a/src/DownloadEngine.h b/src/DownloadEngine.h index ff14a93e..afe51307 100644 --- a/src/DownloadEngine.h +++ b/src/DownloadEngine.h @@ -68,6 +68,11 @@ class Command; #ifdef ENABLE_BITTORRENT class BtRegistry; #endif // ENABLE_BITTORRENT +#ifdef ENABLE_WEBSOCKET +namespace rpc { +class WebSocketSessionMan; +} // namespace rpc +#endif // ENABLE_WEBSOCKET class DownloadEngine { private: @@ -144,6 +149,10 @@ private: SharedHandle authConfigFactory_; +#ifdef ENABLE_WEBSOCKET + SharedHandle webSocketSessionMan_; +#endif // ENABLE_WEBSOCKET + /** * Delegates to StatCalc */ @@ -349,6 +358,15 @@ public: return asyncDNSServers_; } #endif // HAVE_ARES_ADDR_NODE + +#ifdef ENABLE_WEBSOCKET + void setWebSocketSessionMan + (const SharedHandle& wsman); + const SharedHandle& getWebSocketSessionMan() const + { + return webSocketSessionMan_; + } +#endif // ENABLE_WEBSOCKET }; } // namespace aria2 diff --git a/src/MultiUrlRequestInfo.cc b/src/MultiUrlRequestInfo.cc index eaf2608c..d7723a86 100644 --- a/src/MultiUrlRequestInfo.cc +++ b/src/MultiUrlRequestInfo.cc @@ -133,11 +133,7 @@ int MultiUrlRequestInfo::prepare() { global::globalHaltRequested = 0; try { - SharedHandle wsSessionMan; - if(option_->getAsBool(PREF_ENABLE_RPC)) { - wsSessionMan.reset(new rpc::WebSocketSessionMan()); - } - SharedHandle notifier(new Notifier(wsSessionMan)); + SharedHandle notifier(new Notifier()); SingletonHolder::instance(notifier); #ifdef ENABLE_SSL @@ -166,6 +162,14 @@ int MultiUrlRequestInfo::prepare() // Avoid keeping RequestGroups alive longer than necessary requestGroups_.clear(); + if(option_->getAsBool(PREF_ENABLE_RPC)) { + SharedHandle wsSessionMan + (new rpc::WebSocketSessionMan()); + e_->setWebSocketSessionMan(wsSessionMan); + SingletonHolder::instance()->addDownloadEventListener + (wsSessionMan); + } + if(!option_->blank(PREF_LOAD_COOKIES)) { File cookieFile(option_->get(PREF_LOAD_COOKIES)); if(cookieFile.isFile() && diff --git a/src/Notifier.cc b/src/Notifier.cc index 6d843340..5228e76f 100644 --- a/src/Notifier.cc +++ b/src/Notifier.cc @@ -35,47 +35,25 @@ #include "Notifier.h" #include "RequestGroup.h" #include "LogFactory.h" -#ifdef ENABLE_WEBSOCKET -# include "WebSocketSessionMan.h" -#else // !ENABLE_WEBSOCKET -# include "NullWebSocketSessionMan.h" -#endif // !ENABLE_WEBSOCKET namespace aria2 { -Notifier::Notifier(const SharedHandle& wsSessionMan) - : wsSessionMan_(wsSessionMan) -{} +Notifier::Notifier() {} Notifier::~Notifier() {} -void Notifier::addWebSocketSession -(const SharedHandle& wsSession) +void Notifier::addDownloadEventListener +(const SharedHandle& listener) { - A2_LOG_DEBUG("WebSocket session added."); - wsSessionMan_->addSession(wsSession); + listeners_.push_back(listener); } -void Notifier::removeWebSocketSession -(const SharedHandle& wsSession) -{ - A2_LOG_DEBUG("WebSocket session removed."); - wsSessionMan_->removeSession(wsSession); -} - -const std::string Notifier::ON_DOWNLOAD_START = "aria2.onDownloadStart"; -const std::string Notifier::ON_DOWNLOAD_PAUSE = "aria2.onDownloadPause"; -const std::string Notifier::ON_DOWNLOAD_STOP = "aria2.onDownloadStop"; -const std::string Notifier::ON_DOWNLOAD_COMPLETE = "aria2.onDownloadComplete"; -const std::string Notifier::ON_DOWNLOAD_ERROR = "aria2.onDownloadError"; -const std::string Notifier::ON_BT_DOWNLOAD_COMPLETE = - "aria2.onBtDownloadComplete"; - void Notifier::notifyDownloadEvent -(const std::string& event, const RequestGroup* group) +(DownloadEvent event, const RequestGroup* group) { - if(wsSessionMan_) { - wsSessionMan_->addNotification(event, group); + for(std::vector >::const_iterator i = + listeners_.begin(), eoi = listeners_.end(); i != eoi; ++i) { + (*i)->onEvent(event, group); } } diff --git a/src/Notifier.h b/src/Notifier.h index efc9c225..39787326 100644 --- a/src/Notifier.h +++ b/src/Notifier.h @@ -36,45 +36,37 @@ #define D_NOTIFIER_H #include "common.h" + +#include + +#include #include "SharedHandle.h" namespace aria2 { class RequestGroup; -class Option; -struct Pref; -namespace rpc { - -class WebSocketSessionMan; -class WebSocketSession; - -} // namespace rpc +struct DownloadEventListener { + virtual ~DownloadEventListener() {} + virtual void onEvent(DownloadEvent event, const RequestGroup* group) = 0; +}; class Notifier { public: - // The string constants for download events. - static const std::string ON_DOWNLOAD_START; - static const std::string ON_DOWNLOAD_PAUSE; - static const std::string ON_DOWNLOAD_STOP; - static const std::string ON_DOWNLOAD_COMPLETE; - static const std::string ON_DOWNLOAD_ERROR; - static const std::string ON_BT_DOWNLOAD_COMPLETE; - - Notifier(const SharedHandle& wsSessionMan); + Notifier(); ~Notifier(); - void addWebSocketSession(const SharedHandle& wsSes); - void removeWebSocketSession(const SharedHandle& wsSes); + void addDownloadEventListener + (const SharedHandle& listener); // Notifies the download event to all listeners. - void notifyDownloadEvent(const std::string& event, const RequestGroup* group); + void notifyDownloadEvent(DownloadEvent event, const RequestGroup* group); - void notifyDownloadEvent(const std::string& event, + void notifyDownloadEvent(DownloadEvent event, const SharedHandle& group) { notifyDownloadEvent(event, group.get()); } private: - SharedHandle wsSessionMan_; + std::vector > listeners_; }; } // namespace aria2 diff --git a/src/RequestGroupMan.cc b/src/RequestGroupMan.cc index 54cfe5be..3fdf064f 100644 --- a/src/RequestGroupMan.cc +++ b/src/RequestGroupMan.cc @@ -211,7 +211,7 @@ bool RequestGroupMan::removeReservedGroup(a2_gid_t gid) namespace { void notifyDownloadEvent -(const std::string& event, const SharedHandle& group) +(DownloadEvent event, const SharedHandle& group) { // Check NULL to make unit test easier. if(SingletonHolder::instance()) { @@ -239,12 +239,12 @@ void executeStopHook util::executeHookByOptName(group, option, PREF_ON_DOWNLOAD_STOP); } if(result == error_code::FINISHED) { - notifyDownloadEvent(Notifier::ON_DOWNLOAD_COMPLETE, group); + notifyDownloadEvent(EVENT_ON_DOWNLOAD_COMPLETE, group); } else if(result != error_code::IN_PROGRESS && result != error_code::REMOVED) { - notifyDownloadEvent(Notifier::ON_DOWNLOAD_ERROR, group); + notifyDownloadEvent(EVENT_ON_DOWNLOAD_ERROR, group); } else { - notifyDownloadEvent(Notifier::ON_DOWNLOAD_STOP, group); + notifyDownloadEvent(EVENT_ON_DOWNLOAD_STOP, group); } } @@ -392,7 +392,7 @@ public: group->setForceHaltRequested(false); util::executeHookByOptName(group, e_->getOption(), PREF_ON_DOWNLOAD_PAUSE); - notifyDownloadEvent(Notifier::ON_DOWNLOAD_PAUSE, group); + notifyDownloadEvent(EVENT_ON_DOWNLOAD_PAUSE, group); // TODO Should we have to prepend spend uris to remaining uris // in case PREF_REUSE_URI is disabed? } else { @@ -508,7 +508,7 @@ void RequestGroupMan::fillRequestGroupFromReserver(DownloadEngine* e) util::executeHookByOptName(groupToAdd, e->getOption(), PREF_ON_DOWNLOAD_START); - notifyDownloadEvent(Notifier::ON_DOWNLOAD_START, groupToAdd); + notifyDownloadEvent(EVENT_ON_DOWNLOAD_START, groupToAdd); } if(!pending.empty()) { reservedGroups_.insert(reservedGroups_.begin(), RequestGroupKeyFunc(), @@ -577,7 +577,7 @@ RequestGroupMan::DownloadStat RequestGroupMan::getDownloadStat() const lastError); } -enum DownloadStatus { +enum DownloadResultStatus { A2_STATUS_OK, A2_STATUS_INPR, A2_STATUS_RM, @@ -585,7 +585,7 @@ enum DownloadStatus { }; namespace { -const char* getStatusStr(DownloadStatus status, bool useColor) +const char* getStatusStr(DownloadResultStatus status, bool useColor) { // status string is formatted in 4 characters wide. switch(status) { diff --git a/src/WebSocketInteractionCommand.cc b/src/WebSocketInteractionCommand.cc index 9dccc3c3..a21db84d 100644 --- a/src/WebSocketInteractionCommand.cc +++ b/src/WebSocketInteractionCommand.cc @@ -42,6 +42,7 @@ #include "fmt.h" #include "SingletonHolder.h" #include "Notifier.h" +#include "WebSocketSessionMan.h" namespace aria2 { @@ -58,7 +59,7 @@ WebSocketInteractionCommand::WebSocketInteractionCommand writeCheck_(false), wsSession_(wsSession) { - SingletonHolder::instance()->addWebSocketSession(wsSession_); + e_->getWebSocketSessionMan()->addSession(wsSession_); e_->addSocketForReadCheck(socket_, this); } @@ -68,7 +69,7 @@ WebSocketInteractionCommand::~WebSocketInteractionCommand() if(writeCheck_) { e_->deleteSocketForWriteCheck(socket_, this); } - SingletonHolder::instance()->removeWebSocketSession(wsSession_); + e_->getWebSocketSessionMan()->removeSession(wsSession_); } void WebSocketInteractionCommand::updateWriteCheck() diff --git a/src/WebSocketSessionMan.cc b/src/WebSocketSessionMan.cc index 26771bc4..54c96fac 100644 --- a/src/WebSocketSessionMan.cc +++ b/src/WebSocketSessionMan.cc @@ -38,6 +38,7 @@ #include "json.h" #include "util.h" #include "WebSocketInteractionCommand.h" +#include "LogFactory.h" namespace aria2 { @@ -50,12 +51,14 @@ WebSocketSessionMan::~WebSocketSessionMan() {} void WebSocketSessionMan::addSession (const SharedHandle& wsSession) { + A2_LOG_DEBUG("WebSocket session added."); sessions_.insert(wsSession); } void WebSocketSessionMan::removeSession (const SharedHandle& wsSession) { + A2_LOG_DEBUG("WebSocket session removed."); sessions_.erase(wsSession); } @@ -78,6 +81,48 @@ void WebSocketSessionMan::addNotification } } + +namespace { +// The string constants for download events. +const std::string ON_DOWNLOAD_START = "aria2.onDownloadStart"; +const std::string ON_DOWNLOAD_PAUSE = "aria2.onDownloadPause"; +const std::string ON_DOWNLOAD_STOP = "aria2.onDownloadStop"; +const std::string ON_DOWNLOAD_COMPLETE = "aria2.onDownloadComplete"; +const std::string ON_DOWNLOAD_ERROR = "aria2.onDownloadError"; +const std::string ON_BT_DOWNLOAD_COMPLETE = "aria2.onBtDownloadComplete"; +} // namespace + +namespace { +const std::string& getMethodName(DownloadEvent event) +{ + switch(event) { + case EVENT_ON_DOWNLOAD_START: + return ON_DOWNLOAD_START; + case EVENT_ON_DOWNLOAD_PAUSE: + return ON_DOWNLOAD_PAUSE; + case EVENT_ON_DOWNLOAD_STOP: + return ON_DOWNLOAD_STOP; + case EVENT_ON_DOWNLOAD_COMPLETE: + return ON_DOWNLOAD_COMPLETE; + case EVENT_ON_DOWNLOAD_ERROR: + return ON_DOWNLOAD_ERROR; + case EVENT_ON_BT_DOWNLOAD_COMPLETE: + return ON_BT_DOWNLOAD_COMPLETE; + default: + // Not reachable + assert(0); + // For suppress compiler warning + return A2STR::NIL; + } +} +} // namespace + +void WebSocketSessionMan::onEvent(DownloadEvent event, + const RequestGroup* group) +{ + addNotification(getMethodName(event), group); +} + } // namespace rpc } // namespace aria2 diff --git a/src/WebSocketSessionMan.h b/src/WebSocketSessionMan.h index 8004b485..4b2b5acc 100644 --- a/src/WebSocketSessionMan.h +++ b/src/WebSocketSessionMan.h @@ -35,7 +35,7 @@ #ifndef D_WEB_SOCKET_SESSION_MAN_H #define D_WEB_SOCKET_SESSION_MAN_H -#include "common.h" +#include "Notifier.h" #include #include @@ -51,7 +51,7 @@ namespace rpc { class WebSocketSession; -class WebSocketSessionMan { +class WebSocketSessionMan : public DownloadEventListener { public: typedef std::set, RefLess > WebSocketSessions; @@ -60,6 +60,7 @@ public: void addSession(const SharedHandle& wsSession); void removeSession(const SharedHandle& wsSession); void addNotification(const std::string& method, const RequestGroup* group); + virtual void onEvent(DownloadEvent event, const RequestGroup* group); private: WebSocketSessions sessions_; }; diff --git a/src/includes/aria2/aria2.h b/src/includes/aria2/aria2.h index d0edb520..5671c4ee 100644 --- a/src/includes/aria2/aria2.h +++ b/src/includes/aria2/aria2.h @@ -97,6 +97,39 @@ typedef uint64_t A2Gid; */ typedef std::vector > KeyVals; +/** + * @enum + * + * Download event constants + */ +enum DownloadEvent { + /** + * Indicating download has started. + */ + EVENT_ON_DOWNLOAD_START = 1, + /** + * Indicating download has paused. + */ + EVENT_ON_DOWNLOAD_PAUSE, + /** + * Indicating download has stopped. + */ + EVENT_ON_DOWNLOAD_STOP, + /** + * Indicating download has completed. + */ + EVENT_ON_DOWNLOAD_COMPLETE, + /** + * Indicating download has stopped becauseof the error. + */ + EVENT_ON_DOWNLOAD_ERROR, + /** + * Indicating BitTorrent download has completed, but it may still + * continue to perform seeding. + */ + EVENT_ON_BT_DOWNLOAD_COMPLETE +}; + /** * @struct *