惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
Jina AI
Jina AI
WordPress大学
WordPress大学
Recent Announcements
Recent Announcements
G
Google Developers Blog
I
InfoQ
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Google DeepMind News
Google DeepMind News
P
Proofpoint News Feed
MyScale Blog
MyScale Blog
M
MIT News - Artificial intelligence
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
C
Check Point Blog
J
Java Code Geeks
T
Tailwind CSS Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Microsoft Security Blog
Microsoft Security Blog
MongoDB | Blog
MongoDB | Blog
V
Visual Studio Blog
人人都是产品经理
人人都是产品经理
量子位
A
About on SuperTechFans
D
DataBreaches.Net
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知

博客园 - Bigben

foobar2000 sacd 和 生成文件名参考 windows激活 文本生成扩散模型示例/教学项目 从零开始构建一个基于Gemini 3的AI智能体 正则表达式笔记 chromium Profiling 浏览器设置非隐身模式 香港高级音响展下载 2004-2024 香港高级视听展原音精选SACD 下载 博文阅读密码验证 - 博客园 博文阅读密码验证 - 博客园 小米刷机,降级,从14降到12.0.11触摸没反应又刷成12.5.6可以 c++协程原理刨析(asyncio 代码解析 c++20协程 网络库实现 coroutine) c代码自动生成类图 uml understand 对 uri分析获取mime type和 raw data chrome headless启动 Image decoding on the web skia 中一个消息机制,单例的实现 SkMessageBus canvaskit.js 生成的 博文阅读密码验证 - 博客园
download功能的下载注册与cdp 监听 Observer模式的很好示范
Bigben · 2024-01-12 · via 博客园 - Bigben

1,DownloadItem中定义Observer,在BrowserHandler中实现

// One DownloadItem per download. This is the model class that stores all the
// state for a download.
class COMPONENTS_DOWNLOAD_EXPORT DownloadItem : public base::SupportsUserData {
 public:

  // Callback used with AcquireFileAndDeleteDownload().
  using AcquireFileCallback = base::OnceCallback<void(const base::FilePath&)>;
  using RenameDownloadCallback = base::OnceCallback<void(DownloadRenameResult)>;
............
  // Interface that observers of a particular download must implement in order
  // to receive updates to the download's status.
  class COMPONENTS_DOWNLOAD_EXPORT Observer : public base::CheckedObserver {
   public:
    virtual void OnDownloadUpdated(DownloadItem* download) {}
    virtual void OnDownloadOpened(DownloadItem* download) {}
    virtual void OnDownloadRemoved(DownloadItem* download) {}

    // Called when the download is being destroyed. This happens after
    // every OnDownloadRemoved() as well as when the DownloadManager is going
    // down.
    virtual void OnDownloadDestroyed(DownloadItem* download) {}

    ~Observer() override;
  };
.......

什么时候调用 AddObserver(browserHandler), 用如下代码

item->AddObserver(this);

void BrowserHandler::DownloadWillBegin(FrameTreeNode* ftn,
                                       download::DownloadItem* item) {
  if (!download_events_enabled_)
    return;
  const std::u16string likely_filename = net::GetSuggestedFilename(
      item->GetURL(), item->GetContentDisposition(), std::string(),
      item->GetSuggestedFilename(), item->GetMimeType(), "download");

  frontend_->DownloadWillBegin(
      ftn->current_frame_host()->devtools_frame_token().ToString(),
      item->GetGuid(), item->GetURL().spec(),
      base::UTF16ToUTF8(likely_filename));
  item->AddObserver(this);//========================
  pending_downloads_.insert(item);
}

来自:
void WillBeginDownload(download::DownloadCreateInfo* info,
                       download::DownloadItem* item) {
  if (!item) {
    return;
  }
  auto* rfh = static_cast<RenderFrameHostImpl*>(
      RenderFrameHost::FromID(info->render_process_id, info->render_frame_id));
  FrameTreeNode* ftn =
      rfh ? FrameTreeNode::GloballyFindByID(rfh->GetFrameTreeNodeId())
          : nullptr;
  if (!ftn) {
    return;
  }
  DispatchToAgents(ftn, &protocol::BrowserHandler::DownloadWillBegin, ftn,
                   item);
  DispatchToAgents(ftn, &protocol::PageHandler::DownloadWillBegin, ftn, item);

  for (auto* agent_host : BrowserDevToolsAgentHost::Instances()) {
    for (auto* browser_handler :
         protocol::BrowserHandler::ForAgentHost(agent_host)) {
      browser_handler->DownloadWillBegin(ftn, item);//========================
    }
  }
}
/////////////////////////////////////////////////////////////////////////////

从上面可以看到,对browserHandler的对象获取是通过 RenderFrameHost::FromID(info->render_process_id, info->render_frame_id));实现的。 

2, 在 DownloadItemImpl 中存放着 observers

头文件中放着方法:components/download/public/common/download_item.h;DownloadItemImpl 实现了它们

3,更新下载进度条

void DownloadItemImpl::UpdateObservers() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DVLOG(20) << __func__ << "()";

  // Nested updates should not be allowed.
  DCHECK(!is_updating_observers_);

  is_updating_observers_ = true;
  for (auto& observer : observers_)
    observer.OnDownloadUpdated(this);
  is_updating_observers_ = false;
}

3.1 谁调用这个 UpdateObservers,应该是下载管理器。

 初始化时注册进那个实现接口的类 BrowserHandler 。在下载管理器知道进度更新时调用 UpdateObservers。

3.2 谁实现这个observer的 OnDownloadUpdate,应该是CDP的browser_handler .

注意这个browser_handler 是在browser进程的content层实现:src\content\browser\devtools\protocol\browser_handler.h

而非 chrome\browser\devtools\protocol\browser_handler.h chrome浏览器的实现;或者headless浏览器的实现 headless\lib\browser\protocol\browser_handler.h

BrowserHandler 确实实现了我们上面的观察者接口: download::DownloadItem::Observer

class BrowserHandler : public DevToolsDomainHandler,
                       public Browser::Backend,
                       public download::DownloadItem::Observer {

.......

  // DownloadItem::Observer overrides
  void OnDownloadUpdated(download::DownloadItem* item) override;
  void OnDownloadDestroyed(download::DownloadItem* item) override;

}

具体实现:

void BrowserHandler::OnDownloadUpdated(download::DownloadItem* item) {
  std::string state;

  switch (item->GetState()) {
    case download::DownloadItem::IN_PROGRESS:
      state = Browser::DownloadProgress::StateEnum::InProgress;
      break;
    case download::DownloadItem::COMPLETE:
      state = Browser::DownloadProgress::StateEnum::Completed;
      break;
    case download::DownloadItem::CANCELLED:
    case download::DownloadItem::INTERRUPTED:
      state = Browser::DownloadProgress::StateEnum::Canceled;

      break;
    case download::DownloadItem::MAX_DOWNLOAD_STATE:
      NOTREACHED();
  }

  frontend_->DownloadProgress(item->GetGuid(), item->GetTotalBytes(),
                              item->GetReceivedBytes(), state);
  if (state != Browser::DownloadProgress::StateEnum::InProgress) {
    item->RemoveObserver(this);
    pending_downloads_.erase(item);
  }

}