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 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
# Creating requests ####
auth_is_bearer <- function(token = NULL) {
if (is.null(token)) {
token <- auth_get()
}
inherits(token, "rtweet_bearer")
}
# Check token readiness for API v2
#
# Check if current authentication is ready for API v2 usage.
# @param token The token to check if can be used for API v2.
# @param mechanism Which flavor of authentication must be used.
#
# The authentication method required for each endpoint might change, this is a
# helper for examples.
#
# @return If no issue is found the original token, if something is amiss it raises an error.
# @export
#
# @examples
# if (auth_has_default()) {
# tryCatch(check_token_v2())
# }
check_token_v2 <- function(token = NULL, mechanism = "bearer") {
token <- token %||% auth_get()
if (mechanism == "bearer" && !auth_is_bearer(token)) {
abort("A bearer `token` is needed for this endpoint.")
}
token
}
# General function to create the requests for Twitter API v2 with retry limits
# and error handling
req_v2 <- function(token = NULL) {
token <- check_token_v2(token)
req <- httr2::request("https://api.twitter.com/2")
req_headers <- httr2::req_headers(req,
`Content-type` = "application/json",
Authorization = paste0("Bearer ", token$token)
)
req_try <- httr2::req_retry(req_headers,
is_transient = twitter_is_transient,
after = twitter_after)
req_try
}
twitter_is_transient <- function(resp) {
httr2::resp_status(resp) %in% c(403, 503) &&
identical(httr2::resp_header(resp, "x-rate-limit-remaining"), "0")
}
twitter_after <- function(resp) {
when <- as.numeric(httr2::resp_header(resp, "x-rate-limit-reset"))
when - unclass(Sys.time())
}
endpoint_v2 <- function(token, path, throttle) {
req <- httr2::req_url_path_append(req_v2(token), path)
httr2::req_throttle(req, throttle, realm = path)
}
prepare_params <- function(x) {
lapply(x, paste, collapse = ",")
}
# Handling responses ####
parsing <- function(x) {
if (!is.logical(x) || any(is.na(x))) {
stop("parse should be either TRUE or FALSE", call. = FALSE)
}
if (length(x) > 1) {
stop("parse should be of length 1", call. = FALSE)
}
if (isTRUE(x)) {
stop("Parsing for the rtweet API v2 is not yet implemented", call. = FALSE)
}
}
l_minus <- function(l, minus) {
keep <- setdiff(names(l), minus)
l[keep]
}
# Handle the response and give attributes
resp <- function(obj, type = "json", ...) {
out <- switch(type,
"json" = httr2::resp_body_json(obj, ...),
"html" = httr2::resp_body_html(obj, ...),
"xml" = httr2::resp_body_xml(obj, ...))
class(out) <- c("Twitter_resp", class(out))
if (has_name_(out, "meta")) {
meta <- data.frame(sent = strptime(out$meta$sent, tz = "UTC",
format = "%Y-%m-%dT%H:%M:%OS"))
if (has_name_(out$meta, "summary")) {
meta <- cbind(meta, list2DF(out$meta$summary))
}
rest <- list2DF(l_minus(out$meta, c("summary", "sent")))
if (ncol(rest) >= 1 && nrow(rest) == 1) {
meta <- cbind(meta, rest)
} else if (nrow(rest) > 1) {
stop("Please check")
}
out$meta <- meta
}
if (has_name_(out, "errors")) {
out$errors <- do.call(rbind, lapply(out$errors, list2DF))
}
out
}
|