2022-11-24 19:48:51 +01:00
|
|
|
import env from "../environment"
|
2023-11-03 18:17:20 +01:00
|
|
|
import * as Redis from "ioredis"
|
2021-05-04 19:13:44 +02:00
|
|
|
|
|
|
|
const SLOT_REFRESH_MS = 2000
|
|
|
|
const CONNECT_TIMEOUT_MS = 10000
|
2022-11-24 19:48:51 +01:00
|
|
|
export const SEPARATOR = "-"
|
2021-04-27 18:29:05 +02:00
|
|
|
|
2022-06-24 15:42:15 +02:00
|
|
|
/**
|
|
|
|
* These Redis databases help us to segment up a Redis keyspace by prepending the
|
|
|
|
* specified database name onto the cache key. This means that a single real Redis database
|
|
|
|
* can be split up a bit; allowing us to use scans on small databases to find some particular
|
|
|
|
* keys within.
|
|
|
|
* If writing a very large volume of keys is expected (say 10K+) then it is better to keep these out
|
2022-11-24 19:48:51 +01:00
|
|
|
* of the default keyspace and use a separate one - the SelectableDatabase can be used for this.
|
2022-06-24 15:42:15 +02:00
|
|
|
*/
|
2022-11-24 19:48:51 +01:00
|
|
|
export enum Databases {
|
|
|
|
PW_RESETS = "pwReset",
|
|
|
|
VERIFICATIONS = "verification",
|
|
|
|
INVITATIONS = "invitation",
|
|
|
|
DEV_LOCKS = "devLocks",
|
|
|
|
DEBOUNCE = "debounce",
|
|
|
|
SESSIONS = "session",
|
|
|
|
USER_CACHE = "users",
|
|
|
|
FLAGS = "flags",
|
|
|
|
APP_METADATA = "appMetadata",
|
|
|
|
QUERY_VARS = "queryVars",
|
|
|
|
LICENSES = "license",
|
|
|
|
GENERIC_CACHE = "data_cache",
|
|
|
|
WRITE_THROUGH = "writeThrough",
|
|
|
|
LOCKS = "locks",
|
2023-05-25 09:48:56 +02:00
|
|
|
SOCKET_IO = "socket_io",
|
2022-06-23 21:22:51 +02:00
|
|
|
}
|
|
|
|
|
2022-06-24 15:42:15 +02:00
|
|
|
/**
|
|
|
|
* These define the numeric Redis databases that can be access with the SELECT command -
|
|
|
|
* (https://redis.io/commands/select/). By default a Redis server/cluster will have 16 selectable
|
|
|
|
* databases, increasing this count increases the amount of CPU/memory required to run the server.
|
|
|
|
* Ideally new Redis keyspaces should be used sparingly, only when absolutely necessary for performance
|
|
|
|
* to be maintained. Generally a keyspace can grow to be very large is scans are not needed or desired,
|
|
|
|
* but if you need to walk through all values in a database periodically then a separate selectable
|
|
|
|
* keyspace should be used.
|
|
|
|
*/
|
2022-11-24 19:48:51 +01:00
|
|
|
export enum SelectableDatabase {
|
|
|
|
DEFAULT = 0,
|
2023-05-31 11:52:39 +02:00
|
|
|
SOCKET_IO = 1,
|
2023-11-03 19:00:13 +01:00
|
|
|
RATE_LIMITING = 2,
|
2022-11-24 19:48:51 +01:00
|
|
|
UNUSED_2 = 3,
|
|
|
|
UNUSED_3 = 4,
|
|
|
|
UNUSED_4 = 5,
|
|
|
|
UNUSED_5 = 6,
|
|
|
|
UNUSED_6 = 7,
|
|
|
|
UNUSED_7 = 8,
|
|
|
|
UNUSED_8 = 9,
|
|
|
|
UNUSED_9 = 10,
|
|
|
|
UNUSED_10 = 11,
|
|
|
|
UNUSED_11 = 12,
|
|
|
|
UNUSED_12 = 13,
|
|
|
|
UNUSED_13 = 14,
|
|
|
|
UNUSED_14 = 15,
|
2021-04-27 18:29:05 +02:00
|
|
|
}
|
|
|
|
|
2023-11-03 19:03:11 +01:00
|
|
|
export function getRedisConnectionDetails() {
|
2023-02-13 13:09:16 +01:00
|
|
|
let password = env.REDIS_PASSWORD
|
|
|
|
let url: string[] | string = env.REDIS_URL.split("//")
|
2022-03-10 16:53:23 +01:00
|
|
|
// get rid of the protocol
|
|
|
|
url = url.length > 1 ? url[1] : url[0]
|
|
|
|
// check for a password etc
|
|
|
|
url = url.split("@")
|
|
|
|
if (url.length > 1) {
|
|
|
|
// get the password
|
|
|
|
password = url[0].split(":")[1]
|
|
|
|
url = url[1]
|
|
|
|
} else {
|
|
|
|
url = url[0]
|
|
|
|
}
|
|
|
|
const [host, port] = url.split(":")
|
2021-09-09 18:14:24 +02:00
|
|
|
|
2023-11-03 19:03:11 +01:00
|
|
|
return {
|
|
|
|
host,
|
|
|
|
password,
|
|
|
|
port: parseInt(port),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getRedisOptions() {
|
|
|
|
const { host, password, port } = getRedisConnectionDetails()
|
2023-11-03 18:17:20 +01:00
|
|
|
let redisOpts: Redis.RedisOptions = {
|
2021-05-04 19:13:44 +02:00
|
|
|
connectTimeout: CONNECT_TIMEOUT_MS,
|
2023-11-03 19:03:11 +01:00
|
|
|
port: port,
|
2023-11-03 18:17:20 +01:00
|
|
|
host,
|
|
|
|
password,
|
2021-05-04 19:13:44 +02:00
|
|
|
}
|
2023-11-03 18:17:20 +01:00
|
|
|
let opts: Redis.ClusterOptions | Redis.RedisOptions = redisOpts
|
2023-04-28 20:53:15 +02:00
|
|
|
if (env.REDIS_CLUSTERED) {
|
2023-11-03 18:17:20 +01:00
|
|
|
opts = {
|
|
|
|
connectTimeout: CONNECT_TIMEOUT_MS,
|
|
|
|
redisOptions: {
|
|
|
|
...redisOpts,
|
|
|
|
tls: {},
|
|
|
|
},
|
|
|
|
slotsRefreshTimeout: SLOT_REFRESH_MS,
|
|
|
|
dnsLookup: (address: string, callback: any) => callback(null, address),
|
|
|
|
} as Redis.ClusterOptions
|
|
|
|
}
|
2023-11-03 19:03:11 +01:00
|
|
|
return opts
|
2021-05-04 19:13:44 +02:00
|
|
|
}
|
|
|
|
|
2022-11-24 19:48:51 +01:00
|
|
|
export function addDbPrefix(db: string, key: string) {
|
2021-05-13 16:32:03 +02:00
|
|
|
if (key.includes(db)) {
|
|
|
|
return key
|
|
|
|
}
|
2021-04-27 18:29:05 +02:00
|
|
|
return `${db}${SEPARATOR}${key}`
|
|
|
|
}
|
|
|
|
|
2022-11-24 19:48:51 +01:00
|
|
|
export function removeDbPrefix(key: string) {
|
2021-04-27 18:29:05 +02:00
|
|
|
let parts = key.split(SEPARATOR)
|
|
|
|
if (parts.length >= 2) {
|
|
|
|
parts.shift()
|
|
|
|
return parts.join(SEPARATOR)
|
|
|
|
} else {
|
|
|
|
// return the only part
|
|
|
|
return parts[0]
|
|
|
|
}
|
|
|
|
}
|