Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: alphaearth
Title: Search embeddings available in the AlphaEarth Foundations Satellite Embeddings dataset
Version: 0.1.0
Version: 0.1.1
Authors@R:
person("Felipe", "Carlos", email = "efelipecarlos@gmail.com",
role = c("aut", "cre", "cph"))
Expand All @@ -13,6 +13,7 @@ Depends:
R (>= 4.1.0)
Imports:
cli,
curl,
DBI,
duckspatial,
fs,
Expand All @@ -23,7 +24,6 @@ Imports:
sf,
tibble
Suggests:
curl,
knitr,
pkgload,
rmarkdown,
Expand Down
53 changes: 47 additions & 6 deletions R/index.R
Original file line number Diff line number Diff line change
Expand Up @@ -73,24 +73,65 @@ index <- function(overwrite = FALSE) {
#'
#' @noRd
.index_download <- function(overwrite = FALSE) {
# get the index path
gpkg <- .config_gpkg_path()

# check if the index already exists and if we should overwrite it
if (fs::file_exists(gpkg) && !overwrite) {
return(gpkg)
}

# update user
cli::cli_alert_info("Downloading the AlphaEarth index (this happens once)...")

# download index file
utils::download.file(.config_index_url(), gpkg, mode = "wb", quiet = TRUE)
staged <- fs::path_temp("aef_index.gpkg")
on.exit(if (fs::file_exists(staged)) fs::file_delete(staged), add = TRUE)

# download index file (curl has no 60 second cap, unlike download.file())
curl::curl_download(.config_index_url(), staged, quiet = TRUE)

.index_check_size(staged, .config_index_url())
fs::file_move(staged, gpkg)

# return!
gpkg
}

#' Check the downloaded index against the size reported by the server.
#'
#' @description Check the downloaded index against the size reported by the
#' server.
#'
#' @param path [fs::path()] with the path to the downloaded file.
#' @param url `character` with the URL the file was downloaded from.
#'
#' @return `TRUE`, invisibly. Errors when the sizes differ.
#'
#' @noRd
.index_check_size <- function(path, url) {
handle <- curl::new_handle(nobody = TRUE)
headers <- curl::parse_headers_list(
rawToChar(curl::curl_fetch_memory(url, handle = handle)$headers)
)

content_length <- headers[["content-length"]]
expected <- suppressWarnings(as.numeric(content_length))

# as.numeric(NULL) has length 0, so test the header before is.na().
if (is.null(content_length) || length(expected) != 1L || is.na(expected)) {
return(invisible(TRUE))
}

actual <- fs::file_size(path)

if (actual != expected) {
cli::cli_abort(c(
"Downloading the AlphaEarth index failed.",
"x" = "Downloaded {.val {actual}} bytes, but the server reported
{.val {expected}}.",
"i" = "Please try again. The index was not written to the cache."
))
}

invisible(TRUE)
}

#' Open a DuckDB connection
#'
#' @description Open a DuckDB connection with the spatial extension loaded.
Expand Down
37 changes: 37 additions & 0 deletions tests/testthat/test-index.R
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,40 @@ test_that("index - reuses the cache without re-downloading", {
# expect search resolves the fixture tiles
expect_equal(search(fid = 3L)$tile, "24S-0-0")
})

test_that("index - a missing content length does not fail the size check", {
path <- withr::local_tempfile()
writeBin(raw(4L), path)

local_mocked_bindings(
curl_fetch_memory = function(url, handle) {
list(
headers = charToRaw(
"HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\n\r\n"
)
)
},
.package = "curl"
)

expect_true(.index_check_size(path, "https://example.invalid/aef_index.gpkg"))
})

test_that("index - a short download fails the size check", {
path <- withr::local_tempfile()
writeBin(raw(4L), path)

local_mocked_bindings(
curl_fetch_memory = function(url, handle) {
list(
headers = charToRaw("HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\n")
)
},
.package = "curl"
)

expect_error(
.index_check_size(path, "https://example.invalid/aef_index.gpkg"),
"not written to the cache"
)
})