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 *