import redis from 'redis' ; import { getRequiredServerEnvVar } from './misc' ; declare global { var replicaClient , primaryClient ; } const REDIS_URL = getRequiredServerEnvVar ( 'REDIS_URL' ) ; const replica = new URL ( REDIS_URL ) ; const isLocalHost = replica . hostname === 'localhost' ; const isInternal = replica . hostname . includes ( '.internal' ) ; const isMultiRegion = ! isLocalHost && isInternal ; const PRIMARY_REGION = isMultiRegion ? getRequiredServerEnvVar ( 'PRIMARY_REGION' ) : null ; const FLY_REGION = isMultiRegion ? getRequiredServerEnvVar ( 'FLY_REGION' ) : null ; if ( FLY_REGION ) { replica . host = `${ FLY_REGION }.${ replica . host }` ; } const replicaClient = createClient ( 'replicaClient' , { url : replica . toString ( ) , family : isInternal ? 'IPv6' : 'IPv4' , } ) ; let primaryClient = null ; if ( FLY_REGION !== PRIMARY_REGION ) { const primary = new URL ( REDIS_URL ) ; if ( ! isLocalHost ) { primary . host = `${ PRIMARY_REGION }.${ primary . host }` ; } primaryClient = createClient ( 'primaryClient' , { url : primary . toString ( ) , family : isInternal ? 'IPv6' : 'IPv4' , } ) ; } function createClient ( name , options ) { let client = global [ name ] ; if ( ! client ) { const url = new URL ( options . url ?? 'http://no-redis-url.example.com?weird' ) ; client = global [ name ] = redis . createClient ( options ) ; client . on ( 'error' , ( error ) => { console . error ( `REDIS ${ name } (${ url . host }) ERROR:` , error ) ; } ) ; } return client ; } function get < Value = unknown > ( key ) { return new Promise ( resolve => { replicaClient . get ( key , ( err , result ) => { if ( err ) { console . error ( `REDIS replicaClient (${ FLY_REGION }) ERROR with .get:` , err ) ; } resolve ( result ? ( JSON . parse ( result ) as Value ) : null ) ; } ) ; } ) ; } function set < Value > ( key , value ) { return new Promise ( resolve => { replicaClient . set ( key , JSON . stringify ( value ) , ( err , reply ) => { if ( err ) console . error ( `REDIS replicaClient (${ FLY_REGION }) ERROR with .set:` , err ) ; resolve ( reply ) ; } ) ; } ) ; } function del ( key ) { return new Promise ( resolve => { primaryClient ?. del ( key , ( err ) => { if ( err ) { console . error ( 'Primary delete error' , err ) ; } } ) ; replicaClient . del ( key , ( err , result ) => { if ( err ) { console . error ( `REDIS replicaClient (${ FLY_REGION }) ERROR with .del:` , err ) ; resolve ( 'error' ) ; } else { resolve ( `${ key } deleted: ${ result }` ) ; } } ) ; } ) ; } const redisCache = { get , set , del , name : 'redis' } ; export { get , set , del , redisCache } ;