The `RetrievedMaps` struct captures the image and its metadata:
the last modification time and the base timestamp for the maps.
* No longer store the last modification time, called "stamp" before,
separately in the `Maps` struct
* Update methods on `Maps` to use the `RetrievedMaps` structs and
the timestamp base in particular for sampling and map marking
* Update the `MapsRefresh` implemention to use the last modification
time
* Rename some variables from `map` to `image` in the helper functions
for consistency
* Update tests and documentation
This way we can build Rockets from outside the crate and run benchmarks,
for example.
* Add top-level `setup()` function to create a Rocket and set up the
maps refresher task
* Change the type of `maps::run` since `!` is still an unstable type
* Fix HTTP code blocks in `README.md` so they don't appear as doctests
to rustdoc
* Move the function `draw_position` to the maps module and split it up
* Replace and refactor `pollen_at` and `uvi_at` methods on `Maps`
by `pollen_mark` and `uvi_mark`
* Drop the `pollen_project` and `uvi_project` methods on `Maps`,
just call the `project` helper method directly
* Add `map_at` and `mark` helper methods that handle maps slicing
and drawing
* Rename `pollen_sample` and `uvi_sample` methods on `Maps` to their
plural forms
* Also, rename the map handlers to `map_address` and `map_geo`
* Adapt `retrieve_image` to also return a timestamp based on the
CDN's last modified time; adapt other methods accordingly
* For the maps module, use `chrono::Utc` instead of
`tokio::time::Instant` and use `chrono::Duration` instead of
`tokio::time::Duration`
* Pass the maps timestamp to the `sample` function so it can use
that timestamp as base
* Define the map key for Buienradar as `MAP_KEY` (colors used on
Buienradar maps)
* Define a `MapkeyHistogram` type and add the `map_key_historgram()`
function to construct one
* Define the sample size to look for pixels around the sampling
coordinate
* Introduce a separata `sample` function that returns the samples
for a map and the provided coordinates and starting timestamp
* Implement `Maps::pollen_sample` and Maps::uvi_sample`
* A map is a view into the image of concatenated maps
* Ensure that projection only happens on the first map
* Make `project` generic over all generic image views
* Add map reference point constants `*_MAP_REF_POINTS `that can be used
for map projections
* Add (unimplemented )`*_project` and `*_sample` methods to the `Maps`
implementation
* Add `PollenSample` and `UviSample` structs
* Make `Position::new` const
* Add `is_*_stale` methods to the `MapRefresh` trait
* Only update the maps of a type if `retrieve_image` yielded something
or if the maps are stale
* Also only then bump the timestamp for the map type
This means if there is nothing in the cache, it will retry each refresh
to get something because the timestamp is not bumped until there is
something. Once there are maps, it will only update it and bump the
timestamp if there is an image, that or, it has become stale and it
can be set to `None` and we end up in the initial state.
This calculates which offset to use in the maps series with respect to
the instant of caching. It assumes the first map is current for the
instant it was retrieved.
* Rename `*_first` to `*_at` methods
* For convenience, change the types of `*_MAP_COUNT` to `u32`
* Introduce `*_MAP_INTERVAL` constants to indicate the number of
seconds each map in the series applies to
* Return `None` if the provided instant is too far in the future
This makes the response time way more snappy when the maps thread
is updating its cache.
* Move the `MapsHandle` type to the `maps` module
* SWitch to using the standard library mutex
* Split refresh methods into retrieval methods that don't need the lock
and check timestamp & update methods that only need it shortly
* Introduce the `MapsRefresh` trait and implement it for `MapsHandle`
* Reorder some methods for clarity
* Small documentation fixes
* Replace the lazy `once_cell` by a maps handle type
* Use Rocket's managed state to manage a handle
* Ensure that the handlers have access to it
* Pass another handle to the maps updater loop
* Try to keep the lock as short as possible
Still, long downloads block the lock. Add a FIXME to refactor this
so the lock is only taken when updating the maps fields.