diff --git a/src/ApiCallbackDownloadEventListener.cc b/src/ApiCallbackDownloadEventListener.cc index 5e31e29e..84d54a97 100644 --- a/src/ApiCallbackDownloadEventListener.cc +++ b/src/ApiCallbackDownloadEventListener.cc @@ -34,6 +34,7 @@ /* copyright --> */ #include "ApiCallbackDownloadEventListener.h" #include "RequestGroup.h" +#include "Segment.h" namespace aria2 { @@ -46,9 +47,16 @@ ApiCallbackDownloadEventListener::ApiCallbackDownloadEventListener( ApiCallbackDownloadEventListener::~ApiCallbackDownloadEventListener() = default; void ApiCallbackDownloadEventListener::onEvent(DownloadEvent event, - const RequestGroup* group) + const RequestGroup* group, + const Segment* segment) { - callback_(session_, event, group->getGID(), userData_); + struct SegmentInfo info; + if (segment) { + info.index = segment->getIndex(); + info.position = segment->getPosition(); + info.length = segment->getLength(); + } + callback_(session_, event, group->getGID(), userData_, &info); } } // namespace aria2 diff --git a/src/ApiCallbackDownloadEventListener.h b/src/ApiCallbackDownloadEventListener.h index c7776e1d..5399e03f 100644 --- a/src/ApiCallbackDownloadEventListener.h +++ b/src/ApiCallbackDownloadEventListener.h @@ -46,7 +46,8 @@ public: void* userData); virtual ~ApiCallbackDownloadEventListener(); virtual void onEvent(DownloadEvent event, - const RequestGroup* group) CXX11_OVERRIDE; + const RequestGroup* group, + const Segment* segment = nullptr) CXX11_OVERRIDE; private: Session* session_; diff --git a/src/DownloadContext.cc b/src/DownloadContext.cc index 7f175e26..9d5af880 100644 --- a/src/DownloadContext.cc +++ b/src/DownloadContext.cc @@ -328,4 +328,9 @@ void DownloadContext::updateUploadLength(size_t bytes) } } +void DownloadContext::completedSegment(const std::shared_ptr& segment) const +{ + ownerRequestGroup_->completedSegment(segment); +} + } // namespace aria2 diff --git a/src/DownloadContext.h b/src/DownloadContext.h index 04d55ffe..edf1e99f 100644 --- a/src/DownloadContext.h +++ b/src/DownloadContext.h @@ -54,6 +54,7 @@ namespace aria2 { class RequestGroup; class Signature; class FileEntry; +class Segment; class DownloadContext { private: @@ -233,6 +234,10 @@ public: // RequestGroupMan via getOwnerRequestGroup(). void updateUploadLength(size_t bytes); void updateUploadSpeed(size_t bytes); + + // This method will be called by corresponding SegmentMan + // if a Segment get downloaded + void completedSegment(const std::shared_ptr& segment) const; }; } // namespace aria2 diff --git a/src/Notifier.cc b/src/Notifier.cc index d4becd23..302c2598 100644 --- a/src/Notifier.cc +++ b/src/Notifier.cc @@ -48,10 +48,11 @@ void Notifier::addDownloadEventListener(DownloadEventListener* listener) } void Notifier::notifyDownloadEvent(DownloadEvent event, - const RequestGroup* group) + const RequestGroup* group, + const Segment* segment) { for (auto listener : listeners_) { - listener->onEvent(event, group); + listener->onEvent(event, group, segment); } } diff --git a/src/Notifier.h b/src/Notifier.h index b3065209..bd5c1494 100644 --- a/src/Notifier.h +++ b/src/Notifier.h @@ -45,25 +45,38 @@ namespace aria2 { class RequestGroup; +class Segment; struct DownloadEventListener { virtual ~DownloadEventListener() = default; - virtual void onEvent(DownloadEvent event, const RequestGroup* group) = 0; + virtual void onEvent(DownloadEvent event, + const RequestGroup* group, + const Segment* segment = nullptr) = 0; }; class Notifier { public: Notifier(); ~Notifier(); + void addDownloadEventListener(DownloadEventListener* listener); // Notifies the download event to all listeners. - void notifyDownloadEvent(DownloadEvent event, const RequestGroup* group); + void notifyDownloadEvent(DownloadEvent event, + const RequestGroup* group, + const Segment* segment=nullptr); void notifyDownloadEvent(DownloadEvent event, const std::shared_ptr& group) { notifyDownloadEvent(event, group.get()); } + + void notifyDownloadSegmentEvent(DownloadEvent event, + const std::shared_ptr& group, + const std::shared_ptr& segment) + { + notifyDownloadEvent(event, group.get(), segment.get()); + } private: std::vector listeners_; diff --git a/src/RequestGroup.cc b/src/RequestGroup.cc index fd6801fc..cb4434df 100644 --- a/src/RequestGroup.cc +++ b/src/RequestGroup.cc @@ -882,6 +882,11 @@ void RequestGroup::createNextCommand( } } +void RequestGroup::completedSegment(const std::shared_ptr& segment) const +{ + requestGroupMan_->completedSegment(requestGroupMan_->findGroup(this->gid_->getNumericId()), segment); +} + std::string RequestGroup::getFirstFilePath() const { assert(downloadContext_); diff --git a/src/RequestGroup.h b/src/RequestGroup.h index 6698f93d..524c7902 100644 --- a/src/RequestGroup.h +++ b/src/RequestGroup.h @@ -70,6 +70,7 @@ struct DownloadResult; class URISelector; class URIResult; class RequestGroupMan; +class Segment; #ifdef ENABLE_BITTORRENT class BtRuntime; class PeerStorage; @@ -240,6 +241,10 @@ public: void createNextCommand(std::vector>& commands, DownloadEngine* e); + + // This method will be called by corresponding DownloadContext + // if a Segment get downloaded + void completedSegment(const std::shared_ptr& segment) const; bool downloadFinished() const; diff --git a/src/RequestGroupMan.cc b/src/RequestGroupMan.cc index 425351bb..9ecfe8ff 100644 --- a/src/RequestGroupMan.cc +++ b/src/RequestGroupMan.cc @@ -248,6 +248,16 @@ void notifyDownloadEvent(DownloadEvent event, } } +void notifyDownloadSegmentEvent(DownloadEvent event, + const std::shared_ptr& group, + const std::shared_ptr& segment) +{ + // Check NULL to make unit test easier. + if (SingletonHolder::instance()) { + SingletonHolder::instance()->notifyDownloadSegmentEvent(event, group, segment); + } +} + } // namespace namespace { @@ -1112,4 +1122,11 @@ int RequestGroupMan::optimizeConcurrentDownloads() return maxConcurrentDownloads; } + +void RequestGroupMan::completedSegment(const std::shared_ptr& group, + const std::shared_ptr& segment) const +{ + notifyDownloadSegmentEvent(EVENT_ON_SEGMENT_COMPLETE, group, segment); +} + } // namespace aria2 diff --git a/src/RequestGroupMan.h b/src/RequestGroupMan.h index b8aa8d4f..8cc80571 100644 --- a/src/RequestGroupMan.h +++ b/src/RequestGroupMan.h @@ -61,6 +61,7 @@ class OutputFile; class UriListParser; class WrDiskCache; class OpenedFileCounter; +class Segment; typedef IndexedList> RequestGroupList; typedef IndexedList> @@ -213,6 +214,11 @@ public: } bool setupOptimizeConcurrentDownloads(); + + // This method will be called by corresponding RequestGroup + // if a segment get downloaded + void completedSegment(const std::shared_ptr& group, + const std::shared_ptr& segment) const; void showDownloadResults(OutputFile& o, bool full) const; diff --git a/src/SegmentMan.cc b/src/SegmentMan.cc index 1e7acf93..cdc82cc9 100644 --- a/src/SegmentMan.cc +++ b/src/SegmentMan.cc @@ -376,6 +376,7 @@ bool SegmentMan::completeSegment(cuid_t cuid, pieceStorage_->completePiece(segment->getPiece()); pieceStorage_->advertisePiece(cuid, segment->getPiece()->getIndex(), global::wallclock()); + downloadContext_->completedSegment(segment); auto itr = std::find_if(usedSegmentEntries_.begin(), usedSegmentEntries_.end(), FindSegmentEntry(segment)); if (itr == usedSegmentEntries_.end()) { diff --git a/src/WebSocketSessionMan.cc b/src/WebSocketSessionMan.cc index 5e4e3384..4a1ec8cd 100644 --- a/src/WebSocketSessionMan.cc +++ b/src/WebSocketSessionMan.cc @@ -66,7 +66,8 @@ void WebSocketSessionMan::removeSession( } void WebSocketSessionMan::addNotification(const std::string& method, - const RequestGroup* group) + const RequestGroup* group, + const Segment* segment) { auto dict = Dict::g(); dict->put("jsonrpc", "2.0"); @@ -89,6 +90,7 @@ 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_SEGMENT_COMPLETE = "aria2.onSegmentComplete"; const std::string ON_DOWNLOAD_ERROR = "aria2.onDownloadError"; const std::string ON_BT_DOWNLOAD_COMPLETE = "aria2.onBtDownloadComplete"; } // namespace @@ -105,6 +107,8 @@ const std::string& getMethodName(DownloadEvent event) return ON_DOWNLOAD_STOP; case EVENT_ON_DOWNLOAD_COMPLETE: return ON_DOWNLOAD_COMPLETE; + case EVENT_ON_SEGMENT_COMPLETE: + return ON_SEGMENT_COMPLETE; case EVENT_ON_DOWNLOAD_ERROR: return ON_DOWNLOAD_ERROR; case EVENT_ON_BT_DOWNLOAD_COMPLETE: @@ -119,9 +123,10 @@ const std::string& getMethodName(DownloadEvent event) } // namespace void WebSocketSessionMan::onEvent(DownloadEvent event, - const RequestGroup* group) + const RequestGroup* group, + const Segment* segment) { - addNotification(getMethodName(event), group); + addNotification(getMethodName(event), group, segment); } } // namespace rpc diff --git a/src/WebSocketSessionMan.h b/src/WebSocketSessionMan.h index c3f3a071..0d83a937 100644 --- a/src/WebSocketSessionMan.h +++ b/src/WebSocketSessionMan.h @@ -59,9 +59,12 @@ public: ~WebSocketSessionMan(); void addSession(const std::shared_ptr& wsSession); void removeSession(const std::shared_ptr& wsSession); - void addNotification(const std::string& method, const RequestGroup* group); + void addNotification(const std::string& method, + const RequestGroup* group, + const Segment* segment = nullptr); virtual void onEvent(DownloadEvent event, - const RequestGroup* group) CXX11_OVERRIDE; + const RequestGroup* group, + const Segment* segment = nullptr) CXX11_OVERRIDE; private: WebSocketSessions sessions_; diff --git a/src/includes/aria2/aria2.h b/src/includes/aria2/aria2.h index c704a64c..92e11ede 100644 --- a/src/includes/aria2/aria2.h +++ b/src/includes/aria2/aria2.h @@ -119,6 +119,10 @@ enum DownloadEvent { * Indicating download has completed. */ EVENT_ON_DOWNLOAD_COMPLETE, + /** + * Indicating a segment has completed. + */ + EVENT_ON_SEGMENT_COMPLETE, /** * Indicating download has stopped because of the error. */ @@ -130,6 +134,29 @@ enum DownloadEvent { EVENT_ON_BT_DOWNLOAD_COMPLETE }; +/** + * @struct + * + * The segment information. + */ +struct SegmentInfo { + /** + * The index of a piece. + * The default value is ``0``. + */ + size_t index; + /** + * Specify the beginning offset of file. + * The default value is ``0``. + */ + int64_t position; + /** + * Specify number of bytes containing in the segment. + * The default value is ``0``. + */ + int64_t length; +}; + /** * @functypedef * @@ -138,12 +165,15 @@ enum DownloadEvent { * |gid| refers to the download which this event was fired on. The * |userData| is a pointer specified in * :member:`SessionConfig::userData`. + * |segmentInfo| will be non-default values if the event + * is `aria2::EVENT_ON_SEGMENT_COMPLETE`. * * At the moment, the return value is ignored, but the implementation * of this callback should return 0 for compatibility. */ typedef int (*DownloadEventCallback)(Session* session, DownloadEvent event, - A2Gid gid, void* userData); + A2Gid gid, void* userData, + SegmentInfo* segmentInfo); /** * @struct