apiutils.nim 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. # SPDX-License-Identifier: AGPL-3.0-only
  2. import httpclient, asyncdispatch, options, times, strutils, uri
  3. import packedjson, zippy
  4. import types, tokens, consts, parserutils, http_pool
  5. const rl = "x-rate-limit-"
  6. var pool {.threadvar.}: HttpPool
  7. proc genParams*(pars: openarray[(string, string)] = @[]; cursor="";
  8. count="20"; ext=true): seq[(string, string)] =
  9. result = timelineParams
  10. for p in pars:
  11. result &= p
  12. if ext:
  13. result &= ("ext", "mediaStats")
  14. if cursor.len > 0:
  15. result &= ("cursor", cursor)
  16. if count.len > 0:
  17. result &= ("count", count)
  18. proc genHeaders*(token: Token = nil): HttpHeaders =
  19. result = newHttpHeaders({
  20. "connection": "keep-alive",
  21. "authorization": auth,
  22. "content-type": "application/json",
  23. "x-guest-token": if token == nil: "" else: token.tok,
  24. "x-twitter-active-user": "yes",
  25. "authority": "api.twitter.com",
  26. "accept-encoding": "gzip",
  27. "accept-language": "en-US,en;q=0.9",
  28. "accept": "*/*",
  29. "DNT": "1"
  30. })
  31. proc fetch*(url: Uri; oldApi=false): Future[JsonNode] {.async.} =
  32. once:
  33. pool = HttpPool()
  34. var token = await getToken()
  35. if token.tok.len == 0:
  36. raise rateLimitError()
  37. let headers = genHeaders(token)
  38. try:
  39. var resp: AsyncResponse
  40. let body = pool.use(headers):
  41. resp = await c.get($url)
  42. uncompress(await resp.body)
  43. if body.startsWith('{') or body.startsWith('['):
  44. result = parseJson(body)
  45. else:
  46. echo resp.status, ": ", body
  47. result = newJNull()
  48. if not oldApi and resp.headers.hasKey(rl & "reset"):
  49. token.remaining = parseInt(resp.headers[rl & "remaining"])
  50. token.reset = fromUnix(parseInt(resp.headers[rl & "reset"]))
  51. if result.getError notin {invalidToken, forbidden, badToken}:
  52. token.lastUse = getTime()
  53. else:
  54. echo "fetch error: ", result.getError
  55. release(token, true)
  56. raise rateLimitError()
  57. except Exception as e:
  58. echo "error: ", e.msg, ", token: ", token[], ", url: ", url
  59. if "length" notin e.msg and "descriptor" notin e.msg:
  60. release(token, true)
  61. raise rateLimitError()