Support Redis; fixes #13

This commit is contained in:
Marius Lindvall 2019-09-17 12:44:28 +02:00
parent d3a0b02ad9
commit c1ea1f1c18
5 changed files with 114 additions and 27 deletions

View file

@ -1,5 +1,21 @@
<?php const CONFIG = array(
// The type of storage backend Hauk will use. Valid values include:
// MEMCACHED, REDIS
//
// For MEMCACHED, you need either the `memcached` or `memcache` extensions
// enabled in PHP.
//
// For REDIS, you need `redis` extension enabled. Note that `redis` depends on
// `igbinary`, so if you get an error that a redis extension was not found, even
// though you enabled `redis`, you may have to also install and enable
// `igbinary` in PHP.
"storage_backend" => REDIS,
/*----------------------------------------------------------------------------*\
| MEMCACHED SPECIFIC SETTINGS |
\*----------------------------------------------------------------------------*/
// Connection to memcached for data storage. To connect via UNIX socket instead
// of TCP, set host to 'unix:///path/to/memcached.sock' and port to 0.
"memcached_host" => 'localhost',
@ -18,6 +34,28 @@
// shared memcached instance or run multiple instances of Hauk.
"memcached_prefix" => 'hauk',
/*----------------------------------------------------------------------------*\
| REDIS SPECIFIC SETTINGS |
\*----------------------------------------------------------------------------*/
// Connection to Redis for data storage. To connect via UNIX socket instead of
// TCP, set host to '/path/to/redis.sock'.
"redis_host" => 'localhost',
"redis_port" => 6379,
// If you use password authentication in Redis, set `redis_use_auth` to true and
// enter the password in `redis_auth`.
"redis_use_auth" => false,
"redis_auth" => '',
// A prefix to use for all variables sent to Redis. Useful if you have a shared
// Redis instance or run multiple instances of Hauk.
"redis_prefix" => 'hauk',
/*----------------------------------------------------------------------------*\
| GENERAL SETTINGS |
\*----------------------------------------------------------------------------*/
// A hashed password that is required for creating sessions and posting location
// data to Hauk. To generate this value on the terminal:
// - MD5 (insecure!): openssl passwd -1

View file

@ -21,6 +21,9 @@ const LINK_ID_RAND_BYTES = 32;
const GROUP_PIN_MIN = 100000;
const GROUP_PIN_MAX = 999999;
const MEMCACHED = 0;
const REDIS = 1;
const KILOMETERS_PER_HOUR = array(
// Relative distance per second multiplied by number of seconds per hour.
"mpsMultiplier" => 3.6,
@ -42,6 +45,7 @@ const DEFAULTS = array(
// This is the default config. This file is used as a fallback for missing
// options in config.php.
"storage_backend" => MEMCACHED,
"memcached_host" => 'localhost',
"memcached_port" => 11211,
"memcached_binary" => false,
@ -49,6 +53,11 @@ const DEFAULTS = array(
"memcached_sasl_user" => "",
"memcached_sasl_pass" => "",
"memcached_prefix" => 'hauk',
"redis_host" => 'localhost',
"redis_port" => 6379,
"redis_use_auth" => false,
"redis_auth" => '',
"redis_prefix" => 'hauk',
"password_hash" => '$2y$10$4ZP1iY8A3dZygXoPgsXYV.S3gHzBbiT9nSfONjhWrvMxVPkcFq1Ka',
"map_tile_uri" => 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
"map_attribution" => 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
@ -91,9 +100,9 @@ function getConfig($item) {
if (array_key_exists($item, DEFAULTS)) return DEFAULTS[$item];
}
define("PREFIX_SESSION", getConfig("memcached_prefix")."-session-");
define("PREFIX_LOCDATA", getConfig("memcached_prefix")."-locdata-");
define("PREFIX_GROUPID", getConfig("memcached_prefix")."-groupid-");
define("PREFIX_SESSION", "-session-");
define("PREFIX_LOCDATA", "-locdata-");
define("PREFIX_GROUPID", "-groupid-");
// A base class for location shares. Shares contain a reference to all sessions
// that broadcasts location data to the share, but does not contain the location
@ -555,16 +564,30 @@ function requirePOST(...$args) {
// Hauk maintains compatibility with both `memcache` and `memcached`, meaning we
// need an abstraction layer between Hauk and the extensions to ensure a unified
// interface for both. This code loads the correct memcache wrapper.
if (extension_loaded("memcached")) {
include_once(__DIR__."/wrapper/memcached.php");
} else if (extension_loaded("memcache")) {
include_once(__DIR__."/wrapper/memcache.php");
} else {
die("No compatible memcached extension (memcache or memcached) is enabled in your PHP config!\n");
switch (getConfig("storage_backend")) {
case MEMCACHED:
if (extension_loaded("memcached")) {
include_once(__DIR__."/wrapper/memcached.php");
} else if (extension_loaded("memcache")) {
include_once(__DIR__."/wrapper/memcache.php");
} else {
die("No compatible memcached extension (memcache or memcached) is enabled in your PHP config!\n");
}
break;
case REDIS:
if (extension_loaded("redis")) {
include_once(__DIR__."/wrapper/redis.php");
} else {
die("No compatible redis extension (redis) is enabled in your PHP config!\n");
}
break;
default:
die("You have set an invalid storage_backend in Hauk!");
}
// Returns a memcached instance.
function memConnect() {
$memcache = new MemWrapper(getConfig("memcached_host"), getConfig("memcached_port"));
return $memcache;
return new MemWrapper();
}

View file

@ -8,28 +8,24 @@
class MemWrapper {
private $memcache = null;
function __construct($host, $port) {
function __construct() {
$this->memcache = new Memcache();
$this->memcache->connect(getConfig("memcached_host"), getConfig("memcached_port"))
or die ("Server could not connect to memcached!\n");
}
function get($key) {
$data = $this->memcache->get($key);
$data = $this->memcache->get(getConfig("memcached_prefix").$key);
if ($data === false) return false;
return json_decode($data, true);
}
function set($key, $data, $expire) {
$this->memcache->set($key, json_encode($data), 0, $expire);
}
function replace($key, $data, $expire) {
$this->memcache->replace($key, json_encode($data), 0, $expire);
$this->memcache->set(getConfig("memcached_prefix").$key, json_encode($data), 0, $expire);
}
function delete($key) {
$this->memcache->delete($key);
$this->memcache->delete(getConfig("memcached_prefix").$key);
}
}

View file

@ -8,7 +8,7 @@
class MemWrapper {
private $memcache = null;
function __construct($host, $port) {
function __construct() {
// If the hostname starts with "unix://", this is a UNIX socket.
// The `memcached` extension only needs the full pathname and not the
// unix scheme, so we strip the scheme from the path.
@ -27,21 +27,17 @@ class MemWrapper {
}
function get($key) {
$data = $this->memcache->get($key);
$data = $this->memcache->get(getConfig("memcached_prefix").$key);
if ($data === false) return false;
return json_decode($data, true);
}
function set($key, $data, $expire) {
$this->memcache->set($key, json_encode($data), $expire);
}
function replace($key, $data) {
$this->memcache->replace($key, json_encode($data), $expire);
$this->memcache->set(getConfig("memcached_prefix").$key, json_encode($data), $expire);
}
function delete($key) {
$this->memcache->delete($key);
$this->memcache->delete(getConfig("memcached_prefix").$key);
}
}

View file

@ -0,0 +1,34 @@
<?php
// This class is a wrapper class for the `redis` extension in PHP, for
// communication with Redis backends.
class MemWrapper {
private $redis = null;
function __construct() {
$this->redis = new Redis();
if (getConfig("redis_use_auth")) {
$this->redis->auth(getConfig("redis_auth"))
or die("Incorrect Redis authentication!");
}
$this->redis->connect(getConfig("redis_host"), getConfig("redis_port"))
or die ("Server could not connect to Redis!\n");
}
function get($key) {
$data = $this->redis->get(getConfig("redis_prefix").$key);
if ($data === false) return false;
return json_decode($data, true);
}
function set($key, $data, $expire) {
$this->redis->setEx(getConfig("redis_prefix").$key, $expire - time(), json_encode($data));
}
function delete($key) {
$this->redis->del(getConfig("redis_prefix").$key);
}
}
?>