import { createHash } from 'crypto' import createDebug from 'debug' import { RedisClient } from '../types' import { getConnectionName } from './index' const debug = createDebug('redis-semaphore:eval') function createSHA1(script: string) { return createHash('sha1').update(script, 'utf8').digest('hex') } function isNoScriptError(err: Error) { return err.toString().indexOf('NOSCRIPT') !== -1 } export default function createEval, Result>( script: string, keysCount: number ) { const sha1 = createSHA1(script) debug('creating script:', script, 'sha1:', sha1) return async function optimizedEval( client: RedisClient, args: Args ): Promise { const connectionName = getConnectionName(client) const evalSHAArgs = [sha1, keysCount, ...args] debug(connectionName, sha1, 'attempt, args:', evalSHAArgs) try { return (await client.evalsha(sha1, keysCount, ...args)) as Promise } catch (err: any) { if (isNoScriptError(err)) { const evalArgs = [script, keysCount, ...args] debug(connectionName, sha1, 'fallback to eval, args:', evalArgs) return (await client.eval( script, keysCount, ...args )) as Promise } else { throw err } } } }