Repository navigation
Expand file tree
/
Copy pathresource_loader.cpp
More file actions
93 lines (83 loc) · 3.32 KB
/
Copy pathresource_loader.cpp
File metadata and controls
93 lines (83 loc) · 3.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include "resource_loader.hpp"
#include <regex>
namespace aetheris::rendering {
ResourceLoader::ResourceLoader(ResourceCache& cache, Fetcher fetcher)
: m_cache(cache)
, m_fetcher(std::move(fetcher))
{
}
ResourceLoader::ResourceLoader(ResourceCache& cache, std::vector<std::shared_ptr<ResourceBackend>> backends)
: m_cache(cache)
, m_backends(std::move(backends))
{
}
void ResourceLoader::add_backend(std::shared_ptr<ResourceBackend> backend)
{
if (backend)
m_backends.push_back(std::move(backend));
}
ResourceLoadResult ResourceLoader::load(Url const& url)
{
if (!url.is_valid())
return { ResourceLoadState::Failed, nullptr, "Invalid resource URL" };
if (auto cached = m_cache.get(url.serialized()))
return { ResourceLoadState::Ready, std::move(cached), {} };
if (m_fetcher) {
auto fetched = m_fetcher(url);
if (fetched) {
if (fetched->url.empty())
fetched->url = url.serialized();
if (fetched->url != url.serialized())
return { ResourceLoadState::Failed, nullptr, "Loaded resource URL does not match request" };
m_cache.put(std::move(*fetched));
return { ResourceLoadState::Ready, m_cache.get(url.serialized()), {} };
}
}
bool supported = false;
std::string failure;
for (auto const& backend : m_backends) {
if (!backend || !backend->supports(url))
continue;
supported = true;
auto result = backend->load(url);
if (result.succeeded()) {
auto fetched = std::move(*result.resource);
if (fetched.url.empty())
fetched.url = url.serialized();
if (fetched.url != url.serialized())
return { ResourceLoadState::Failed, nullptr, "Loaded resource URL does not match request" };
m_cache.put(std::move(fetched));
return { ResourceLoadState::Ready, m_cache.get(url.serialized()), {} };
}
if (!result.message.empty())
failure = std::move(result.message);
}
if (!supported)
return { ResourceLoadState::Missing, nullptr, "Resource is not cached and no backend supports the URL" };
return { ResourceLoadState::Missing, nullptr, failure.empty() ? "Resource backend did not provide the requested resource" : failure };
}
ResourceLoadResult ResourceLoader::load(ResourceType expected_type, Url const& url)
{
auto result = load(url);
if (!result.succeeded())
return result;
if (result.resource->type != expected_type)
return { ResourceLoadState::Failed, nullptr, "Loaded resource has an unexpected type" };
return result;
}
std::vector<Url> ResourceLoader::discover_dependencies(ResourceData const& document, Url const& base_url) const
{
std::vector<Url> urls;
if (document.type != ResourceType::Document)
return urls;
auto text = std::string(document.bytes.begin(), document.bytes.end());
std::regex pattern(R"((?:href|src)\s*=\s*[\"']([^\"']+)[\"'])", std::regex::icase);
for (std::sregex_iterator it(text.begin(), text.end(), pattern), end; it != end; ++it) {
auto raw = (*it)[1].str();
auto resolved = Url::resolve(base_url, raw);
if (resolved.is_valid())
urls.push_back(std::move(resolved));
}
return urls;
}
} // namespace aetheris::rendering