redis_module_ext/
export.rs

1use std::ffi::c_int;
2
3use redis_module::raw;
4
5use crate::RedisModule;
6
7#[macro_export]
8macro_rules! export_redis_module {
9    ($module:ty) => {
10        const _: () = {
11            /// Redis module allocator.
12            #[global_allocator]
13            static REDIS_MODULE_ALLOCATOR: $crate::redis::alloc::RedisAlloc = $crate::redis::alloc::RedisAlloc;
14
15            #[unsafe(no_mangle)]
16            #[allow(non_snake_case, unsafe_op_in_unsafe_fn)]
17            pub unsafe extern "C" fn RedisModule_OnLoad(
18                ctx: *mut $crate::raw::RedisModuleCtx,
19                argv: *mut *mut $crate::raw::RedisModuleString,
20                argc: std::os::raw::c_int,
21            ) -> std::os::raw::c_int {
22                unsafe { $crate::export::on_load::<$module>(ctx, argv, argc) }
23            }
24
25            #[unsafe(no_mangle)]
26            #[allow(non_snake_case, unsafe_op_in_unsafe_fn)]
27            pub extern "C" fn RedisModule_OnUnload(ctx: *mut $crate::raw::RedisModuleCtx) -> std::os::raw::c_int {
28                unsafe { $crate::export::on_unload::<$module>(ctx) }
29            }
30        };
31    };
32}
33
34/// # Safety
35/// The `ctx` must be a valid ptr and this function must only be called once when redis is loading the module.
36/// Calling this function outside of the redis loading is UB.
37pub unsafe fn on_load<M: RedisModule>(
38    ctx: *mut raw::RedisModuleCtx,
39    _: *mut *mut raw::RedisModuleString,
40    _: std::os::raw::c_int,
41) -> std::os::raw::c_int {
42    let name = M::name();
43    let version = M::version();
44
45    let result = unsafe { raw::Export_RedisModule_Init(ctx, name.as_ptr(), version, raw::REDISMODULE_APIVER_1 as c_int) };
46
47    if result == raw::Status::Err as c_int {
48        return raw::Status::Err as c_int;
49    }
50
51    let context = redis_module::Context::new(ctx);
52    let _ = redis_module::MODULE_CONTEXT.set_context(&context);
53
54    if !M::register_data_types(&context) {
55        return raw::Status::Err as c_int;
56    }
57
58    if let Err(e) = M::register_commands(&context) {
59        context.log_warning(&e.to_string());
60    }
61
62    if let Err(e) = redis_module::defrag::register_defrag_functions(&context) {
63        context.log_warning(&e.to_string());
64        return raw::Status::Err as c_int;
65    }
66
67    extern "C" fn __info_func(ctx: *mut raw::RedisModuleInfoCtx, for_crash_report: i32) {
68        redis_module::basic_info_command_handler(&redis_module::InfoContext::new(ctx), for_crash_report == 1);
69    }
70
71    raw::register_info_function(ctx, Some(__info_func));
72
73    if let Err(e) = redis_module::server_events::register_server_events(&context) {
74        context.log_warning(&e.to_string());
75        return raw::Status::Err as c_int;
76    }
77
78    if let Err(err) = M::init_fn(&context) {
79        context.log_warning(&err.to_string());
80        return raw::Status::Err as c_int;
81    }
82
83    raw::Status::Ok as c_int
84}
85
86/// # Safety
87/// The `ctx` must be a valid ptr and this function must only be called once when redis is unloading the module.
88/// Calling this function outside of the redis unloading is UB.
89pub unsafe fn on_unload<M: RedisModule>(ctx: *mut raw::RedisModuleCtx) -> std::os::raw::c_int {
90    let context = redis_module::Context::new(ctx);
91
92    if let Err(err) = M::deinit_fn(&context) {
93        context.log_warning(&err.to_string());
94        return raw::Status::Err as c_int;
95    }
96
97    raw::Status::Ok as c_int
98}