Skip to content
This repository was archived by the owner on Jul 11, 2025. It is now read-only.

Commit 1090632

Browse files
Merge pull request #62 from open-AIMS/feat/criteria-ranges
Endpoint to retrieve min/max values for criteria ranges
2 parents 393a903 + fc40c65 commit 1090632

File tree

8 files changed

+478
-381
lines changed

8 files changed

+478
-381
lines changed

src/ReefGuideAPI.jl

Lines changed: 5 additions & 225 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ using
2626

2727
include("Middleware.jl")
2828
include("admin.jl")
29+
include("file_io.jl")
30+
include("server_cache.jl")
2931

3032
include("job_management/JobInterface.jl")
3133
include("job_management/DiskService.jl")
@@ -49,237 +51,12 @@ function get_regions()
4951
return regions
5052
end
5153

52-
"""
53-
initialize_regional_data_cache(reef_data_path::String, reg_cache_fn::String)
54-
55-
Create initial regional data store with data from `reef_data_path`, excluding geospatial
56-
data and save to `reg_cache_fn` path.
57-
"""
58-
function initialize_regional_data_cache(reef_data_path::String, reg_cache_fn::String)
59-
regional_assessment_data = OrderedDict{
60-
String,Union{RegionalCriteria,DataFrame,Dict}
61-
}()
62-
for reg in get_regions()
63-
@debug "$(now()) : Initializing cache for $reg"
64-
data_paths = String[]
65-
data_names = String[]
66-
67-
slope_table = nothing
68-
flat_table = nothing
69-
70-
for (k, dp) in criteria_data_map()
71-
g = glob("$reg*$dp.tif", reef_data_path)
72-
if length(g) == 0
73-
continue
74-
end
75-
76-
push!(data_paths, first(g))
77-
push!(data_names, string(k))
78-
if occursin("valid", string(dp))
79-
# Load up Parquet files
80-
parq_file = replace(first(g), ".tif" => "_lookup.parq")
81-
82-
if occursin("slope", string(dp))
83-
slope_table = GeoParquet.read(parq_file)
84-
elseif occursin("flat", string(dp))
85-
@warn "Skipping data for reef flats as it is currently unused"
86-
# flat_table = GeoParquet.read(parq_file)
87-
else
88-
msg = "Unknown lookup found: $(parq_file). Must be 'slope' or 'flat'"
89-
throw(ArgumentError(msg))
90-
end
91-
end
92-
end
93-
94-
# Pre-extract long/lat coordinates
95-
coords = GI.coordinates.(slope_table.geometry)
96-
slope_table[!, :lons] .= first.(coords)
97-
slope_table[!, :lats] .= last.(coords)
98-
99-
# coords = GI.coordinates.(flat_table.geometry)
100-
# flat_table[!, :lons] .= first.(coords)
101-
# flat_table[!, :lats] .= last.(coords)
102-
103-
rst_stack = RasterStack(data_paths; name=data_names, lazy=true)
104-
regional_assessment_data[reg] = RegionalCriteria(
105-
rst_stack,
106-
slope_table,
107-
slope_table[[1], :] # flat_table
108-
)
109-
110-
@debug "$(now()) : Finished initialization for $reg"
111-
end
112-
113-
regional_assessment_data["region_long_names"] = Dict(
114-
"FarNorthern" => "Far Northern Management Area",
115-
"Cairns-Cooktown" => "Cairns/Cooktown Management Area",
116-
"Townsville-Whitsunday" => "Townsville/Whitsunday Management Area",
117-
"Mackay-Capricorn" => "Mackay/Capricorn Management Area"
118-
)
119-
120-
# Store cache on disk to avoid excessive cold startup times
121-
@debug "Saving regional data cache to disk"
122-
serialize(reg_cache_fn, regional_assessment_data)
123-
124-
return regional_assessment_data
125-
end
126-
127-
"""
128-
setup_regional_data(config::Dict)
129-
130-
Load regional data to act as an in-memory cache.
131-
132-
# Arguments
133-
- `config` : Configuration settings, typically loaded from a TOML file.
134-
- `reef_data_path` : Path to pre-prepared reef data
135-
136-
# Returns
137-
OrderedDict of `RegionalCriteria` for each region.
138-
"""
139-
function setup_regional_data(config::Dict)
140-
reef_data_path = config["prepped_data"]["PREPPED_DATA_DIR"]
141-
reg_cache_dir = config["server_config"]["REGIONAL_CACHE_DIR"]
142-
reg_cache_fn = joinpath(reg_cache_dir, "regional_cache.dat")
143-
144-
if @isdefined(REGIONAL_DATA)
145-
@debug "Using previously generated regional data store."
146-
elseif isfile(reg_cache_fn)
147-
@debug "Loading regional data cache from disk"
148-
# Updates to packages like DiskArrays can break deserialization
149-
try
150-
@eval const REGIONAL_DATA = deserialize($(reg_cache_fn))
151-
catch err
152-
@warn "Failed to deserialize $(reg_cache_fn) with error:" err
153-
rm(reg_cache_fn)
154-
end
155-
end
156-
157-
if !@isdefined(REGIONAL_DATA)
158-
@debug "Setting up regional data store..."
159-
regional_assessment_data = initialize_regional_data_cache(
160-
reef_data_path,
161-
reg_cache_fn
162-
)
163-
# Remember, `@eval` runs in global scope.
164-
@eval const REGIONAL_DATA = $(regional_assessment_data)
165-
end
166-
167-
# If REGIONAL_DATA is defined, but failed to load supporting data that cannot be
168-
# cached to disk, such as the reef outlines, (e.g., due to incorrect config), then it
169-
# will cause errors later on.
170-
# Then there's no way to address this, even between web server sessions, as `const`
171-
# values cannot be modified.
172-
# Here, we check for existence and try to load again if needed.
173-
if !haskey(REGIONAL_DATA, "reef_outlines")
174-
reef_outline_path = joinpath(reef_data_path, "rrap_canonical_outlines.gpkg")
175-
REGIONAL_DATA["reef_outlines"] = GDF.read(reef_outline_path)
176-
end
177-
178-
return REGIONAL_DATA
179-
end
180-
181-
"""
182-
_cache_location(config::Dict)::String
183-
184-
Retrieve cache location for geotiffs.
185-
"""
186-
function _cache_location(config::Dict)::String
187-
cache_loc = try
188-
in_debug = haskey(config["server_config"], "DEBUG_MODE")
189-
if in_debug && lowercase(config["server_config"]["DEBUG_MODE"]) == "true"
190-
if "DEBUG_CACHE_DIR" keys(ENV)
191-
ENV["DEBUG_CACHE_DIR"] = mktempdir()
192-
end
193-
194-
ENV["DEBUG_CACHE_DIR"]
195-
else
196-
config["server_config"]["TIFF_CACHE_DIR"]
197-
end
198-
catch err
199-
@warn "Encountered error:" err
200-
if "DEBUG_CACHE_DIR" keys(ENV)
201-
ENV["DEBUG_CACHE_DIR"] = mktempdir()
202-
end
203-
204-
ENV["DEBUG_CACHE_DIR"]
205-
end
206-
207-
return cache_loc
208-
end
209-
210-
"""
211-
cache_filename(qp::Dict, config::Dict, suffix::String, ext::String)
212-
213-
Generate a filename for a cache.
214-
215-
# Arguments
216-
- `qp` : Query parameters to hash
217-
- `config` : app configuration (to extract cache parent directory from)
218-
- `suffix` : a suffix to use in the filename (pass `""` if none required)
219-
- `ext` : file extension to use
220-
"""
221-
function cache_filename(qp::Dict, config::Dict, suffix::String, ext::String)
222-
file_id = create_job_id(qp)
223-
temp_path = _cache_location(config)
224-
cache_file_path = joinpath(temp_path, "$(file_id)$(suffix).$(ext)")
225-
226-
return cache_file_path
227-
end
228-
229-
"""
230-
n_gdal_threads(config::Dict)::String
231-
232-
Retrieve the configured number of threads to use when writing COGs with GDAL.
233-
"""
234-
function n_gdal_threads(config::Dict)::String
235-
n_cog_threads = try
236-
config["server_config"]["COG_THREADS"]
237-
catch
238-
"1" # Default to using a single thread for GDAL write
239-
end
240-
241-
return n_cog_threads
242-
end
243-
244-
"""
245-
tile_size(config::Dict)::Tuple
246-
247-
Retrieve the configured size of map tiles in pixels (width and height / lon and lat).
248-
"""
249-
function tile_size(config::Dict)::Tuple
250-
tile_dims = try
251-
res = parse(Int, config["server_config"]["TILE_SIZE"])
252-
(res, res)
253-
catch
254-
(256, 256) # 256x256
255-
end
256-
257-
return tile_dims
258-
end
259-
26054
function get_auth_router(config::Dict)
26155
# Setup auth middleware - depends on config.toml - can return identity func
26256
auth = setup_jwt_middleware(config)
26357
return router(""; middleware=[auth])
26458
end
26559

266-
"""
267-
warmup_cache(config_path::String)
268-
269-
Invokes warm up of regional data cache to reduce later spin up times.
270-
"""
271-
function warmup_cache(config_path::String)
272-
config = TOML.parsefile(config_path)
273-
274-
# Create re-usable empty tile
275-
no_data_path = cache_filename(Dict("no_data" => "none"), config, "no_data", "png")
276-
if !isfile(no_data_path)
277-
save(no_data_path, zeros(RGBA, tile_size(config)))
278-
end
279-
280-
return setup_regional_data(config)
281-
end
282-
28360
function start_server(config_path)
28461
@info "Launching server... please wait"
28562

@@ -291,6 +68,9 @@ function start_server(config_path)
29168
@info "Setting up auth middleware and router."
29269
auth = get_auth_router(config)
29370

71+
@info "Setting up criteria routes..."
72+
setup_criteria_routes(config, auth)
73+
29474
@info "Setting up region routes..."
29575
setup_region_routes(config, auth)
29676

0 commit comments

Comments
 (0)