tokens.nim 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import asyncdispatch, httpclient, times, sequtils, strutils, json
  2. import types, agents, consts, http_pool
  3. var
  4. clientPool {.threadvar.}: HttpPool
  5. tokenPool {.threadvar.}: seq[Token]
  6. lastFailed: Time
  7. minFail = initDuration(seconds=10)
  8. proc fetchToken(): Future[Token] {.async.} =
  9. if getTime() - lastFailed < minFail:
  10. return Token()
  11. let headers = newHttpHeaders({
  12. "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
  13. "accept-language": "en-US,en;q=0.5",
  14. "connection": "keep-alive",
  15. "user-agent": getAgent(),
  16. "authorization": auth
  17. })
  18. var
  19. resp: string
  20. tok: string
  21. try:
  22. resp = clientPool.use(headers): await c.postContent(activate)
  23. tok = parseJson(resp)["guest_token"].getStr
  24. let time = getTime()
  25. result = Token(tok: tok, remaining: 187, reset: time + 15.minutes,
  26. init: time, lastUse: time)
  27. except Exception as e:
  28. lastFailed = getTime()
  29. echo "fetching token failed: ", e.msg
  30. result = Token()
  31. proc expired(token: Token): bool {.inline.} =
  32. const
  33. expirationTime = 2.hours
  34. maxLastUse = 1.hours
  35. let time = getTime()
  36. result = token.init < time - expirationTime or
  37. token.lastUse < time - maxLastUse
  38. proc isLimited(token: Token): bool {.inline.} =
  39. token == nil or (token.remaining <= 1 and token.reset > getTime()) or
  40. token.expired
  41. proc release*(token: Token) =
  42. if token != nil and not token.expired:
  43. token.lastUse = getTime()
  44. tokenPool.insert(token)
  45. proc getToken*(): Future[Token] {.async.} =
  46. for i in 0 ..< tokenPool.len:
  47. if not result.isLimited: break
  48. result.release()
  49. result = tokenPool.pop()
  50. if result.isLimited:
  51. result.release()
  52. result = await fetchToken()
  53. proc poolTokens*(amount: int) {.async.} =
  54. var futs: seq[Future[Token]]
  55. for i in 0 ..< amount:
  56. futs.add fetchToken()
  57. for token in futs:
  58. release(await token)
  59. proc initTokenPool*(cfg: Config) {.async.} =
  60. clientPool = HttpPool()
  61. while true:
  62. if tokenPool.countIt(not it.isLimited) < cfg.minTokens:
  63. await poolTokens(min(4, cfg.minTokens - tokenPool.len))
  64. await sleepAsync(2000)