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 94 95 96 97 98 99 100 101 102
|
#' Rate limit helpers
#'
#' `r lifecycle::badge("deprecated")`
#'
#' @description
#' * `rate_limit()` returns a tibble of info about all rate limits
#' * `rate_limit_reset()` returns the next reset for a endpoint
#' * `rate_limit_wait()` waits for the next reset for an endpoint
#'
#' You should not need to use these function in the usual operation of rtweet
#' because all paginated functions will wait on your behalf if you set
#' `retryonratelimit = TRUE`.
#'
#' @inheritParams lookup_users
#' @param resource_match An optional regular expression used to filter the
#' resources listed in returned rate limit data.
#' @param endpoint Name of Twitter endpoint like `"lookup/users"`,
#' `"/media/upload"`, or `"/feedback/show/:id"`.
#' @family tokens
#' @seealso [`rtweet-deprecated`]
#' @export
#' @references <https://developer.twitter.com/en/docs/twitter-api/v1/developer-utilities/rate-limit-status>
rate_limit <- function(resource_match = NULL, token = NULL) {
json <- TWIT_get(token, "/1.1/application/rate_limit_status")
resources <- unlist(unname(json$resources), recursive = FALSE)
df <- tibble::tibble(
resource = names(resources),
limit = unlist(lapply(resources, "[[", "limit"), use.names = FALSE),
remaining = unlist(lapply(resources, "[[", "remaining"), use.names = FALSE),
reset_at = unlist(lapply(resources, "[[", "reset"), use.names = FALSE),
)
df$reset_at <- .POSIXct(df$reset_at)
df$reset <- round(difftime(df$reset_at, Sys.time(), units = "mins"))
if (!is.null(resource_match)) {
df <- df[grepl(resource_match, df$resource), ]
}
df
}
#' @export
#' @rdname rate_limit
rate_limit_reset <- function(endpoint, token = NULL) {
endpoint <- gsub("^/", "", endpoint)
resource <- strsplit(endpoint, "/")[[1]][[1]]
params <- list(resource = resource)
json <- TWIT_get(token, "/1.1/application/rate_limit_status", params)
info <- json$resources[[resource]][[paste0("/", endpoint)]]
if (is.null(info)) {
stop("Unrecognised endpoint '", endpoint, "'", call. = FALSE)
}
if (info$remaining > 0) {
Sys.time()
} else {
.POSIXct(info$reset)
}
}
#' @export
#' @rdname rate_limit
rate_limit_wait <- function(endpoint, token = NULL) {
reset <- unclass(rate_limit_reset(endpoint, token))
wait_until(reset, endpoint)
invisible()
}
wait_until <- function(until, api, fps = 8, verbose = TRUE) {
until <- unclass(until)
seconds <- until - unclass(Sys.time())
if (!verbose) {
Sys.sleep(ceiling(seconds))
return()
}
if (seconds < 0) {
return(invisible())
}
pb <- progress::progress_bar$new(
total = seconds * fps,
format = paste0(
"Rate limit exceeded for Twitter endpoint '", api, "'. ",
"Waiting for refresh in :mins mins :spin"
)
)
withr::defer(pb$terminate())
while(Sys.time() < until) {
Sys.sleep(1 / fps)
mins <- round((until - unclass(Sys.time())) / 60)
pb$tick(tokens = list(mins = mins))
}
invisible()
}
|