depot_download: produce 'state' report

The state report reflects the progress of downloading, verifying, and
extracting archives. For the download step, it includes the progress
as reported by fetchurl.
This commit is contained in:
Norman Feske 2018-05-19 17:52:48 +02:00 committed by Christian Helmuth
parent a529a35ce6
commit c21e5863b9
4 changed files with 109 additions and 14 deletions

View File

@ -32,6 +32,8 @@
report="dynamic -> state"/>
<policy label="manager -> verified"
report="dynamic -> verify -> result"/>
<policy label="manager -> fetchurl_progress"
report="dynamic -> fetchurl -> progress"/>
</config>
</start>
@ -81,11 +83,13 @@
<resource name="RAM" quantum="1M"/>
<config/>
<route>
<service name="Report" label="state"> <parent label="state"/> </service>
<service name="Report"> <child name="report_rom"/> </service>
<service name="ROM" label="dependencies"> <child name="report_rom"/> </service>
<service name="ROM" label="user"> <child name="report_rom"/> </service>
<service name="ROM" label="init_state"> <child name="report_rom"/> </service>
<service name="ROM" label="verified"> <child name="report_rom"/> </service>
<service name="ROM" label="dependencies"> <child name="report_rom"/> </service>
<service name="ROM" label="user"> <child name="report_rom"/> </service>
<service name="ROM" label="init_state"> <child name="report_rom"/> </service>
<service name="ROM" label="verified"> <child name="report_rom"/> </service>
<service name="ROM" label="fetchurl_progress"> <child name="report_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
@ -95,7 +99,6 @@
<binary name="init"/>
<route>
<service name="ROM" label="config"> <child name="report_rom"/> </service>
<service name="Report" label="fetchurl -> progress"> <parent/> </service>
<service name="Report"> <child name="report_rom"/> </service>
<service name="File_system" label="depot"> <child name="depot_ro"/> </service>
<service name="File_system" label="depot_rw"> <parent label="depot"/> </service>

View File

@ -102,6 +102,7 @@ append config {
<route>
<service name="ROM" label="config">
<parent label="depot_download.config"/> </service>
<service name="Report"> <child name="report_rom"/> </service>
<service name="File_system"> <child name="vfs"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>

View File

@ -16,6 +16,7 @@
/* Genode includes */
#include <util/xml_node.h>
#include <util/xml_generator.h>
#include <base/registry.h>
#include <base/allocator.h>
@ -29,6 +30,22 @@ namespace Depot_download_manager {
class Depot_download_manager::Import
{
public:
/**
* Interface for obtaining the download progress for a given archive
*/
struct Download_progress : Interface
{
struct Info
{
typedef String<32> Bytes;
Bytes total, now;
};
virtual Info download_progress(Archive::Path const &) const = 0;
};
private:
struct Item
@ -49,6 +66,18 @@ class Depot_download_manager::Import
:
_element(registry, *this), path(path)
{ }
char const *state_text() const
{
switch (state) {
case DOWNLOAD_IN_PROGRESS: return "download";
case DOWNLOAD_COMPLETE: return "verify";
case VERIFIED: return "extract";
case VERIFICATION_FAILED: return "verification failed";
case UNPACKED: return "done";
};
return "";
}
};
Allocator &_alloc;
@ -171,6 +200,23 @@ class Depot_download_manager::Import
if (item.state == Item::VERIFIED)
item.state = Item::UNPACKED; });
}
void report(Xml_generator &xml, Download_progress const &progress) const
{
_items.for_each([&] (Item const &item) {
xml.node("archive", [&] () {
xml.attribute("path", item.path);
xml.attribute("state", item.state_text());
if (item.state == Item::DOWNLOAD_IN_PROGRESS) {
Download_progress::Info const info =
progress.download_progress(item.path);
xml.attribute("total", info.total);
xml.attribute("now", info.now);
}
});
});
}
};
#endif /* _IMPORT_H_ */

View File

@ -50,15 +50,16 @@ struct Depot_download_manager::Child_exit_state
};
struct Depot_download_manager::Main
struct Depot_download_manager::Main : Import::Download_progress
{
Env &_env;
Heap _heap { _env.ram(), _env.rm() };
Attached_rom_dataspace _installation { _env, "installation" };
Attached_rom_dataspace _dependencies { _env, "dependencies" };
Attached_rom_dataspace _init_state { _env, "init_state" };
Attached_rom_dataspace _installation { _env, "installation" };
Attached_rom_dataspace _dependencies { _env, "dependencies" };
Attached_rom_dataspace _init_state { _env, "init_state" };
Attached_rom_dataspace _fetchurl_progress { _env, "fetchurl_progress" };
/**
* User identity, from which current downloads are fetched
@ -89,6 +90,8 @@ struct Depot_download_manager::Main
Expanding_reporter _init_config { _env, "config", "init_config" };
Expanding_reporter _state_reporter { _env, "state", "state" };
/**
* Version counters, used to enforce the restart or reconfiguration of
* components.
@ -100,6 +103,32 @@ struct Depot_download_manager::Main
Constructible<Import> _import { };
/**
* Download_progress interface
*/
Info download_progress(Archive::Path const &path) const
{
Info result { Info::Bytes(), Info::Bytes() };
try {
Url const url_path(_current_user_url(), "/", path, ".tar.xz");
/* search fetchurl progress report for matching 'url_path' */
_fetchurl_progress.xml().for_each_sub_node("fetch", [&] (Xml_node fetch) {
if (fetch.attribute_value("url", Url()) == url_path)
result = { .total = fetch.attribute_value("total", Info::Bytes()),
.now = fetch.attribute_value("now", Info::Bytes()) }; });
} catch (Invalid_download_url) { }
return result;
}
void _update_state_report()
{
_state_reporter.generate([&] (Xml_generator &xml) {
if (_import.constructed())
_import->report(xml, *this); });
}
void _generate_init_config(Xml_generator &);
void _generate_init_config()
@ -127,13 +156,23 @@ struct Depot_download_manager::Main
void _handle_init_state();
Signal_handler<Main> _fetchurl_progress_handler {
_env.ep(), *this, &Main::_handle_fetchurl_progress };
void _handle_fetchurl_progress()
{
_fetchurl_progress.update();
_update_state_report();
}
Main(Env &env) : _env(env)
{
_dependencies.sigh(_query_result_handler);
_current_user.sigh(_query_result_handler);
_init_state .sigh(_init_state_handler);
_verified .sigh(_init_state_handler);
_installation.sigh(_installation_handler);
_dependencies .sigh(_query_result_handler);
_current_user .sigh(_query_result_handler);
_init_state .sigh(_init_state_handler);
_verified .sigh(_init_state_handler);
_installation .sigh(_installation_handler);
_fetchurl_progress.sigh(_fetchurl_progress_handler);
_generate_init_config();
}
@ -225,6 +264,7 @@ void Depot_download_manager::Main::_handle_query_result()
if (!dependencies.has_sub_node("missing")) {
log("installation complete.");
_update_state_report();
return;
}
@ -241,6 +281,7 @@ void Depot_download_manager::Main::_handle_query_result()
/* start new import */
_import.construct(_heap, _current_user_name(), _dependencies.xml());
_update_state_report();
/* spawn fetchurl */
_generate_init_config();
@ -324,6 +365,10 @@ void Depot_download_manager::Main::_handle_init_state()
}
}
/* report before destructing '_import' to avoid empty intermediate reports */
if (reconfigure_init)
_update_state_report();
if (import_finished)
_import.destruct();