feat: add production-like particle field feed
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#include <mbgl/style/sources/raster_array_source.hpp>
|
||||
|
||||
#include <mbgl/particle/field/offline_fixture_particle_adapter.hpp>
|
||||
#include <mbgl/particle/field/local_particle_field_feed.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/storage/resource.hpp>
|
||||
#include <mbgl/style/source_observer.hpp>
|
||||
@@ -203,6 +204,9 @@ RasterArraySource::RasterArraySource(std::string id,
|
||||
std::move(nextFieldURL),
|
||||
std::move(runtimeFields))) {}
|
||||
|
||||
RasterArraySource::RasterArraySource(std::string id, std::vector<RasterArrayLocalFieldDescriptor> localFields)
|
||||
: Source(makeMutable<Impl>(std::move(id), std::move(localFields))) {}
|
||||
|
||||
RasterArraySource::~RasterArraySource() {
|
||||
weakFactory.invalidateWeakPtrs();
|
||||
}
|
||||
@@ -213,6 +217,39 @@ const RasterArraySource::Impl& RasterArraySource::impl() const {
|
||||
|
||||
void RasterArraySource::loadDescription(FileSource& fileSource) {
|
||||
if (metadataRequest || fieldRequest) return;
|
||||
if (!impl().localFields.empty()) {
|
||||
localFields.reserve(impl().localFields.size());
|
||||
for (const auto& descriptor : impl().localFields) {
|
||||
LocalFieldCandidate candidate;
|
||||
candidate.descriptor = descriptor;
|
||||
localFields.push_back(std::move(candidate));
|
||||
const auto index = localFields.size() - 1;
|
||||
auto& local = localFields.back();
|
||||
local.metadataRequest = fileSource.request(Resource::source(local.descriptor.metadataURL),
|
||||
[this, self = makeWeakPtr(), index](const Response& response) {
|
||||
if (auto guard = self.lock(); self) {
|
||||
if (response.error || response.noContent || !response.data) {
|
||||
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("particle local metadata request failed")));
|
||||
return;
|
||||
}
|
||||
localFields[index].metadata = *response.data;
|
||||
tryLoadLocalField(index);
|
||||
}
|
||||
});
|
||||
local.fieldRequest = fileSource.request(Resource::source(local.descriptor.fieldURL),
|
||||
[this, self = makeWeakPtr(), index](const Response& response) {
|
||||
if (auto guard = self.lock(); self) {
|
||||
if (response.error || response.noContent || !response.data) {
|
||||
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error("particle local field request failed")));
|
||||
return;
|
||||
}
|
||||
localFields[index].fieldBytes = std::vector<char>(response.data->begin(), response.data->end());
|
||||
tryLoadLocalField(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
metadataRequest = fileSource.request(
|
||||
Resource::source(impl().metadataURL), [this, self = makeWeakPtr()](const Response& response) {
|
||||
if (auto guard = self.lock(); self) {
|
||||
@@ -371,17 +408,68 @@ void RasterArraySource::tryLoadRuntimeField(const size_t index) {
|
||||
}
|
||||
}
|
||||
|
||||
void RasterArraySource::tryLoadLocalField(const size_t index) {
|
||||
auto& candidate = localFields.at(index);
|
||||
if (candidate.snapshot || !candidate.metadata || !candidate.fieldBytes) return;
|
||||
const auto result = particle::LocalParticleFieldFeed::load(*candidate.metadata, *candidate.fieldBytes);
|
||||
if (!result) {
|
||||
const auto fieldID = candidate.metadata->find("fieldId") == std::string::npos ? "" : "metadata";
|
||||
Log::Warning(Event::Render, "ParticleField: event=ADAPTER_REJECTED sourceId=" + getID() +
|
||||
" errorCode=" + particle::particleFieldAdapterErrorName(result.error) +
|
||||
" fieldId=" + fieldID + " payloadBytes=" + std::to_string(candidate.fieldBytes->size()) +
|
||||
" error=" + result.message);
|
||||
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(result.message)));
|
||||
return;
|
||||
}
|
||||
candidate.snapshot = std::move(*result.snapshot);
|
||||
Log::Info(Event::Render, "ParticleField: event=PRODUCTION_FEED_LOAD fieldId=" + candidate.snapshot->fieldID +
|
||||
" generation=" + std::to_string(candidate.snapshot->generation) +
|
||||
" validTime=" + std::to_string(candidate.snapshot->validTime) +
|
||||
" payloadBytes=" + std::to_string(candidate.fieldBytes->size()));
|
||||
tryInitializeTimeline();
|
||||
}
|
||||
|
||||
void RasterArraySource::tryInitializeTimeline() {
|
||||
if (timeline || !loaded || !impl().field || !impl().nextField || runtimeFields.empty()) return;
|
||||
if (timeline) return;
|
||||
if (!impl().localFields.empty()) {
|
||||
if (localFields.size() != impl().localFields.size() || localFields.size() < 2) return;
|
||||
for (const auto& candidate : localFields) if (!candidate.snapshot) return;
|
||||
std::vector<RasterArrayTimelineRuntime::Entry> entries;
|
||||
entries.reserve(localFields.size());
|
||||
for (const auto& candidate : localFields) {
|
||||
entries.push_back({std::make_shared<particle::ParticleFieldSnapshot>(*candidate.snapshot), candidate.snapshot->validTime});
|
||||
}
|
||||
try {
|
||||
if (submitInitialRuntimeFieldWindow(*localFields[0].snapshot, *localFields[1].snapshot) !=
|
||||
RasterArrayRuntimeFieldUpdateResult::Applied) {
|
||||
return;
|
||||
}
|
||||
timeline = std::make_shared<RasterArrayTimelineRuntime>(std::move(entries));
|
||||
auto updated = makeMutable<Impl>(impl());
|
||||
updated->timeline = timeline;
|
||||
baseImpl = std::move(updated);
|
||||
loaded = true;
|
||||
Log::Info(Event::Render, "ParticleTimeline: event=READY snapshots=" + std::to_string(localFields.size()));
|
||||
observer->onSourceLoaded(*this);
|
||||
observer->onSourceChanged(*this);
|
||||
} catch (const std::exception& error) {
|
||||
observer->onSourceError(*this, std::make_exception_ptr(std::runtime_error(error.what())));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!loaded || !impl().field || !impl().nextField || runtimeFields.empty()) return;
|
||||
std::vector<RasterArrayTimelineRuntime::Entry> entries;
|
||||
entries.reserve(runtimeFields.size() + 2);
|
||||
entries.push_back({std::make_shared<particle::ParticleFieldSnapshot>(*impl().field), 0});
|
||||
entries.push_back({std::make_shared<particle::ParticleFieldSnapshot>(*impl().nextField), 40000});
|
||||
entries.push_back({std::make_shared<particle::ParticleFieldSnapshot>(*impl().field),
|
||||
impl().field->validTime ? impl().field->validTime : 0});
|
||||
entries.push_back({std::make_shared<particle::ParticleFieldSnapshot>(*impl().nextField),
|
||||
impl().nextField->validTime ? impl().nextField->validTime : 40000});
|
||||
for (size_t index = 0; index < runtimeFields.size(); ++index) {
|
||||
if (!runtimeFields[index].snapshot) return;
|
||||
auto field = *runtimeFields[index].snapshot;
|
||||
entries.push_back({std::make_shared<particle::ParticleFieldSnapshot>(std::move(field)),
|
||||
80000 + static_cast<uint64_t>(index) * 40000});
|
||||
runtimeFields[index].descriptor.timestamp ? runtimeFields[index].descriptor.timestamp
|
||||
: 80000 + static_cast<uint64_t>(index) * 40000});
|
||||
}
|
||||
try {
|
||||
timeline = std::make_shared<RasterArrayTimelineRuntime>(std::move(entries));
|
||||
@@ -403,6 +491,19 @@ void RasterArraySource::tryInitializeTimeline() {
|
||||
}
|
||||
}
|
||||
|
||||
RasterArrayRuntimeFieldUpdateResult RasterArraySource::submitInitialRuntimeFieldWindow(
|
||||
particle::ParticleFieldSnapshot t0, particle::ParticleFieldSnapshot t1) {
|
||||
if (loaded || !t0.isValid() || !t1.isValid() || t0.generation == 0 || t1.generation == 0 ||
|
||||
t0.validTime >= t1.validTime || !t0.isTimeInterpolationCompatibleWith(t1)) {
|
||||
return rejectRuntimeFieldUpdate(RasterArrayRuntimeFieldUpdateResult::RejectedInvalidSnapshot,
|
||||
"INVALID_INITIAL_WINDOW");
|
||||
}
|
||||
baseImpl = makeMutable<Impl>(impl(), std::move(t0), std::move(t1));
|
||||
loaded = true;
|
||||
Log::Info(Event::Render, "ParticleField: event=SNAPSHOT_SUBMIT kind=INITIAL_T0_T1");
|
||||
return RasterArrayRuntimeFieldUpdateResult::Applied;
|
||||
}
|
||||
|
||||
RasterArrayRuntimeFieldUpdateResult RasterArraySource::rejectRuntimeFieldUpdate(
|
||||
const RasterArrayRuntimeFieldUpdateResult result, const std::string& reason) const {
|
||||
Log::Warning(Event::Render,
|
||||
|
||||
Reference in New Issue
Block a user