Browse Source

Fix #1164 Implement XEP-0410: MUC Self-Ping (Schrödinger's Chat) basic behavior

pull/1323/head
Timothée Jaussoin 1 year ago
parent
commit
117f90f1ea
  1. 1
      CHANGELOG.md
  2. 17
      app/widgets/Rooms/Rooms.php
  3. 57
      src/Movim/ChatroomPings.php
  4. 4
      src/Moxl/Stanza/Ping.php
  5. 34
      src/Moxl/Xec/Action/Ping/Room.php
  6. 2
      src/Moxl/Xec/Action/Ping/Server.php
  7. 39
      src/Moxl/Xec/Payload/Message.php
  8. 3
      src/Moxl/Xec/Payload/Presence.php

1
CHANGELOG.md

@ -3,6 +3,7 @@ Movim Changelog
v0.24.2 (master)
---------------------------
* Fix #1164 Implement XEP-0410: MUC Self-Ping (Schrödinger's Chat) basic behavior
* Fix #1317 Handle properly the from attribute from MAM messages
* Set a priority of XEP-0319: Last User Interaction in Presence over XEP-0203: Delayed Delivery
* Refactor the prepareDate and prepareTime functions

17
app/widgets/Rooms/Rooms.php

@ -10,6 +10,7 @@ use Movim\ChatStates;
use Movim\Widget\Base;
use App\Conference;
use Movim\ChatroomPings;
class Rooms extends Base
{
@ -250,20 +251,13 @@ class Rooms extends Base
$this->rpc('Chat_ajaxGet');
// We properly exit
$resource = $this->user->session->conferences()
$conference = $this->user->session->conferences()
->where('conference', $room)
->first();
if (!$resource) return;
$resource = $resource
->presences()
->where('mucjid', $this->user->id)
->first();
if (!$conference) return;
$resource = $resource
? $resource->resource
: null;
$resource = $conference->presence?->resource;
$jid = explodeJid($room);
$capability = \App\Info::where('server', $jid['server'])
@ -274,6 +268,9 @@ class Rooms extends Base
$this->user->messages()->where('jidfrom', $room)->delete();
}
// We clear the ping timer
ChatroomPings::getInstance()->clear($room);
// We clear the presences from the buffer cache and then the DB
$this->user->session->conferences()
->where('conference', $room)

57
src/Movim/ChatroomPings.php

