3 * StatusNet - the distributed open-source microblogging tool
4 * Copyright (C) 2011, StatusNet, Inc.
6 * A channel for real-time browser data
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.
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.
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/>.
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/
31 if (!defined('STATUSNET')) {
36 * A channel for real-time browser data
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.
43 * @author Evan Prodromou <evan@status.net>
44 * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
45 * @link http://status.net/
50 class Realtime_channel extends Managed_DataObject
52 const TIMEOUT = 1800; // 30 minutes
54 public $__table = 'realtime_channel'; // table name
56 public $user_id; // int -> user.id, can be null
57 public $action; // string
58 public $arg1; // argument
59 public $arg2; // argument, usually null
60 public $channel_key; // 128-bit shared secret key
61 public $audience; // listener count
62 public $created; // created date
63 public $modified; // modified date
66 * Get an instance by key
68 * This is a utility method to get a single instance with a given key value.
70 * @param string $k Key to use to lookup (usually 'user_id' for this class)
71 * @param mixed $v Value to lookup
73 * @return Realtime_channel object found, or null for no hits
76 function staticGet($k, $v=null)
78 return Managed_DataObject::staticGet('Realtime_channel', $k, $v);
82 * Get an instance by compound key
84 * @param array $kv array of key-value mappings
86 * @return Realtime_channel object found, or null for no hits
91 return Managed_DataObject::pkeyGet('Realtime_channel', $kv);
95 * The One True Thingy that must be defined and declared.
97 public static function schemaDef()
100 'description' => 'A channel of realtime notice data',
102 'user_id' => array('type' => 'int',
104 'description' => 'user viewing page; can be null'),
105 'action' => array('type' => 'varchar',
108 'description' => 'page being viewed'),
109 'arg1' => array('type' => 'varchar',
112 'description' => 'page argument, like username or tag'),
113 'arg2' => array('type' => 'varchar',
116 'description' => 'second page argument, like tag for showstream'),
117 'channel_key' => array('type' => 'varchar',
120 'description' => 'shared secret key for this channel'),
121 'audience' => array('type' => 'integer',
124 'description' => 'reference count'),
125 'created' => array('type' => 'datetime',
127 'description' => 'date this record was created'),
128 'modified' => array('type' => 'datetime',
130 'description' => 'date this record was modified'),
132 'primary key' => array('channel_key'),
133 'unique keys' => array('realtime_channel_user_page_idx' => array('user_id', 'action', 'arg1', 'arg2')),
134 'foreign keys' => array(
135 'realtime_channel_user_id_fkey' => array('user', array('user_id' => 'id')),
138 'realtime_channel_modified_idx' => array('modified'),
139 'realtime_channel_page_idx' => array('action', 'arg1', 'arg2')
144 static function saveNew($user_id, $action, $arg1, $arg2)
146 $channel = new Realtime_channel();
148 $channel->user_id = $user_id;
149 $channel->action = $action;
150 $channel->arg1 = $arg1;
151 $channel->arg2 = $arg2;
152 $channel->audience = 1;
154 $channel->channel_key = common_good_rand(16); // 128-bit key, 32 hex chars
156 $channel->created = common_sql_now();
157 $channel->modified = $channel->created;
164 static function getChannel($user_id, $action, $arg1, $arg2)
166 $channel = self::fetchChannel($user_id, $action, $arg1, $arg2);
168 // Ignore (and delete!) old channels
170 if (!empty($channel)) {
171 $modTime = strtotime($channel->modified);
172 if ((time() - $modTime) > self::TIMEOUT) {
178 if (empty($channel)) {
179 $channel = self::saveNew($user_id, $action, $arg1, $arg2);
185 static function getAllChannels($action, $arg1, $arg2)
187 $channel = new Realtime_channel();
189 $channel->action = $action;
191 if (is_null($arg1)) {
192 $channel->whereAdd('arg1 is null');
194 $channel->arg1 = $arg1;
197 if (is_null($arg2)) {
198 $channel->whereAdd('arg2 is null');
200 $channel->arg2 = $arg2;
203 $channel->whereAdd('modified > "' . common_sql_date(time() - self::TIMEOUT) . '"');
207 if ($channel->find()) {
208 $channels = $channel->fetchAll();
214 static function fetchChannel($user_id, $action, $arg1, $arg2)
216 $channel = new Realtime_channel();
218 if (is_null($user_id)) {
219 $channel->whereAdd('user_id is null');
221 $channel->user_id = $user_id;
224 $channel->action = $action;
226 if (is_null($arg1)) {
227 $channel->whereAdd('arg1 is null');
229 $channel->arg1 = $arg1;
232 if (is_null($arg2)) {
233 $channel->whereAdd('arg2 is null');
235 $channel->arg2 = $arg2;
238 if ($channel->find(true)) {
239 $channel->increment();
249 $orig = clone($this);
251 $this->modified = common_sql_now();
252 $this->update($orig);
258 $orig = clone($this);
259 $this->modified = common_sql_now();
260 $this->update($orig);
266 if ($this->audience == 1) {
269 $orig = clone($this);
271 $this->modified = common_sql_now();
272 $this->update($orig);