]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Realtime/Realtime_channel.php
The overloaded DB_DataObject function staticGet is now called getKV
[quix0rs-gnu-social.git] / plugins / Realtime / Realtime_channel.php
1 <?php
2 /**
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2011, StatusNet, Inc.
5  *
6  * A channel for real-time browser data
7  *
8  * PHP version 5
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Affero General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Affero General Public License for more details.
19  *
20  * You should have received a copy of the GNU Affero General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * @category  Realtime
24  * @package   StatusNet
25  * @author    Evan Prodromou <evan@status.net>
26  * @copyright 2011 StatusNet, Inc.
27  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
28  * @link      http://status.net/
29  */
30
31 if (!defined('STATUSNET')) {
32     exit(1);
33 }
34
35 /**
36  * A channel for real-time browser data
37  *
38  * For each user currently browsing the site, we want to know which page they're on
39  * so we can send real-time updates to their browser.
40  *
41  * @category Realtime
42  * @package  StatusNet
43  * @author   Evan Prodromou <evan@status.net>
44  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
45  * @link     http://status.net/
46  *
47  * @see      DB_DataObject
48  */
49 class Realtime_channel extends Managed_DataObject
50 {
51     const TIMEOUT = 1800; // 30 minutes
52
53     public $__table = 'realtime_channel'; // table name
54
55     public $user_id;       // int -> user.id, can be null
56     public $action;        // string
57     public $arg1;          // argument
58     public $arg2;          // argument, usually null
59     public $channel_key;   // 128-bit shared secret key
60     public $audience;      // listener count
61     public $created;       // created date
62     public $modified;      // modified date
63
64     /**
65      * Get an instance by compound key
66      *
67      * @param array $kv array of key-value mappings
68      *
69      * @return Realtime_channel object found, or null for no hits
70      */
71     function pkeyGet($kv)
72     {
73         return Managed_DataObject::pkeyGet('Realtime_channel', $kv);
74     }
75
76     /**
77      * The One True Thingy that must be defined and declared.
78      */
79     public static function schemaDef()
80     {
81         return array(
82             'description' => 'A channel of realtime notice data',
83             'fields' => array(
84                 'user_id' => array('type' => 'int',
85                                    'not null' => false,
86                                    'description' => 'user viewing page; can be null'),
87                 'action' => array('type' => 'varchar',
88                                   'length' => 255,
89                                   'not null' => true,
90                                   'description' => 'page being viewed'),
91                 'arg1' => array('type' => 'varchar',
92                                 'length' => 255,
93                                 'not null' => false,
94                                 'description' => 'page argument, like username or tag'),
95                 'arg2' => array('type' => 'varchar',
96                                 'length' => 255,
97                                 'not null' => false,
98                                 'description' => 'second page argument, like tag for showstream'),
99                 'channel_key' => array('type' => 'varchar',
100                                'length' => 32,
101                                'not null' => true,
102                                'description' => 'shared secret key for this channel'),
103                 'audience' => array('type' => 'integer',
104                                     'not null' => true,
105                                     'default' => 0,
106                                     'description' => 'reference count'),
107                 'created' => array('type' => 'datetime',
108                                    'not null' => true,
109                                    'description' => 'date this record was created'),
110                 'modified' => array('type' => 'datetime',
111                                     'not null' => true,
112                                     'description' => 'date this record was modified'),
113             ),
114             'primary key' => array('channel_key'),
115             'unique keys' => array('realtime_channel_user_page_idx' => array('user_id', 'action', 'arg1', 'arg2')),
116             'foreign keys' => array(
117                 'realtime_channel_user_id_fkey' => array('user', array('user_id' => 'id')),
118             ),
119             'indexes' => array(
120                 'realtime_channel_modified_idx' => array('modified'),
121                 'realtime_channel_page_idx' => array('action', 'arg1', 'arg2')
122             ),
123         );
124     }
125
126     static function saveNew($user_id, $action, $arg1, $arg2)
127     {
128         $channel = new Realtime_channel();
129
130         $channel->user_id = $user_id;
131         $channel->action  = $action;
132         $channel->arg1    = $arg1;
133         $channel->arg2    = $arg2;
134         $channel->audience  = 1;
135
136         $channel->channel_key = common_good_rand(16); // 128-bit key, 32 hex chars
137
138         $channel->created  = common_sql_now();
139         $channel->modified = $channel->created;
140
141         $channel->insert();
142
143         return $channel;
144     }
145
146     static function getChannel($user_id, $action, $arg1, $arg2)
147     {
148         $channel = self::fetchChannel($user_id, $action, $arg1, $arg2);
149
150         // Ignore (and delete!) old channels
151
152         if (!empty($channel)) {
153             $modTime = strtotime($channel->modified);
154             if ((time() - $modTime) > self::TIMEOUT) {
155                 $channel->delete();
156                 $channel = null;
157             }
158         }
159
160         if (empty($channel)) {
161             $channel = self::saveNew($user_id, $action, $arg1, $arg2);
162         }
163
164         return $channel;
165     }
166
167     static function getAllChannels($action, $arg1, $arg2)
168     {
169         $channel = new Realtime_channel();
170
171         $channel->action = $action;
172
173         if (is_null($arg1)) {
174             $channel->whereAdd('arg1 is null');
175         } else {
176             $channel->arg1 = $arg1;
177         }
178
179         if (is_null($arg2)) {
180             $channel->whereAdd('arg2 is null');
181         } else {
182             $channel->arg2 = $arg2;
183         }
184
185         $channel->whereAdd('modified > "' . common_sql_date(time() - self::TIMEOUT) . '"');
186
187         $channels = array();
188
189         if ($channel->find()) {
190             $channels = $channel->fetchAll();
191         }
192
193         return $channels;
194     }
195
196     static function fetchChannel($user_id, $action, $arg1, $arg2)
197     {
198         $channel = new Realtime_channel();
199
200         if (is_null($user_id)) {
201             $channel->whereAdd('user_id is null');
202         } else {
203             $channel->user_id = $user_id;
204         }
205
206         $channel->action = $action;
207
208         if (is_null($arg1)) {
209             $channel->whereAdd('arg1 is null');
210         } else {
211             $channel->arg1 = $arg1;
212         }
213
214         if (is_null($arg2)) {
215             $channel->whereAdd('arg2 is null');
216         } else {
217             $channel->arg2 = $arg2;
218         }
219
220         if ($channel->find(true)) {
221             $channel->increment();
222             return $channel;
223         } else {
224             return null;
225         }
226     }
227
228     function increment()
229     {
230         // XXX: race
231         $orig = clone($this);
232         $this->audience++;
233         $this->modified = common_sql_now();
234         $this->update($orig);
235     }
236
237     function touch()
238     {
239         // XXX: race
240         $orig = clone($this);
241         $this->modified = common_sql_now();
242         $this->update($orig);
243     }
244
245     function decrement()
246     {
247         // XXX: race
248         if ($this->audience == 1) {
249             $this->delete();
250         } else {
251             $orig = clone($this);
252             $this->audience--;
253             $this->modified = common_sql_now();
254             $this->update($orig);
255         }
256     }
257 }