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: