Show error page when rate limited
This commit is contained in:
parent
2128b280b4
commit
4e1d213488
6 changed files with 25 additions and 5 deletions
|
@ -31,13 +31,16 @@ proc genHeaders*(token: Token = nil): HttpHeaders =
|
||||||
"DNT": "1"
|
"DNT": "1"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
proc rateLimitError(): ref RateLimitError =
|
||||||
|
newException(RateLimitError, "rate limited with " & getPoolInfo())
|
||||||
|
|
||||||
proc fetch*(url: Uri; oldApi=false): Future[JsonNode] {.async.} =
|
proc fetch*(url: Uri; oldApi=false): Future[JsonNode] {.async.} =
|
||||||
once:
|
once:
|
||||||
pool = HttpPool()
|
pool = HttpPool()
|
||||||
|
|
||||||
var token = await getToken()
|
var token = await getToken()
|
||||||
if token.tok.len == 0:
|
if token.tok.len == 0:
|
||||||
result = newJNull()
|
raise rateLimitError()
|
||||||
|
|
||||||
let headers = genHeaders(token)
|
let headers = genHeaders(token)
|
||||||
try:
|
try:
|
||||||
|
@ -59,4 +62,4 @@ proc fetch*(url: Uri; oldApi=false): Future[JsonNode] {.async.} =
|
||||||
token.release()
|
token.release()
|
||||||
except Exception:
|
except Exception:
|
||||||
echo "error: ", url
|
echo "error: ", url
|
||||||
result = newJNull()
|
raise rateLimitError()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import asyncdispatch, strformat
|
import asyncdispatch, strformat
|
||||||
from net import Port
|
from net import Port
|
||||||
|
from htmlgen import a
|
||||||
|
|
||||||
import jester
|
import jester
|
||||||
|
|
||||||
|
@ -9,6 +10,8 @@ import routes/[
|
||||||
preferences, timeline, status, media, search, rss, list,
|
preferences, timeline, status, media, search, rss, list,
|
||||||
unsupported, embed, resolver, router_utils]
|
unsupported, embed, resolver, router_utils]
|
||||||
|
|
||||||
|
const instancesUrl = "https://github.com/zedeus/nitter/wiki/Instances"
|
||||||
|
|
||||||
const configPath {.strdefine.} = "./nitter.conf"
|
const configPath {.strdefine.} = "./nitter.conf"
|
||||||
let (cfg, fullCfg) = getConfig(configPath)
|
let (cfg, fullCfg) = getConfig(configPath)
|
||||||
|
|
||||||
|
@ -71,6 +74,12 @@ routes:
|
||||||
error Http404:
|
error Http404:
|
||||||
resp Http404, showError("Page not found", cfg)
|
resp Http404, showError("Page not found", cfg)
|
||||||
|
|
||||||
|
error RateLimitError:
|
||||||
|
echo error.exc.msg
|
||||||
|
resp Http429, showError("Instance has been rate limited.<br>Use " &
|
||||||
|
a("another instance", href = instancesUrl) &
|
||||||
|
" or try again later.", cfg)
|
||||||
|
|
||||||
extend unsupported, ""
|
extend unsupported, ""
|
||||||
extend preferences, ""
|
extend preferences, ""
|
||||||
extend resolver, ""
|
extend resolver, ""
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
.error-panel {
|
.error-panel {
|
||||||
@include center-panel(var(--error_red));
|
@include center-panel(var(--error_red));
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-bar > form {
|
.search-bar > form {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import asyncdispatch, httpclient, times, sequtils, strutils, json
|
import asyncdispatch, httpclient, times, sequtils, json, math
|
||||||
|
import strutils, strformat
|
||||||
import types, agents, consts, http_pool
|
import types, agents, consts, http_pool
|
||||||
|
|
||||||
var
|
var
|
||||||
|
@ -32,8 +33,8 @@ proc fetchToken(): Future[Token] {.async.} =
|
||||||
init: time, lastUse: time)
|
init: time, lastUse: time)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
lastFailed = getTime()
|
lastFailed = getTime()
|
||||||
echo "fetching token failed: ", e.msg
|
|
||||||
result = Token()
|
result = Token()
|
||||||
|
echo "fetching token failed: ", e.msg
|
||||||
|
|
||||||
proc expired(token: Token): bool {.inline.} =
|
proc expired(token: Token): bool {.inline.} =
|
||||||
const
|
const
|
||||||
|
@ -77,3 +78,7 @@ proc initTokenPool*(cfg: Config) {.async.} =
|
||||||
if tokenPool.countIt(not it.isLimited) < cfg.minTokens:
|
if tokenPool.countIt(not it.isLimited) < cfg.minTokens:
|
||||||
await poolTokens(min(4, cfg.minTokens - tokenPool.len))
|
await poolTokens(min(4, cfg.minTokens - tokenPool.len))
|
||||||
await sleepAsync(2000)
|
await sleepAsync(2000)
|
||||||
|
|
||||||
|
proc getPoolInfo*: string =
|
||||||
|
let avg = tokenPool.mapIt(it.remaining).sum()
|
||||||
|
return &"{tokenPool.len} tokens, average remaining: {avg}"
|
||||||
|
|
|
@ -4,6 +4,8 @@ import prefs_impl
|
||||||
genPrefsType()
|
genPrefsType()
|
||||||
|
|
||||||
type
|
type
|
||||||
|
RateLimitError* = object of CatchableError
|
||||||
|
|
||||||
Token* = ref object
|
Token* = ref object
|
||||||
tok*: string
|
tok*: string
|
||||||
remaining*: int
|
remaining*: int
|
||||||
|
|
|
@ -117,4 +117,4 @@ proc renderMain*(body: VNode; req: Request; cfg: Config; prefs=defaultPrefs;
|
||||||
proc renderError*(error: string): VNode =
|
proc renderError*(error: string): VNode =
|
||||||
buildHtml(tdiv(class="panel-container")):
|
buildHtml(tdiv(class="panel-container")):
|
||||||
tdiv(class="error-panel"):
|
tdiv(class="error-panel"):
|
||||||
span: text error
|
span: verbatim error
|
||||||
|
|
Loading…
Reference in a new issue