rdcache/
script.rs

1use sha1::{Digest, Sha1};
2use std::sync::LazyLock;
3
4pub(crate) struct Script {
5    pub src: &'static str,
6    pub hash: String,
7}
8
9impl Script {
10    pub fn new(src: &'static str) -> Self {
11        let mut hasher = Sha1::new();
12
13        hasher.update(src.as_bytes());
14
15        let result = hasher.finalize();
16        Self {
17            src,
18            hash: format!("{:x}", result),
19        }
20    }
21}
22
23pub(crate) static DELETE_SCRIPT: LazyLock<Script> = LazyLock::new(|| {
24    Script::new(
25        r#"
26redis.call('HSET', KEYS[1], 'lockUntil', 0)
27redis.call('HDEL', KEYS[1], 'lockOwner')
28redis.call('EXPIRE', KEYS[1], ARGV[1])"#,
29    )
30});
31
32pub(crate) static GET_SCRIPT: LazyLock<Script> = LazyLock::new(|| {
33    Script::new(
34        r#"
35local v = redis.call('HGET', KEYS[1], 'value')
36local lu = redis.call('HGET', KEYS[1], 'lockUntil')
37if lu ~= false and tonumber(lu) < tonumber(ARGV[1]) or lu == false and v == false then
38    redis.call('HSET', KEYS[1], 'lockUntil', ARGV[2])
39    redis.call('HSET', KEYS[1], 'lockOwner', ARGV[3])
40    return { v, 'LOCKED' }
41end
42return {v, lu}"#,
43    )
44});
45
46pub(crate) static SET_SCRIPT: LazyLock<Script> = LazyLock::new(|| {
47    Script::new(
48        r#"
49local o = redis.call('HGET', KEYS[1], 'lockOwner')
50if o ~= ARGV[2] then
51		return
52end
53redis.call('HSET', KEYS[1], 'value', ARGV[1])
54redis.call('HDEL', KEYS[1], 'lockUntil')
55redis.call('HDEL', KEYS[1], 'lockOwner')
56redis.call('EXPIRE', KEYS[1], ARGV[3])"#,
57    )
58});
59
60pub(crate) static UNLOCK_SCRIPT: LazyLock<Script> = LazyLock::new(|| {
61    Script::new(
62        r#"
63local lo = redis.call('HGET', KEYS[1], 'lockOwner')
64if lo == ARGV[1] then
65	redis.call('HSET', KEYS[1], 'lockUntil', 0)
66	redis.call('HDEL', KEYS[1], 'lockOwner')
67	redis.call('EXPIRE', KEYS[1], ARGV[2])
68end"#,
69    )
70});
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn test_script_new() {
78        let script = Script::new("return 1");
79        assert_eq!(script.hash, "e0e1f9fabfc9d4800c877a703b823ac0578ff8db");
80        assert_eq!(script.src, "return 1");
81    }
82}