debug) { vprintf($f, $a); } } /** * Parser the header and and init the FFI Singleton */ private function initFFI() { if (self::$ffi) { return; } $this->log("+ %s()\n", __METHOD__); // Try if preloaded try { self::$ffi = \FFI::scope("_REMI_REDIS_"); } catch (\FFI\Exception $e) { // Try direct load self::$ffi = \FFI::load(__DIR__ . '/preload-redis.h'); } if (!self::$ffi) { throw new \RuntimeException("FFI parse fails"); } } /** * Free redisContext memory */ public function cleanup() { if (!is_null($this->conn)) { self::$ffi->redisFree($this->conn); $this->conn = NULL; } } /** * Constructor + connection */ public function __construct($path, $port=6379, $debug=false) { $this->debug = $debug; $this->log("+ %s(%s, %d)\n", __METHOD__, $path, $port); $this->initFFI(); if ($path[0] === '/') { $this->conn = self::$ffi->redisConnectUnix($path); } else { $this->conn = self::$ffi->redisConnect($path, $port); } if ($this->conn->err) { $msg = ''; for($i=0 ; $i<128 && $this->conn->errstr[$i] ; $i++) { $msg .= $this->conn->errstr[$i]; } $this->cleanup(); throw new \RuntimeException($msg); } } /** * Destructor */ public function __destruct() { $this->log("+ %s\n\n", __METHOD__); $this->cleanup(); } /** * Parse the redisReply */ private function resp($rep, $free=true) { if (is_null($rep)) { throw new \RuntimeException('Command fails'); } switch ($rep->type) { case self::REDIS_REPLY_STATUS: case self::REDIS_REPLY_STRING: case self::REDIS_REPLY_ERROR: $msg = ''; for($i=0 ; $i<$rep->len ; $i++) { $msg .= $rep->str[$i]; } if ($rep->type == self::REDIS_REPLY_ERROR) { if ($free) self::$ffi->freeReplyObject($rep); throw new \RuntimeException($msg); } $ret = $msg; break; case self::REDIS_REPLY_ARRAY: $ret = []; for ($i=0 ; $i<$rep->elements ; $i++) { $ret[] = $this->resp($rep->element[$i], false); } break; case self::REDIS_REPLY_INTEGER: $ret = $rep->integer; break; case self::REDIS_REPLY_NIL: $ret = NULL; break; default: if ($free) self::$ffi->freeReplyObject($rep); throw new \RuntimeException('Unkown response type'); } if ($free) self::$ffi->freeReplyObject($rep); return $ret; } /** * Unkown command */ public function grrr() { $this->log("+ %s()\n", __METHOD__); return($this->resp(self::$ffi->redisCommand($this->conn, 'GRRR'))); } /** * DEL command */ public function del($name) { $this->log("+ %s(%s)\n", __METHOD__, $name); return($this->resp(self::$ffi->redisCommand($this->conn, "DEL $name"))); } /** * SET command */ public function set($name, $value) { $this->log("+ %s(%s, %s)\n", __METHOD__, $name, $value); return($this->resp(self::$ffi->redisCommand($this->conn, "SET $name %s", (string)$value))); } /** * GET command */ public function get($name) { $this->log("+ %s(%s)\n", __METHOD__, $name); return($this->resp(self::$ffi->redisCommand($this->conn, "GET $name"))); } /** * INCR command */ public function incr($name) { $this->log("+ %s(%s)\n", __METHOD__, $name); return($this->resp(self::$ffi->redisCommand($this->conn, "INCR $name"))); } /** * DECR command */ public function decr($name) { $this->log("+ %s(%s)\n", __METHOD__, $name); return($this->resp(self::$ffi->redisCommand($this->conn, "DECR $name"))); } /** * LPUSH command */ public function lpush($name, $elt) { $this->log("+ %s(%s, %s)\n", __METHOD__, $name, $elt); return($this->resp(self::$ffi->redisCommand($this->conn, "LPUSH $name %s", (string)$elt))); } /** * RPUSH command */ public function rpush($name, $elt) { $this->log("+ %s(%s, %s)\n", __METHOD__, $name, $elt); return($this->resp(self::$ffi->redisCommand($this->conn, "RPUSH $name %s", (string)$elt))); } /** * LSET command */ public function lset($name, $ind, $elt) { $this->log("+ %s(%s, %d, %s)\n", __METHOD__, $name, $ind, $elt); return($this->resp(self::$ffi->redisCommand($this->conn, "LSET $name %d %s", (int)$ind, (string)$elt))); } /** * LRANGE command */ public function lrange($name, $start, $end) { $this->log("+ %s(%s, %d, %s)\n", __METHOD__, $name, $start, $end); return($this->resp(self::$ffi->redisCommand($this->conn, "LRANGE $name %d %d", (int)$start, (int)$end))); } /** * LPOP command */ public function lpop($name) { $this->log("+ %s(%s)\n", __METHOD__, $name); return($this->resp(self::$ffi->redisCommand($this->conn, "LPOP $name"))); } /** * RPOP command */ public function rpop($name) { $this->log("+ %s(%s)\n", __METHOD__, $name); return($this->resp(self::$ffi->redisCommand($this->conn, "RPOP $name"))); } /** * LLEN command */ public function llen($name) { $this->log("+ %s(%s)\n", __METHOD__, $name); return($this->resp(self::$ffi->redisCommand($this->conn, "LLEN $name"))); } }