     return request.remoteAddress
 }
 
-public class Limiter: RouterMiddleware {
+private func defaultWhitelist(request: RouterRequest) -> Bool {
+    return false
+}
+
+private func defaultOnRedisError(request: RouterRequest, response: RouterResponse, next: @escaping NextFunc) throws {
+    response.status(HTTPStatusCode.internalServerError).send("Internal server error")
+    try response.end()
+}
+
+class Limiter: RouterMiddleware {
     let by: By
     let onRateLimited: RouterHandler
     let expire: Int


typealias By = (_ request: RouterRequest) -> String
typealias NextFunc = () -> Void

private func now() -> Int { // ms since epoch
    return Int(Date().timeIntervalSince1970 * 1000)

    let defaultLimitJSON: JSON
    let redis: Redis
    let ignoreErrors: Bool
    let whitelist: WhiteList
    let onRedisError: RouterHandler
    let skipHeaders: Bool

    // 150 req/hour default
    init(redis: Redis, by: @escaping By = defaultByFunc, total: Int = 150, expire: Int = 1000 * 60 * 60, onRateLimited: @escaping RouterHandler = defaultOnRateLimited, ignoreErrors: Bool = false, whitelist: @escaping WhiteList = defaultWhitelist, onRedisError: @escaping RouterHandler = defaultOnRedisError, skipHeaders: Bool = false) {
        self.redis = redis
        self.by = by
        self.total = total
        self.expire = expire
        self.onRateLimited = onRateLimited
        self.onRedisError = onRedisError
        self.ignoreErrors = ignoreErrors
        self.whitelist = whitelist
        self.skipHeaders = skipHeaders
        self.defaultLimitJSON = JSON([
            "total": total,
            "remaining": total,
            "reset": now() + expire
        ])
    }

    func handle(request: RouterRequest, response: RouterResponse, next: @escaping NextFunc) throws {

        if whitelist(request) {
            return next()
        }

        let key = "ratelimit:\(self.by(request))"

        redis.get(key) { (string: RedisString?, redisError: NSError?) in
