Annotation of parser3/src/types/pa_vredis.h, revision 1.1

1.1     ! moko        1: /** @file
        !             2:        Parser: @b redis class decls.
        !             3: 
        !             4:        Copyright (c) 2001-2026 Art. Lebedev Studio (https://www.artlebedev.com)
        !             5:        Authors: Konstantin Morshnev <moko@design.ru>
        !             6: */
        !             7: 
        !             8: #ifndef PA_VREDIS_H
        !             9: #define PA_VREDIS_H
        !            10: 
        !            11: #define IDENT_PA_VREDIS_H "$Id$"
        !            12: 
        !            13: #include "classes.h"
        !            14: #include "pa_vstateless_object.h"
        !            15: #include "pa_common.h"
        !            16: #include "pa_os.h"
        !            17: 
        !            18: #ifdef WITH_REDIS
        !            19: #include <hiredis/hiredis.h>
        !            20: #endif
        !            21: 
        !            22: // defines
        !            23: #define VREDIS_TYPE "redis"
        !            24: #define MAX_REDIS_COMMAND_PARAMS 10000
        !            25: 
        !            26: // externs
        !            27: extern Methoded *redis_class;
        !            28: 
        !            29: #ifdef WITH_REDIS
        !            30: /// classes/redis.C: the native code of ^r.command_name[arguments...]
        !            31: void redis_command_method(Request& r, MethodParams& params);
        !            32: 
        !            33: class Temp_redis_reply {
        !            34:        redisReply* freply;
        !            35: public:
        !            36:        Temp_redis_reply(redisReply* areply): freply(areply) {}
        !            37:        ~Temp_redis_reply() { if(freply) freeReplyObject(freply); }
        !            38: };
        !            39: #endif
        !            40: 
        !            41: class VRedis: public VStateless_object {
        !            42: public:
        !            43:        // value
        !            44:        override const char* type() const { return VREDIS_TYPE; }
        !            45:        override VStateless_class *get_class() { return redis_class; }
        !            46: 
        !            47: #ifdef WITH_REDIS
        !            48: #ifdef FEATURE_GET_ELEMENT4CALL
        !            49:        override Value* get_element4call(const String& aname) {
        !            50: #else
        !            51:        override Value* get_element(const String& aname) {
        !            52: #endif
        !            53:                if(Value* result=VStateless_object::get_element(aname))
        !            54:                        return result;
        !            55: 
        !            56:                Method* method=new Method(
        !            57:                        Method::CT_DYNAMIC,
        !            58:                        0, MAX_REDIS_COMMAND_PARAMS,
        !            59:                        0/*params_names*/, 0/*locals_names*/,
        !            60:                        0/*parser_code*/, redis_command_method, false/*all_vars_local*/
        !            61: #ifdef OPTIMIZE_RESULT
        !            62:                        , Method::RO_USE_WCONTEXT
        !            63: #endif
        !            64: #ifdef OPTIMIZE_CALL
        !            65:                        , Method::CO_WITHOUT_WCONTEXT
        !            66: #endif
        !            67:                        );
        !            68:                method->name=&aname;
        !            69:                return method->get_vjunction(*this);
        !            70: }
        !            71: 
        !            72: public: // usage
        !            73: 
        !            74:        VRedis(): fcontext(0), fuser(0), fpassword(0), fdb(0), fprotocol(3), fauto_reconnect(0) {}
        !            75: 
        !            76:        redisContext* fcontext;
        !            77:        const char* fuser;
        !            78:        const char* fpassword;
        !            79:        int fdb;
        !            80:        int fprotocol;
        !            81:        int fauto_reconnect; // 0 = disabled, N>0 = sleeps N sec before reconnecting
        !            82: 
        !            83:        /// HELLO or AUTH, then SELECT: on open and on reconnect
        !            84:        void handshake() {
        !            85:                if(fprotocol==3) {
        !            86:                        const char* argv[5]={"HELLO", "3"};
        !            87:                        int argc=2;
        !            88:                        if(fpassword) {
        !            89:                                argv[argc++]="AUTH";
        !            90:                                argv[argc++]=fuser ? fuser : "default";
        !            91:                                argv[argc++]=fpassword;
        !            92:                        }
        !            93:                        void_command(argc, argv);
        !            94:                } else if(fpassword) {
        !            95:                        const char* argv[3]={"AUTH"};
        !            96:                        int argc=1;
        !            97:                        if(fuser)
        !            98:                                argv[argc++]=fuser;
        !            99:                        argv[argc++]=fpassword;
        !           100:                        void_command(argc, argv);
        !           101:                }
        !           102:                if(fdb) {
        !           103:                        const char* argv[2]={"SELECT", pa_itoa(fdb)};
        !           104:                        void_command(2, argv);
        !           105:                }
        !           106:        }
        !           107: 
        !           108:        /// sends the command and returns the reply, which the caller frees
        !           109:        redisReply* command(int argc, const char** argv, const size_t* lengths=0) {
        !           110:                redisReply* reply=(redisReply*)redisCommandArgv(context(), argc, argv, lengths);
        !           111:                if(!reply)
        !           112:                        throw Exception("redis", 0, "%s failed: %s", argv[0], fcontext->errstr);
        !           113:                return reply;
        !           114:        }
        !           115: 
        !           116:        /// a command whose reply is only checked for an error
        !           117:        void void_command(int argc, const char** argv) {
        !           118:                redisReply* reply=command(argc, argv);
        !           119:                Temp_redis_reply temp_reply(reply);
        !           120:                if(reply->type==REDIS_REPLY_ERROR)
        !           121:                        throw Exception("redis", 0, "%s failed: %s", argv[0], reply->str);
        !           122:        }
        !           123: 
        !           124: private:
        !           125: 
        !           126:        /// reconnects first if the connection is broken and auto_reconnect is enabled
        !           127:        redisContext* context() {
        !           128:                if(!fcontext)
        !           129:                        throw Exception("redis", 0, "using unopened or released redis object");
        !           130:                if(fcontext->err) {
        !           131:                        if(fauto_reconnect <= 0)
        !           132:                                throw Exception("redis", 0, "connection is broken (auto_reconnect is not enabled): %s", fcontext->errstr);
        !           133:                        pa_sleep(fauto_reconnect, 0);
        !           134:                        if(redisReconnect(fcontext) != REDIS_OK)
        !           135:                                throw Exception("redis", 0, "reconnect failed: %s", fcontext->errstr);
        !           136:                        handshake();
        !           137:                }
        !           138:                return fcontext;
        !           139:        }
        !           140: 
        !           141: #endif // WITH_REDIS
        !           142: };
        !           143: 
        !           144: #endif

E-mail: