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/
49 class Realtime_channel extends Managed_DataObject
51 const TIMEOUT = 1800; // 30 minutes
53 public $__table = 'realtime_channel'; // table name
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
65 * Get an instance by key
67 * This is a utility method to get a single instance with a given key value.
69 * @param string $k Key to use to lookup (usually 'user_id' for this class)
70 * @param mixed $v Value to lookup
72 * @return Realtime_channel object found, or null for no hits
74 function staticGet($k, $v=null)
76 return Managed_DataObject::staticGet('Realtime_channel', $k, $v);
80 * Get an instance by compound key
82 * @param array $kv array of key-value mappings
84 * @return Realtime_channel object found, or null for no hits
88 return Managed_DataObject::pkeyGet('Realtime_channel', $kv);
92 * The One True Thingy that must be defined and declared.
94 public static function schemaDef()
97 'description' => 'A channel of realtime notice data',
99 'user_id' => array('type' => 'int',
101 'description' => 'user viewing page; can be null'),
102 'action' => array('type' => 'varchar',
105 'description' => 'page being viewed'),
106 'arg1' => array('type' => 'varchar',
109 'description' => 'page argument, like username or tag'),
110 'arg2' => array('type' => 'varchar',
113 'description' => 'second page argument, like tag for showstream'),
114 'channel_key' => array('type' => 'varchar',
117 'description' => 'shared secret key for this channel'),
118 'audience' => array('type' => 'integer',
121 'description' => 'reference count'),
122 'created' => array('type' => 'datetime',
124 'description' => 'date this record was created'),
125 'modified' => array('type' => 'datetime',
127 'description' => 'date this record was modified'),
129 'primary key' => array('channel_key'),
130 'unique keys' => array('realtime_channel_user_page_idx' => array('user_id', 'action', 'arg1', 'arg2')),
131 'foreign keys' => array(
132 'realtime_channel_user_id_fkey' => array('user', array('user_id' => 'id')),
135 'realtime_channel_modified_idx' => array('modified'),
136 'realtime_channel_page_idx' => array('action', 'arg1', 'arg2')
141 static function saveNew($user_id, $action, $arg1, $arg2)
143 $channel = new Realtime_channel();
145 $channel->user_id = $user_id;
146 $channel->action = $action;
147 $channel->arg1 = $arg1;
148 $channel->arg2 = $arg2;
149 $channel->audience = 1;
151 $channel->channel_key = common_good_rand(16); // 128-bit key, 32 hex chars
153 $channel->created = common_sql_now();
154 $channel->modified = $channel->created;
161 static function getChannel($user_id, $action, $arg1, $arg2)
163 $channel = self::fetchChannel($user_id, $action, $arg1, $arg2);
165 // Ignore (and delete!) old channels
167 if (!empty($channel)) {
168 $modTime = strtotime($channel->modified);
169 if ((time() - $modTime) > self::TIMEOUT) {
175 if (empty($channel)) {
176 $channel = self::saveNew($user_id, $action, $arg1, $arg2);
182 static function getAllChannels($action, $arg1, $arg2)
184 $channel = new Realtime_channel();
186 $channel->action = $action;
188 if (is_null($arg1)) {
189 $channel->whereAdd('arg1 is null');
191 $channel->arg1 = $arg1;
194 if (is_null($arg2)) {
195 $channel->whereAdd('arg2 is null');
197 $channel->arg2 = $arg2;
200 $channel->whereAdd('modified > "' . common_sql_date(time() - self::TIMEOUT) . '"');
204 if ($channel->find()) {
205 $channels = $channel->fetchAll();
211 static function fetchChannel($user_id, $action, $arg1, $arg2)
213 $channel = new Realtime_channel();
215 if (is_null($user_id)) {
216 $channel->whereAdd('user_id is null');
218 $channel->user_id = $user_id;
221 $channel->action = $action;
223 if (is_null($arg1)) {
224 $channel->whereAdd('arg1 is null');
226 $channel->arg1 = $arg1;
229 if (is_null($arg2)) {
230 $channel->whereAdd('arg2 is null');
232 $channel->arg2 = $arg2;
235 if ($channel->find(true)) {
236 $channel->increment();
246 $orig = clone($this);
248 $this->modified = common_sql_now();
249 $this->update($orig);
255 $orig = clone($this);
256 $this->modified = common_sql_now();
257 $this->update($orig);
263 if ($this->audience == 1) {
266 $orig = clone($this);
268 $this->modified = common_sql_now();
269 $this->update($orig);