2014-08-22 19:26:22 +02:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Notifications: push via notification polling
|
|
|
|
*
|
|
|
|
* @link http://www.egroupware.org
|
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
|
|
* @package api
|
|
|
|
* @subpackage ajax
|
|
|
|
* @author Ralf Becker <rb@stylite.de>
|
|
|
|
* @version $Id$
|
|
|
|
*/
|
|
|
|
|
2016-03-20 17:45:42 +01:00
|
|
|
use EGroupware\Api;
|
2016-05-06 11:19:36 +02:00
|
|
|
use EGroupware\Api\Json;
|
2014-08-22 19:26:22 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Class to push via notification polling and other json requests from client-side
|
|
|
|
*/
|
2016-03-20 17:45:42 +01:00
|
|
|
class notifications_push implements Json\PushBackend
|
2014-08-22 19:26:22 +02:00
|
|
|
{
|
|
|
|
const APP = 'notifications';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Notification table in SQL database
|
|
|
|
*/
|
|
|
|
const TABLE = 'egw_notificationpopup';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Notification type
|
|
|
|
*/
|
|
|
|
const TYPE = 'push';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reference to global DB object
|
|
|
|
*
|
2016-05-06 11:19:36 +02:00
|
|
|
* @var Api\Db
|
2014-08-22 19:26:22 +02:00
|
|
|
*/
|
|
|
|
public static $db;
|
|
|
|
|
|
|
|
public static function get()
|
|
|
|
{
|
2020-04-02 11:16:55 +02:00
|
|
|
if (session_status() === PHP_SESSION_NONE)
|
|
|
|
{
|
|
|
|
$session_reopened = session_start();
|
|
|
|
}
|
2016-03-20 17:45:42 +01:00
|
|
|
$already_send =& Api\Cache::getSession(__CLASS__, 'already_send');
|
|
|
|
$max_id = Api\Cache::getInstance(__CLASS__, 'max_id');
|
2014-08-22 19:26:22 +02:00
|
|
|
|
|
|
|
if (!isset($already_send))
|
|
|
|
{
|
|
|
|
self::cleanup_push_msgs();
|
|
|
|
|
|
|
|
if (!isset($max_id))
|
|
|
|
{
|
|
|
|
$max_id = (int)self::$db->select(self::TABLE, 'MAX(notify_id)', false, __LINE__, __FILE__, false, '', self::APP)->fetchColumn();
|
2016-03-20 17:45:42 +01:00
|
|
|
Api\Cache::setInstance(__CLASS__, 'max_id', $max_id);
|
2014-08-22 19:26:22 +02:00
|
|
|
}
|
|
|
|
$already_send = $max_id;
|
|
|
|
}
|
|
|
|
elseif (isset($max_id) && $max_id > $already_send)
|
|
|
|
{
|
2016-03-20 17:45:42 +01:00
|
|
|
$response = Json\Response::get();
|
2014-08-22 19:26:22 +02:00
|
|
|
|
|
|
|
foreach(self::$db->select(self::TABLE, '*', array(
|
|
|
|
'account_id' => array(0, $GLOBALS['egw_info']['user']['account_id']),
|
|
|
|
'notify_type' => self::TYPE,
|
|
|
|
'notify_id > '.(int)$already_send,
|
|
|
|
), __LINE__, __FILE__, false, 'ORDER BY notify_id ASC', self::APP) as $row)
|
|
|
|
{
|
|
|
|
$message = json_decode($row['notify_message'], true);
|
2014-08-22 19:27:36 +02:00
|
|
|
//error_log(__METHOD__."() already_send=$already_send, message=".array2string($message));
|
2014-08-22 19:26:22 +02:00
|
|
|
if (is_array($message) && method_exists($response, $message['method']))
|
|
|
|
{
|
|
|
|
call_user_func_array(array($response, $message['method']), (array)$message['data']);
|
|
|
|
}
|
|
|
|
$already_send = $row['notify_id'];
|
|
|
|
}
|
|
|
|
}
|
2020-04-02 11:16:55 +02:00
|
|
|
if (!empty($session_reopened))
|
|
|
|
{
|
|
|
|
session_write_close();
|
|
|
|
}
|
2014-08-22 19:27:36 +02:00
|
|
|
//error_log(__METHOD__."() max_id=$max_id, already_sent=$already_send");
|
2014-08-22 19:26:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds any type of data to the message
|
|
|
|
*
|
2019-11-04 09:29:49 +01:00
|
|
|
* @param int|null $account_id account_id to push message too, 0 for broadcast
|
|
|
|
* or null for curent session (we can only send to current user)
|
2014-08-22 19:26:22 +02:00
|
|
|
* @param string $key
|
|
|
|
* @param mixed $data
|
2018-01-26 16:24:21 +01:00
|
|
|
*
|
|
|
|
* This function doesn't throw exception regarding if user availability anymore,
|
|
|
|
* if you need to check if user is online or not please use this function
|
|
|
|
* Api\Session::notifications_active($account_id) in a clause.
|
2014-08-22 19:26:22 +02:00
|
|
|
*/
|
|
|
|
public function addGeneric($account_id, $key, $data)
|
|
|
|
{
|
2019-11-04 09:29:49 +01:00
|
|
|
if (!isset($account_id)) $account_id = $GLOBALS['egw_info']['user']['account_id'];
|
|
|
|
|
2014-08-22 19:26:22 +02:00
|
|
|
self::$db->insert(self::TABLE, array(
|
|
|
|
'account_id' => $account_id,
|
|
|
|
'notify_type' => self::TYPE,
|
|
|
|
'notify_message' => json_encode(array(
|
|
|
|
'method' => $key,
|
|
|
|
'data' => $data,
|
|
|
|
)),
|
|
|
|
), false, __LINE__, __FILE__, self::APP);
|
|
|
|
|
|
|
|
// cache highest id, to not poll database
|
2016-03-20 17:45:42 +01:00
|
|
|
Api\Cache::setInstance(__CLASS__, 'max_id', self::$db->get_last_insert_id(self::TABLE, 'notify_id'));
|
2014-08-22 19:26:22 +02:00
|
|
|
|
|
|
|
self::cleanup_push_msgs();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Delete push messges older then our heartbeat-limit (poll frequency of notifications)
|
|
|
|
*/
|
|
|
|
protected static function cleanup_push_msgs()
|
|
|
|
{
|
2016-06-05 16:41:02 +02:00
|
|
|
if (($ts = self::$db->from_unixtime(Api\Session::heartbeat_limit())))
|
|
|
|
{
|
|
|
|
self::$db->delete(self::TABLE, array(
|
|
|
|
'notify_type' => self::TYPE,
|
|
|
|
'notify_created < '.$ts,
|
|
|
|
), __LINE__, __FILE__, self::APP);
|
|
|
|
}
|
2014-08-22 19:26:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Init our static variables eg. database object
|
|
|
|
*/
|
|
|
|
public static function init_static()
|
|
|
|
{
|
|
|
|
self::$db =& $GLOBALS['egw']->db;
|
|
|
|
}
|
2020-04-20 13:07:58 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get users online / connected to push-server
|
|
|
|
*
|
|
|
|
* @return array of integer account_id currently available for push
|
|
|
|
*/
|
|
|
|
public function online()
|
|
|
|
{
|
|
|
|
$online = [];
|
|
|
|
foreach($GLOBALS['egw']->session->session_list(0, 'DESC', 'session_dla', true, ['notification_heartbeat IS NOT NULL']) as $row)
|
|
|
|
{
|
|
|
|
$online[] = (int)$row['account_id'];
|
|
|
|
}
|
|
|
|
return array_unique($online);
|
|
|
|
}
|
2014-08-22 19:26:22 +02:00
|
|
|
}
|
|
|
|
notifications_push::init_static();
|