PHPOpenChat PHP Cross Reference Customer Relationship Management

Source: /include/class.Channel_Buffer_Mem.inc - 472 lines - 14411 bytes - Summary - Text - Print

   1  <?php //-*-php-*-
   2  /*   ********************************************************************   **
   3  **   Copyright notice                                                       **
   4  **                                                                          **
   5  **   (c) 1995-2004 PHPOpenChat Development Team                             **
   6  **   http://phpopenchat.sourceforge.net/                                    **
   7  **                                                                          **
   8  **   All rights reserved                                                    **
   9  **                                                                          **
  10  **   This script is part of the PHPOpenChat project. The PHPOpenChat        **
  11  **   project is free software; you can redistribute it and/or modify        **
  12  **   it under the terms of the GNU General Public License as published by   **
  13  **   the Free Software Foundation; either version 2 of the License, or      **
  14  **   (at your option) any later version.                                    **
  15  **                                                                          **
  16  **   The GNU General Public License can be found at                         **
  17  **   http://www.gnu.org/copyleft/gpl.html.                                  **
  18  **   A copy is found in the textfile GPL and important notices to the       **
  19  **   license from the team is found in the textfile LICENSE distributed     **
  20  **   with these scripts.                                                    **
  21  **                                                                          **
  22  **   This script is distributed in the hope that it will be useful,         **
  23  **   but WITHOUT ANY WARRANTY; without even the implied warranty of         **
  24  **   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          **
  25  **   GNU General Public License for more details.                           **
  26  **                                                                          **
  27  **   This copyright notice MUST APPEAR in all copies of the script!         **
  28  **   ********************************************************************   */
  29  
  30  // Class Channel_Buffer based on Shared Memory (Unix only)
  31  
  32  //Get default values
  33  require_once (POC_BASE.'/config.inc.php');
  34  require_once (POC_INCLUDE_PATH.'/class.Logger.inc');
  35  
  36  // TODO: move remove_lock() to disconnect()
  37  // TODO: get_cur_idx() should read shared memory?
  38  // shared memory stores variables only under integer keys
  39  // therefore we need some constants
  40  
  41  define("CB_INIT_FLAG",0); // channel buffer init flag
  42  define("CB_MAX_LINE_IDX",1); // channel buffer maximum line number shm index
  43  define("CB_CUR_LINE_IDX",2); // channel buffer current line number shm index
  44  define("CB_LINE_OFFSET",3);  // channel buffer line array index offset
  45  // CB_LINE_MEMORY = strlen(serialize($maximum_length_line_object))
  46  define("CB_LINE_MEMORY",2048); // channel buffer shared memory per line in bytes
  47  
  48  /**
  49   * Channel buffer based on shared memory
  50   *
  51   * @author Frerk Meyer <frerk@sourceforge.net>
  52   * @access public
  53   * @version $Id: class.Channel_Buffer_Mem.inc,v 1.23.2.4 2004/03/02 21:05:17 letreo Exp $
  54   */
  55  
  56  class POC_Channel_Buffer {
  57  
  58    /**
  59     * channel name
  60     *
  61     * @var    string
  62     * @access public
  63     * @see    Channel_Buffer()
  64     */
  65    var $channel;
  66    
  67    /**
  68     * channel id 32-bit based on channel name
  69     * needed for shared memory and semaphores
  70     *
  71     * @var    string
  72     * @access private
  73     * @see    Channel_Buffer()
  74     */
  75    var $channel_id;
  76  
  77    /**
  78     * Semaphore Id for channel buffer locking
  79     * 
  80     * @var    int
  81     * @access private
  82     * @see    Channel_Buffer()
  83     * @see    lock()
  84     * @see    unlock()
  85     */
  86    var $sem_id;
  87  
  88    /**
  89     * Shared memory Id for channel buffer storage
  90     *
  91     * @var    int
  92     * @access private
  93     * @see    Channel_Buffer()
  94     */
  95    var $shm_id;
  96  
  97    /**
  98     * Maximum line index of channel buffer
  99     *
 100     * @var    int
 101     * @access private
 102     * @see    Channel_Buffer()
 103     */
 104    var $max_line_idx;
 105  
 106    /**
 107     * Current line index of channel buffer
 108     *
 109     * @var    int
 110     * @access private
 111     * @see    Channel_Buffer()
 112     */
 113    var $cur_line_idx;
 114  
 115    var $locked;
 116  
 117    var $connected;
 118  
 119    /**
 120    * Constructor
 121    *
 122    * create a new channel buffer object with name 'channel'
 123    *
 124    * @param  string $channel
 125    * @access public
 126    */
 127    function POC_Channel_Buffer ($channel) {
 128      $this->channel = $channel;
 129      $this->channel_id = crc32($channel);
 130      $this->max_line_idx = CB_MAX_LINE;
 131      $this->cur_line_idx = 0;
 132      $this->sem_id = 0;
 133      $this->shm_id = 0;
 134      $this->locked = 0;
 135      $this->connected = 0;
 136    }
 137  
 138    /**
 139    * Get maximum line index
 140    *
 141    * @access public
 142    * @return int max_line_idx
 143    */
 144    function get_max_line_idx() {
 145      if (!$this->connected) $this->connect();
 146      $this->lock();
 147      $this->cur_line_idx = shm_get_var($this->shm_id,CB_CUR_LINE_IDX);    
 148      return $this->max_line_idx;
 149      $this->unlock();
 150    }
 151  
 152    /**
 153    * Get current line index
 154    *
 155    * @access public
 156    * @return int cur_line_idx
 157    */
 158    function get_cur_line_idx() {
 159      if (!$this->connected) $this->connect();
 160      $this->lock();
 161      $this->cur_line_idx = shm_get_var($this->shm_id,CB_CUR_LINE_IDX);
 162      return $this->cur_line_idx;
 163      $this->unlock();
 164    }
 165  
 166    /**
 167    * Get channel name
 168    *
 169    * @access public
 170    * @return string channel
 171    */
 172    function get_name() {
 173      return $this->channel;
 174    }
 175  
 176    /**
 177     * Lock access to shared memory with a semaphore
 178     *
 179     * Semaphore is created by connect()
 180     *
 181     * @access private
 182     * @return int semaphore id
 183     * @see    connect()
 184     */
 185    function lock() {
 186      if (!$this->locked) { // lock only if unlocked
 187        // lock for only one process and read/write for owner only
 188        if (!sem_acquire($this->sem_id)) die ("can't aquire channel buffer semaphore");
 189        $this->locked = true;
 190      }
 191      return true;
 192    }
 193  
 194    /**
 195     * Unlock access to shared memory with a semaphore
 196     *
 197     * To remove sempahore use remove_lock()
 198     *
 199     * @access private
 200     * @return int semaphore id
 201     * @see    remove_lock()
 202     */
 203    function unlock() {
 204      if ($this->locked) { // unlock only if locked
 205        if (!sem_release($this->sem_id)) die ("can't release channel buffer semaphore");
 206        $this->locked = false; // status unlocked
 207      }
 208      return true;
 209    }
 210  
 211    /**
 212     * Remove lock semaphore
 213     * TODO: Test if really needed and working, fm
 214     * @access private
 215     * @return int semaphore id
 216     */
 217    function remove_lock() {
 218      if (!$this->sem_id) {
 219        if (!sem_remove($this->sem_id)) die ("can't remove semaphore");
 220        $this->sem_id = 0;
 221      }
 222      return true;
 223    }
 224  
 225    /**
 226    * Connect to the shared memory segment
 227    *
 228    * Create semaphore and shared memory segment if non-existant
 229    * Init if created
 230    *
 231    * @param string
 232    * @access public
 233    */
 234    function connect() {  // connect and init
 235      // get semaphore id, create one if none exists
 236      if (!($this->sem_id = sem_get($this->channel_id,1,0600))) die ("can't get semaphore id");
 237      // get shared mem id, create one if none exists
 238      if (!($this->shm_id = shm_attach($this->channel_id,CB_LINE_MEMORY*$this->max_line_idx,0600)))
 239        die ("can't attach to channel buffer shared memory");
 240      if (!$this->connected)
 241      { // shm already attached?
 242        $this->connected=true;
 243        $this->lock();
 244        if (!@shm_remove_var($this->shm_id,CB_INIT_FLAG))
 245        { // init if created
 246          shm_put_var($this->shm_id,CB_INIT_FLAG,1);
 247          shm_put_var($this->shm_id,CB_MAX_LINE_IDX,$this->max_line_idx);
 248          shm_put_var($this->shm_id,CB_CUR_LINE_IDX,$this->cur_line_idx);
 249          for ($i=0; $i<$this->max_line_idx; $i++)
 250          {
 251            if (!shm_put_var($this->shm_id,$i+CB_LINE_OFFSET,"$i"))
 252              die ("can't write line $i to channel memory");
 253          }
 254          // TODO else get values from channel!!!
 255          $this->max_line_idx = shm_get_var($this->shm_id,CB_MAX_LINE_IDX);
 256          $this->cur_line_idx = shm_get_var($this->shm_id,CB_CUR_LINE_IDX);
 257        }
 258        else
 259          shm_put_var($this->shm_id,CB_INIT_FLAG,1);
 260        
 261        $this->unlock();
 262      }
 263      return true;
 264    }
 265  
 266    function disconnect() {
 267      if ($this->connected) {
 268        $this->lock();
 269        
 270        
 271        // detach from channel memory and preserve data for other processes
 272        if (!shm_detach($this->shm_id)) die ("can't detach from channel buffer shared memory");
 273        $this->connected=false;
 274        $this->unlock();
 275      }
 276    }
 277  
 278  
 279    // initialize the channel buffer shared memory
 280    // creating a new one if necessary and
 281    // overwriting an existing one
 282  
 283    function init() {    
 284      return true; // TODO: delete init() calls in main
 285      // get shared mem id, create one if none exists
 286      if (!($this->shm_id = shm_attach($this->channel_id,CB_LINE_MEMORY*$this->max_line_idx,0600))) die ("can't attach to channel buffer shared memory");
 287      shm_put_var($this->shm_id,CB_INIT_FLAG,1);
 288      shm_put_var($this->shm_id,CB_MAX_LINE_IDX,$this->max_line_idx);
 289      shm_put_var($this->shm_id,CB_CUR_LINE_IDX,$this->cur_line_idx);
 290      for ($i=0; $i<$this->max_line_idx; $i++) {
 291        if (!shm_put_var($this->shm_id,$i+CB_LINE_OFFSET,"$i")) die ("can't write line $i to channel memory");
 292      }
 293      return true;
 294    }
 295  
 296    /**
 297    * Cleans up the channel buffer in database.
 298    *
 299    * @access public
 300    */
 301    function mkclean()
 302    {
 303      return;
 304    }
 305    
 306    function destroy() {
 307      $this->lock();
 308      // remove channel memory and destroy data
 309        if (!($this->shm_id = shm_attach($this->channel_id))) die ("can't attach to channel buffer shared memory");
 310        if (!shm_remove($this->shm_id)) die ("can't remove channel buffer shared memory");
 311      $this->unlock();
 312    }
 313  
 314    /**
 315    * Get current chat line object
 316    *
 317    * @access public
 318    * @return object Line
 319    */
 320    function get_cur_line() {
 321      $this->lock();
 322      // get current line
 323      $this->cur_line_idx = shm_get_var($this->shm_id,CB_CUR_LINE_IDX);
 324      $cur_line = shm_get_var($this->shm_id,$this->cur_line_idx+CB_LINE_OFFSET);
 325      $this->unlock();
 326      return $cur_line;
 327    }
 328  
 329    /**
 330    * Get all chat lines since given index
 331    *
 332    * Idea is get all lines that were written by others
 333    * since the last line you have written
 334    *
 335    * @param int $since_idx
 336    * @access public
 337    * @return array of instances of class Chat_Line
 338    */
 339    function get_lines_since($since_idx) {
 340  
 341      $i = 0;
 342  
 343      $this->lock();
 344      // get max and current line index
 345      $this->max_line_idx = shm_get_var($this->shm_id,CB_MAX_LINE_IDX);
 346      $this->cur_line_idx = shm_get_var($this->shm_id,CB_CUR_LINE_IDX);
 347      
 348      if (($since_idx < 0) || ($since_idx >= $this->max_line_idx))
 349        $_SESSION['logger']->error('Line index '.$line_idx.' out of bounds exception',__FILE__,__LINE__);
 350      // read all lines from since to current
 351      $i = $since_idx;
 352      $lines = array();
 353      while ($i <> $this->cur_line_idx) {
 354        $i = ++$i % $this->max_line_idx;  // modulo calculation for wrap around
 355        $lines[] = shm_get_var($this->shm_id,$i+CB_LINE_OFFSET);
 356      }
 357      // if array $lines[] is empty, nothing was put into buffer since last time
 358      $this->unlock();
 359      return $lines;
 360    }
 361    
 362    /**
 363    * Provides all lines within the buffer
 364    *
 365    * @param int $since_idx
 366    * @access public
 367    * @return array of instances of class Chat_Line
 368    */
 369    function get_all_lines_in_buffer()
 370    {
 371      // get max and current line index
 372      $max_line_idx = $this->get_max_line_idx();
 373      $cur_line_idx = $this->get_cur_line_idx();
 374      $since_idx = ++$cur_line_idx % $max_line_idx;
 375      
 376      return $this->get_lines_since($since_idx);
 377    }
 378  
 379    function put_line($line) {
 380      /*
 381      if( is_object($_SESSION['logger']) )
 382      {
 383        print_r($line);exit;
 384        $sender = $line->get_sender();
 385        //$recipient = $line->get_recipient()
 386        $_SESSION['logger']->line($sender->get_nick().': '.$line->get_said());
 387      }
 388      */
 389      $this->lock();
 390      // put line as current into channel buffer
 391      $this->cur_line_idx = shm_get_var($this->shm_id,CB_CUR_LINE_IDX);
 392      $this->max_line = shm_get_var($this->shm_id,CB_MAX_LINE_IDX);
 393      $this->cur_line_idx = ++$this->cur_line_idx % $this->max_line_idx;
 394      shm_put_var($this->shm_id,$this->cur_line_idx+CB_LINE_OFFSET,$line);
 395      shm_put_var($this->shm_id,CB_CUR_LINE_IDX,$this->cur_line_idx);
 396      $this->unlock();
 397      return $this->cur_line_idx; // return index of current line
 398    }
 399  
 400    /**
 401     * test method for class Channel_Buffer
 402     *
 403     * call like: POC_Channel_Buffer::test();
 404     * initialize 2 channel buffers, write some lines
 405     * read them, disconnect and reconnect,
 406     * and verify the lines again
 407     * test function must work identical in Mem and DB version
 408    **/
 409    function test() {
 410      $nl="<br>\n";
 411      // create 2 new channel buffers
 412      $cb1 = new POC_Channel_Buffer("schulhof");
 413      $cb2 = new POC_Channel_Buffer("lehrerzimmer");
 414      // connect (and create if non existent)
 415      $cb1->connect();
 416      $cb2->connect();
 417      // fill with test lines in mixed order
 418      $cb1_idx = $cb1->put_line("1:1");
 419      $cb1->put_line("1:2");
 420      $cb2->put_line("2:1");
 421      $cb2_idx = $cb2->put_line("2:2");
 422      $cb1->put_line("1:3");
 423      $cb2->put_line("2:3");
 424      // get test lines and print them
 425      // first channel buffer
 426      // expect "1:2","1:3"
 427      $lines = $cb1->get_lines_since($cb1_idx);
 428      foreach ($lines as $l) {
 429        print $cb1->get_name().": $l $nl";
 430      }
 431      // second channel buffer
 432      // expect "2:3"
 433      $lines = $cb2->get_lines_since($cb2_idx);
 434      foreach ($lines as $l) {
 435        print $cb2->get_name().": $l $nl";
 436      }
 437      // disconnect from channel buffer, don't remove them
 438      $cb1->disconnect();
 439      $cb2->disconnect();
 440      unset($cb1);
 441      unset($cb1_idx);
 442      unset($cb2);
 443      unset($cb2_idx);
 444      // reconnect to channel buffers
 445      $cb1 = new POC_Channel_Buffer("schulhof");
 446      $cb2 = new POC_Channel_Buffer("lehrerzimmer");
 447      $cb1->connect();
 448      $cb2->connect();
 449      // write some extra lines
 450      $cb1_idx = $cb1->get_cur_line_idx();
 451      $cb2_idx = $cb2->get_cur_line_idx();
 452      $cb1->put_line("1:4");
 453      $cb2->put_line("2:4");
 454      // get test lines and print them
 455      // first channel buffer
 456      // expect "1:4"
 457      $lines = $cb1->get_lines_since($cb1_idx);
 458      foreach ($lines as $l) {
 459        print $cb1->get_name().": $l $nl";
 460      }
 461      // second channel buffer
 462      // expect "2:4"
 463      $lines = $cb2->get_lines_since($cb2_idx);
 464      foreach ($lines as $l) {
 465        print $cb2->get_name().": $l $nl";
 466      }
 467      // destroy channel buffers (channel is removed)
 468      $cb1->destroy();
 469      $cb2->destroy();
 470    }
 471  }
 472  ?>

title

Description

title

Description

title

Description

title

title

Body