diff --git a/api/js/jsapi/egw.js b/api/js/jsapi/egw.js index f1d3e5f597..5c3592e9cb 100644 --- a/api/js/jsapi/egw.js +++ b/api/js/jsapi/egw.js @@ -415,7 +415,8 @@ { egw.json('websocket', {}, undefined, this).openWebSocket( egw_script.getAttribute('data-websocket-url'), - JSON.parse(egw_script.getAttribute('data-websocket-tokens')) + JSON.parse(egw_script.getAttribute('data-websocket-tokens')), + parseInt(egw_script.getAttribute('data-websocket-account_id')) ); } } diff --git a/api/js/jsapi/egw_global.d.ts b/api/js/jsapi/egw_global.d.ts index e199a28468..db2c3d5ae1 100644 --- a/api/js/jsapi/egw_global.d.ts +++ b/api/js/jsapi/egw_global.d.ts @@ -685,11 +685,12 @@ declare class JsonRequest * Open websocket to push server (and keeps it open) * * @param {string} url this.websocket(s)://host:port - * @param {array} tokens tokens to subscribe too + * @param {array} tokens tokens to subscribe too: sesssion-, user- and instance-token (in that order!) + * @param {number} account_id to connect for * @param {function} error option error callback(_msg) used instead our default this.error * @param {int} reconnect timeout in ms (internal) */ - openWebSocket(url : string, tokens : string[], error : Function, reconnect : number); + openWebSocket(url : string, tokens : string[], account_id : number, error : Function, reconnect : number); } /** diff --git a/api/js/jsapi/egw_json.js b/api/js/jsapi/egw_json.js index 4e1b843f26..5ef159af12 100644 --- a/api/js/jsapi/egw_json.js +++ b/api/js/jsapi/egw_json.js @@ -98,11 +98,12 @@ egw.extend('json', egw.MODULE_WND_LOCAL, function(_app, _wnd) * Open websocket to push server (and keeps it open) * * @param {string} url this.websocket(s)://host:port - * @param {array} tokens tokens to subscribe too + * @param {array} tokens tokens to subscribe too: sesssion-, user- and instance-token (in that order!) + * @param {number} account_id to connect for * @param {function} error option error callback(_msg) used instead our default this.error * @param {int} reconnect timeout in ms (internal) */ - json_request.prototype.openWebSocket = function(url, tokens, error, reconnect) + json_request.prototype.openWebSocket = function(url, tokens, account_id, error, reconnect) { const min_reconnect_time = 1000; const max_reconnect_time = 300000; @@ -113,7 +114,8 @@ egw.extend('json', egw.MODULE_WND_LOCAL, function(_app, _wnd) { reconnect_time = min_reconnect_time; this.websocket.send(JSON.stringify({ - subscribe: tokens + subscribe: tokens, + account_id: parseInt(account_id) })); }, this); @@ -147,7 +149,7 @@ egw.extend('json', egw.MODULE_WND_LOCAL, function(_app, _wnd) // e.g. server process killed or network down // event.code is usually 1006 in this case console.log('[close] Connection died --> reconnect in '+reconnect_time+'ms'); - window.setTimeout(jQuery.proxy(this.openWebSocket, this, url, tokens, error, reconnect_time), reconnect_time); + window.setTimeout(jQuery.proxy(this.openWebSocket, this, url, tokens, account_id, error, reconnect_time), reconnect_time); } }, this); }, diff --git a/api/src/Json/Push.php b/api/src/Json/Push.php index 277afe991c..cad34d2f19 100644 --- a/api/src/Json/Push.php +++ b/api/src/Json/Push.php @@ -49,6 +49,18 @@ class Push extends Msg */ const SESSION = null; + /** + * How long to cache online status / maximum frequency for querying + */ + const INSTANCE_ONLINE_CACHE_EXPIRATION = 10; + + /** + * account_id's of users currently online + * + * @var array|null + */ + protected static $online; + /** * * @param int $account_id =null account_id to push message too or @@ -67,6 +79,37 @@ class Push extends Msg * @throws Exception\NotOnline if $account_id is not online */ protected function addGeneric($key, $data) + { + self::checkSetBackend(); + + self::$backend->addGeneric($this->account_id, $key, $data); + } + + /** + * Get users online / connected to push-server + * + * @return array of integer account_id currently available for push + */ + public function online() + { + if (!isset(self::$online)) + { + self::$online = Api\Cache::getInstance(__CLASS__, 'online', function() + { + self::checkSetBackend(); + + return self::$backend->online(); + }, [], self::INSTANCE_ONLINE_CACHE_EXPIRATION); + } + return self::$online; + } + + /** + * Check and if neccessary set push backend + * + * @throws Exception\NotOnline + */ + protected function checkSetBackend() { if (!isset(self::$backend)) { diff --git a/api/src/Json/PushBackend.php b/api/src/Json/PushBackend.php index 95d139656a..3e6f9402fe 100644 --- a/api/src/Json/PushBackend.php +++ b/api/src/Json/PushBackend.php @@ -27,4 +27,11 @@ interface PushBackend * @throws Exception\NotOnline if $account_id is not online */ public function addGeneric($account_id, $key, $data); + + /** + * Get users online / connected to push-server + * + * @return array of integer account_id currently available for push + */ + public function online(); } diff --git a/notifications/inc/class.notifications_push.inc.php b/notifications/inc/class.notifications_push.inc.php index 3d9287415f..f7c30226d7 100644 --- a/notifications/inc/class.notifications_push.inc.php +++ b/notifications/inc/class.notifications_push.inc.php @@ -135,5 +135,20 @@ class notifications_push implements Json\PushBackend { self::$db =& $GLOBALS['egw']->db; } + + /** + * 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); + } } notifications_push::init_static();