/Class/Comet/Storage.php
https://github.com/jmarien/phpBayeux · PHP · 316 lines · 239 code · 32 blank · 45 comment · 33 complexity · 0ba2d9a13d47f64e36a3aef962065a55 MD5 · raw file
- <?php
- /**
- * @todo refactor storage backend out to an abstract driver interface
- * @todo implement/try a redis backend
- * @todo test memcached again, on 64bit Ubuntu laptop everything was ok, on 32 Ubuntu PC not.
- */
- class Comet_Storage {
- protected $_channel = null;
- protected $_memcacheServer = '127.0.0.1';
- protected $_memcachePort = 11211;
- protected $_cacheBackend = null;
- protected $_cacheType = 'memcache';
- public function __construct() {
- $this->_loadBackend();
- }
- public function setChannel($channel) {
- //_log(' '.__FILE__.' '.__LINE__.' | set channel to '.$this->_normalizeName($channel));
- $this->_channel = $this->_normalizeName($channel);
- }
- /**
- *
- * @return string channel name
- */
- public function getChannel() {
- return $this->_channel;
- }
- /**
- *
- * @param string $clientid
- * @return array
- */
- public function getClientData($clientid) {
- $channel = $this->getChannel();
- $lastid = 0;
- switch ($this->_cacheType) {
- case 'file':
- $clientPath = $this->_cacheBackend . DIRECTORY_SEPARATOR . 'client_'.$clientid;
- //_log(' '.__FILE__.' '.__LINE__.' | get client info from '.$clientPath);
- $clientinfo = unserialize(file_get_contents($clientPath));
- if (isset($clientinfo[$channel])) {
- $lastid = $clientinfo[$channel];
- }
- break;
- case 'memcache':
- //_log(' '.__FILE__.' '.__LINE__.' | get client info from client_'.$clientid);
- $clientinfo = $this->_cacheBackend->get('client_'.$clientid);
- if (isset($clientinfo[$channel])) {
- $lastid = $clientinfo[$channel];
- }
- break;
- }
- $data = $this->_getChannelData();
- //_log(' '.__FILE__.' '.__LINE__.' | channel data restored from storage '.print_r($data,1));
- //_log(' '.__FILE__.' '.__LINE__.' | checking for position '.$lastid);
- if (isset($data[$lastid])) {
- //_log(' '.__FILE__.' '.__LINE__.' | channel data found for client on position '.$lastid);
- $length = count($data) - $lastid;
- $result = array_slice($data,$lastid, $length, true);
- $keys = array_keys($result);
- $lastid = array_pop($keys);
- if ($lastid > 0) {
- $this->_setClientInfo($clientid, $lastid + 1);
- }
- return array_values($result);
- } else {
- //_log(' '.__FILE__.' '.__LINE__.' | no channel data found for client '.$lastid);
- return array();
- }
- }
- public function getClientChannels($clientid) {
- switch ($this->_cacheType) {
- case 'file':
- $clientPath = $this->_cacheBackend . DIRECTORY_SEPARATOR . 'client_'.$clientid;
- //_log(' '.__FILE__.' '.__LINE__.' | get client info from '.$clientPath);
- if (file_exists($clientPath)) {
- $clientinfo = unserialize(file_get_contents($clientPath));
- return($clientinfo);
- }
- break;
- case 'memcache':
- //_log(' '.__FILE__.' '.__LINE__.' | get client info from client_'.$clientid);
- $clientinfo = $this->_cacheBackend->get('client_'.$clientid);
- if ($clientinfo) {
- return $clientinfo;
- }
- break;
- }
- return false;
- }
-
- public function addClient($clientid) {
- //_log(' '.__FILE__.' '.__LINE__.' | add client '.$clientid);
- $data = $this->_getChannelData();
- $lastid = count($data);
- $this->_setClientInfo($clientid,$lastid);
- }
-
- public function removeClient($clientid) {
- switch ($this->_cacheType) {
- case 'file':
- $clientPath = $this->_cacheBackend . DIRECTORY_SEPARATOR . 'client_'.$clientid;
- $clientinfo = unserialize(file_get_contents($clientPath));
- foreach($clientinfo as $channel => $id) {
- $this->setChannel($channel);
- $this->_deleteChannelUser($clientId);
- }
- unlink($clientPath);
- break;
- case 'memcache':
- $clientinfo = $this->_cacheBackend->get('client_'.$clientid);
- foreach($clientinfo as $channel => $id) {
- $this->setChannel($channel);
- $this->_deleteChannelUser($clientid);
- }
- //_log(' '.__FILE__.' '.__LINE__.' | remove client .'.$clientid.' from channel '.$channel);
- $this->_cacheBackend->delete('client_'.$clientid);
- break;
- }
- }
- public function removeClientFromChannel($clientid) {
- //_log(' '.__FILE__.' '.__LINE__.' | add client '.$clientid);
- $data = $this->_getChannelData();
- $lastid = count($data);
- $this->_addChannelUser($clientid);
- $this->_setClientInfo($clientid,NULL);
- }
- public function addClientToChannel($clientid) {
- //_log(' '.__FILE__.' '.__LINE__.' | add client '.$clientid);
- $data = $this->_getChannelData();
- $lastid = count($data);
- $this->_addChannelUser($clientid);
- $this->_setClientInfo($clientid,$lastid);
- }
- public function addChannelData($data) {
- $channel = $this->getChannel();
- switch ($this->_cacheType) {
- case 'file':
- $channelPath = $this->_cacheBackend . DIRECTORY_SEPARATOR . 'channel_'.$channel;
- $channelinfo = unserialize(file_get_contents($channelPath));
- if (is_array($channelinfo)) {
- $channelinfo[] = $data;
- } else {
- $channelinfo[0] = $data;
- }
- //_log(' '.__FILE__.' '.__LINE__.' | set channel info to '.$channelPath);
- file_put_contents($channelPath, serialize($channelinfo));
- break;
- case 'memcache':
- $channelinfo = $this->_cacheBackend->get('channel_'.$channel);
- if (is_array($channelinfo)) {
- $channelinfo[] = $data;
- } else {
- $channelinfo = array();
- $channelinfo[0] = $data;
- }
- //_log(' '.__FILE__.' '.__LINE__.' | set channel info to channel_'.$channel);
- $this->_cacheBackend->set('channel_'.$channel,$channelinfo);
- break;
- }
- }
- protected function _getChannelData() {
- $channel = $this->getChannel();
- $channelinfo = array();
- switch ($this->_cacheType) {
- case 'file':
- $channelPath = $this->_cacheBackend . DIRECTORY_SEPARATOR . 'channel_'.$channel;
- //_log(' '.__FILE__.' '.__LINE__.' | get channel info from '.$channelPath);
- $channelinfo = unserialize(file_get_contents($channelPath));
- break;
- case 'memcache':
- //_log(' '.__FILE__.' '.__LINE__.' | get channel info from channel_'.$channel);
- $channelinfo = $this->_cacheBackend->get('channel_'.$channel);
- break;
- }
- return $channelinfo;
- }
- protected function _getChannelUsers() {
- $channel = $this->getChannel();
- $channelinfo = array();
- switch ($this->_cacheType) {
- case 'file':
- $channelUsersPath = $this->_cacheBackend . DIRECTORY_SEPARATOR . 'channelusers_'.$channel;
- //_log(' '.__FILE__.' '.__LINE__.' | get channel users from '.$channelPath);
- $channelusers = unserialize(file_get_contents($channelUsersPath));
- break;
- case 'memcache':
- //_log(' '.__FILE__.' '.__LINE__.' | get channel info from channel_'.$channel);
- $channelusers = $this->_cacheBackend->get('channelusers_'.$channel);
- break;
- }
- return $channelusers;
- }
- protected function _addChannelUser($clientid) {
- $users = $this->_getChannelUsers();
- if (!in_array($clientid,$users)) {
- $users[] = $clientid;
- $this->_saveChannelUsers($users);
- }
- }
- protected function _deleteChannelUser($clientid) {
- $users = $this->_getChannelUsers();
- if (in_array($clientid,$users)) {
- $users_flip = array_flip($users);
- unset($users_flip[$clientid]);
- $users = array_flip($users_flip);
- $this->_saveChannelUsers($users);
- }
- }
- protected function _saveChannelUsers($users) {
- $channel = $this->getChannel();
- switch ($this->_cacheType) {
- case 'file':
- $channelUsersPath = $this->_cacheBackend . DIRECTORY_SEPARATOR . 'channelusers_'.$channel;
- //_log(' '.__FILE__.' '.__LINE__.' | saving channel users to '.$channelUsersPath);
- file_put_contents($channelUsersPath, serialize($users));
- break;
- case 'memcache':
- //_log(' '.__FILE__.' '.__LINE__.' | save channel users to channelusers_'.$channel);
- $this->_cacheBackend->set('channelusers_'.$channel,$users);
- break;
- }
- }
- protected function _setClientInfo($clientid,$lastid = NULL) {
- $channel = $this->getChannel();
- //_log(' '.__FILE__.' '.__LINE__.' | store clientid,channel,lastid: '.$clientid.' - '.$channel.' - '.$lastid);
- switch ($this->_cacheType) {
- case 'file':
- $clientPath = $this->_cacheBackend . DIRECTORY_SEPARATOR . 'client_'.$clientid;
- //_log(' '.__FILE__.' '.__LINE__.' | store client info to '.$clientPath);
- $clientinfo = unserialize(file_get_contents($clientPath));
- if (is_null($lastid)) {
- unset($clientinfo[$channel]);
- } else {
- $clientinfo[$channel] = $lastid;
- }
- //_log(' '.__FILE__.' '.__LINE__.' | store client info to '.$clientPath.' :'.print_r($clientinfo,1));
- file_put_contents($clientPath, serialize($clientinfo));
- break;
- case 'memcache':
- $clientinfo = $this->_cacheBackend->get('client_'.$clientid);
- if (!is_array($clientinfo)) {
- $clientinfo = array();
- }
- if (isset($clientinfo[$channel])) {
- if (is_null($lastid)) {
- unset($clientinfo[$channel]);
- } else {
- $clientinfo[$channel] = $lastid;
- }
- } else {
- $clientinfo[$channel] = $lastid;
- }
- //_log(' '.__FILE__.' '.__LINE__.' | store client info to client_'.$clientid.' :'.print_r($clientinfo,1));
- $this->_cacheBackend->set('client_'.$clientid,$clientinfo);
- $val = $this->_cacheBackend->get('client_'.$clientid);
- //_log(' '.__FILE__.' '.__LINE__.' | client info stored :'.print_r($val,1));
- break;
- }
- }
- protected function _normalizeName($channel) {
- return str_replace(array('/'),array('_'),strtolower($channel));
- }
-
- protected function _loadBackend() {
- //_log(' '.__FILE__.' '.__LINE__.' | load storage backend');
- $memcache = false;
- if (class_exists('Memcache')) {
- $memcache = new Memcache;
- $memcache->connect($this->_memcacheServer, $this->_memcachePort);
- //_log(' '.__FILE__.' '.__LINE__.' | memcache version '.$memcache->getVersion());
- }
- //$memcache = false;
- if ($memcache) {
- //_log(' '.__FILE__.' '.__LINE__.' | storage backend = memcache ');
- $this->_cacheBackend = $memcache;
- $this->_cacheType = 'memcache';
- } else {
- //_log(' '.__FILE__.' '.__LINE__.' | storage backend = file based at '.sys_get_temp_dir());
- if (is_dir('/dev/shm')) {
- $this->_cacheBackend = '/dev/shm';
- } else {
- $this->_cacheBackend = sys_get_temp_dir();
- }
- $this->_cacheType = 'file';
- }
- }
- }