const env = require("../environment") const SLOT_REFRESH_MS = 2000 const CONNECT_TIMEOUT_MS = 10000 const SEPARATOR = "-" const REDIS_URL = !env.REDIS_URL ? "localhost:6379" : env.REDIS_URL const REDIS_PASSWORD = !env.REDIS_PASSWORD ? "budibase" : env.REDIS_PASSWORD /** * 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 * of the default keyspace and use a separate one - the SelectableDatabases can be used for this. */ exports.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", } /** * 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. */ exports.SelectableDatabases = { DEFAULT: 0, WRITE_THROUGH: 1, UNUSED_1: 2, 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, } exports.SEPARATOR = SEPARATOR exports.getRedisOptions = (clustered = false) => { let password = REDIS_PASSWORD let url = REDIS_URL.split("//") // 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(":") let redisProtocolUrl // fully qualified redis URL if (/rediss?:\/\//.test(REDIS_URL)) { redisProtocolUrl = REDIS_URL } const opts = { connectTimeout: CONNECT_TIMEOUT_MS, } if (clustered) { opts.redisOptions = {} opts.redisOptions.tls = {} opts.redisOptions.password = password opts.slotsRefreshTimeout = SLOT_REFRESH_MS opts.dnsLookup = (address, callback) => callback(null, address) } else { opts.host = host opts.port = port opts.password = password } return { opts, host, port, redisProtocolUrl } } exports.addDbPrefix = (db, key) => { if (key.includes(db)) { return key } return `${db}${SEPARATOR}${key}` } exports.removeDbPrefix = key => { let parts = key.split(SEPARATOR) if (parts.length >= 2) { parts.shift() return parts.join(SEPARATOR) } else { // return the only part return parts[0] } }