@ -0,0 +1,57 @@
<?php
/*
* SPDX-FileCopyrightText: 2024 Jaussoin Timothée
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Movim;
use Moxl\Xec\Action\Ping\Room;
/**
* Handling XEP-0410: MUC Self-Ping (Schrödinger's Chat) pings and timeouts
*/
class ChatroomPings
{
protected static $instance;
private $_chatrooms = [];
private $_timeout = 5 * 60;
public static function getInstance()
{
if (!isset(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
public function touch(string $from)
{
global $loop;
$this->clear($from);
$this->_chatrooms[$from] = $loop->addTimer($this->_timeout, function () use ($from) {
$presence = \App\User::me()->session->conferences()
->where('conference', $from)
->first()?->presence;
if ($presence) {
$pingRoom = new Room;
$pingRoom->setResource($from . '/' . $presence->resource)
->setRoom($from)
->request();
}
});
}
public function clear(string $from)
{
global $loop;
if (array_key_exists($from, $this->_chatrooms)) {
$loop->cancelTimer($this->_chatrooms[$from]);
}
}
}

4
src/Moxl/Stanza/Ping.php

@ -6,12 +6,12 @@ use Movim\Session;
class Ping
{
public static function server()
public static function entity(?string $to = null)
{
$session = Session::start();
$dom = new \DOMDocument('1.0', 'UTF-8');
$ping = $dom->createElementNS('urn:xmpp:ping', 'ping');
\Moxl\API::request(\Moxl\API::iqWrapper($ping, $session->get('host'), 'get'));
\Moxl\API::request(\Moxl\API::iqWrapper($ping, $to ?? $session->get('host'), 'get'));
}
public static function pong($to, $id)

34
src/Moxl/Xec/Action/Ping/Room.php

@ -0,0 +1,34 @@
<?php
namespace Moxl\Xec\Action\Ping;
use Movim\ChatroomPings;
use Moxl\Xec\Action;
use Moxl\Stanza\Ping;
use Rooms;
use SimpleXMLElement;
/**
* XEP-0410: MUC Self-Ping (Schrödinger's Chat)
*/
class Room extends Action
{
protected ?string $_room = null;
protected ?string $_resource = null;
public function request()
{
$this->store();
Ping::entity($this->_resource);
}
public function handle(?SimpleXMLElement $stanza = null, ?SimpleXMLElement $parent = null)
{
ChatroomPings::getInstance()->touch($this->_room);
}
public function error(string $errorId, ?string $message = null)
{
(new Rooms())->ajaxExit($this->_room);
}
}

2
src/Moxl/Xec/Action/Ping/Server.php

@ -10,6 +10,6 @@ class Server extends Action
public function request()
{
$this->store();
Ping::server();
Ping::entity();
}
}

39
src/Moxl/Xec/Payload/Message.php

@ -3,30 +3,37 @@
namespace Moxl\Xec\Payload;
use App\BundleCapabilityResolver;
use Movim\ChatroomPings;
use Movim\ChatStates;
class Message extends Payload
{
public function handle(?\SimpleXMLElement $stanza = null, ?\SimpleXMLElement $parent = null)
{
if ($stanza->confirm
&& $stanza->confirm->attributes()->xmlns == 'http://jabber.org/protocol/http-auth') {
if (
$stanza->confirm
&& $stanza->confirm->attributes()->xmlns == 'http://jabber.org/protocol/http-auth'
) {
return;
}
// Retracted messages are handled by Retracted
if ($stanza->{'apply-to'}
&& $stanza->{'apply-to'}->attributes()->xmlns == 'urn:xmpp:fasten:0'
&& $stanza->{'apply-to'}->retract
&& $stanza->{'apply-to'}->retract->attributes()->xmlns == 'urn:xmpp:message-retract:0') {
if (
$stanza->{'apply-to'}
&& $stanza->{'apply-to'}->attributes()->xmlns == 'urn:xmpp:fasten:0'
&& $stanza->{'apply-to'}->retract
&& $stanza->{'apply-to'}->retract->attributes()->xmlns == 'urn:xmpp:message-retract:0'
) {
return;
}
// ...same with moderated messages
if ($stanza->{'apply-to'}
&& $stanza->{'apply-to'}->attributes()->xmlns == 'urn:xmpp:fasten:0'
&& $stanza->{'apply-to'}->moderated
&& $stanza->{'apply-to'}->moderated->attributes()->xmlns == 'urn:xmpp:message-moderate:0') {
if (
$stanza->{'apply-to'}
&& $stanza->{'apply-to'}->attributes()->xmlns == 'urn:xmpp:fasten:0'
&& $stanza->{'apply-to'}->moderated
&& $stanza->{'apply-to'}->moderated->attributes()->xmlns == 'urn:xmpp:message-moderate:0'
) {
return;
}
@ -47,9 +54,13 @@ class Message extends Payload
return;
}
if ($message->isMuc()) {
ChatroomPings::getInstance()->touch($message->jidfrom);
}
if ($stanza->composing || $stanza->paused || $stanza->active) {
$from = ($message->isMuc())
? $message->jidfrom.'/'.$message->resource
? $message->jidfrom . '/' . $message->resource
: $message->jidfrom;
if ($stanza->composing) {
@ -61,8 +72,10 @@ class Message extends Payload
}
}
if ($message->valid()
&& (!$message->isEmpty() || $message->isSubject())) {
if (
$message->valid()
&& (!$message->isEmpty() || $message->isSubject())
) {
$message->save();
$message = $message->fresh();

3
src/Moxl/Xec/Payload/Presence.php

@ -5,6 +5,7 @@ namespace Moxl\Xec\Payload;
use Movim\Session;
use App\Presence as DBPresence;
use App\PresenceBuffer;
use Movim\ChatroomPings;
class Presence extends Payload
{
@ -33,6 +34,8 @@ class Presence extends Payload
PresenceBuffer::getInstance()->append($presence, function () use ($presence, $stanza) {
if ($presence->muc) {
ChatroomPings::getInstance()->touch($presence->jid);
if ($presence->mucjid == \App\User::me()->id) {
// Spectrum2 specific bug, we can receive two self-presences, one with several caps items
$cCount = 0;

Loading…
Cancel
Save