Browse Source

Fix #480, implement XEP-0215: External Service Discovery and use it to provide STUN/TURN servers to Visio

Fallback to the public list
pull/932/head
Timothée Jaussoin 6 years ago
parent
commit
ce299e038c
  1. 1
      CHANGELOG.md
  2. 1
      app/MessageBuffer.php
  3. 14
      app/Session.php
  4. 19
      app/widgets/Presence/Presence.php
  5. 23
      app/widgets/Visio/Visio.php
  6. 55
      app/widgets/Visio/visio.js
  7. 4
      app/widgets/Visio/visio.tpl
  8. 21
      database/migrations/20200419103403_add_external_services_to_sessions_table.php
  9. 7
      doap.xml
  10. 17
      lib/moxl/src/Moxl/Stanza/ExternalServices.php
  11. 44
      lib/moxl/src/Moxl/Xec/Action/ExternalServices/Get.php

1
CHANGELOG.md

@ -18,6 +18,7 @@ v0.17.2 (trunk)
* Add a PresenceBuffer to do mass insert of Presences in the SQL DB
* Complete and fix Jingle/WebRTC implementation in Movim, work on Compatibility with Conversations
* Add Audio-only call support
* Added support for XEP-0215: External Service Discovery
v0.17.1
---------------------------

1
app/MessageBuffer.php

@ -33,6 +33,7 @@ class MessageBuffer
} catch (\Exception $e) {
\Utils::error($e->getMessage());
}
$this->_models = collect();
}

14
app/Session.php

@ -101,6 +101,20 @@ class Session extends Model
$s->set('password', $password);
}
public function setExternalservicesAttribute(array $externalServices)
{
$this->attributes['externalservices'] = serialize($externalServices);
}
public function getExternalservicesAttribute()
{
if (isset($this->attributes['externalservices'])) {
return unserialize($this->attributes['externalservices']);
}
return null;
}
public function getUploadService()
{
return Info::where('server', 'like', '%' . $this->host)

19
app/widgets/Presence/Presence.php

@ -21,6 +21,7 @@ class Presence extends Base
$this->registerEvent('mypresence', 'onMyPresence');
$this->registerEvent('session_up', 'onSessionUp');
$this->registerEvent('session_down', 'onSessionDown');
$this->registerEvent('externalservices_get_handle', 'onExternalServices');
}
public function onSessionUp()
@ -35,6 +36,15 @@ class Presence extends Base
$p->request();
}
public function onExternalServices($packet)
{
$session = $this->user->session;
if ($session) {
$session->externalservices = $packet->content;
$session->save();
};
}
public function onMyPresence($packet)
{
$this->rpc('MovimTpl.fill', '#presence_widget', $this->preparePresence());
@ -62,6 +72,7 @@ class Presence extends Base
$this->ajaxFeedRefresh();
$this->ajaxServerDisco();
$this->ajaxProfileRefresh();
$this->ajaxExternalServicesGet();
}
public function ajaxAskLogout()
@ -133,6 +144,14 @@ class Presence extends Base
->request();
}
// We discover the server services
public function ajaxExternalServicesGet()
{
$c = new \Moxl\Xec\Action\ExternalServices\Get;
$c->setTo($this->user->session->host)
->request();
}
// We refresh the profile
public function ajaxProfileRefresh()
{

23
app/widgets/Visio/Visio.php

@ -199,7 +199,30 @@ class Visio extends Base
public function display()
{
$externalServices = [];
if ($this->user->session->externalservices) {
$turn = $stun = false;
foreach ($this->user->session->externalservices as $service) {
// One STUN/TURN server max
if ($service['type'] == 'stun' && $stun) continue;
if ($service['type'] == 'stun') $stun = true;
if ($service['type'] == 'turn' && $turn) continue;
if ($service['type'] == 'turn') $turn = true;
$url = $service['type'].':'.$service['host'];
$url .= !empty($service['port']) ? ':'.$service['port'] : '';
$item = ['urls' => $url];
if (isset($service['username']) && isset($service['password'])) {
$item['username'] = $service['username'];
$item['credential'] = $service['password'];
}
array_push($externalServices, $item);
}
}
$this->view->assign('withvideo', $this->getView() == 'visio');
$this->view->assign('externalservices', json_encode($externalServices));
$this->view->assign('contact', \App\Contact::firstOrNew(['id' => $this->get('f')]));
}
}

55
app/widgets/Visio/visio.js

@ -33,33 +33,38 @@ var Visio = {
Visio.localAudio = document.getElementById('audio');
Visio.remoteAudio = document.getElementById('remote_audio');
const servers = ['stun:stun01.sipphone.com',
'stun:stun.ekiga.net',
'stun:stun.fwdnet.net',
'stun:stun.ideasip.com',
'stun:stun.iptel.org',
'stun:stun.rixtelecom.se',
'stun:stun.schlund.de',
'stun:stun.l.google.com:19302',
'stun:stun1.l.google.com:19302',
'stun:stun2.l.google.com:19302',
'stun:stun3.l.google.com:19302',
'stun:stun4.l.google.com:19302',
'stun:stunserver.org',
'stun:stun.softjoys.com',
'stun:stun.voiparound.com',
'stun:stun.voipbuster.com',
'stun:stun.voipstunt.com',
'stun:stun.voxgratia.org',
'stun:stun.xten.com'
];
const shuffled = servers.sort(() => 0.5 - Math.random());
var iceServers = [];
if (Visio.externalServices.length > 0) {
iceServers = Visio.externalServices
} else {
const servers = ['stun:stun01.sipphone.com',
'stun:stun.ekiga.net',
'stun:stun.fwdnet.net',
'stun:stun.ideasip.com',
'stun:stun.iptel.org',
'stun:stun.rixtelecom.se',
'stun:stun.schlund.de',
'stun:stun.l.google.com:19302',
'stun:stun1.l.google.com:19302',
'stun:stun2.l.google.com:19302',
'stun:stun3.l.google.com:19302',
'stun:stun4.l.google.com:19302',
'stun:stunserver.org',
'stun:stun.softjoys.com',
'stun:stun.voiparound.com',
'stun:stun.voipbuster.com',
'stun:stun.voipstunt.com',
'stun:stun.voxgratia.org',
'stun:stun.xten.com'
];
const shuffled = servers.sort(() => 0.5 - Math.random());
iceServers = [{urls: shuffled.slice(0, 2)}];
}
var configuration = {
'iceServers': [
{urls: shuffled.slice(0, 2)}
]
'iceServers': iceServers
};
Visio.pc = new RTCPeerConnection(configuration);

4
app/widgets/Visio/visio.tpl

@ -63,5 +63,7 @@ Visio.states = {
connecting: '{$c->__('visio.connecting')}',
ended: '{$c->__('visio.ended')}',
declined: '{$c->__('visio.declined')}'
}
};
Visio.externalServices = {autoescape="off"}{$externalservices}{/autoescape};
</script>

21
database/migrations/20200419103403_add_external_services_to_sessions_table.php

@ -0,0 +1,21 @@
<?php
use Movim\Migration;
use Illuminate\Database\Schema\Blueprint;
class AddExternalServicesToSessionsTable extends Migration
{
public function up()
{
$this->schema->table('sessions', function (Blueprint $table) {
$table->text('externalservices')->nullable();
});
}
public function down()
{
$this->schema->table('sessions', function (Blueprint $table) {
$table->dropColumn('externalservices');
});
}
}

7
doap.xml

@ -261,6 +261,13 @@
<xmpp:version>2.0</xmpp:version>
</xmpp:SupportedXep>
</implements>
<implements>
<xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0215.html"/>
<xmpp:status>complete</xmpp:status>
<xmpp:version>0.7</xmpp:version>
</xmpp:SupportedXep>
</implements>
<implements>
<xmpp:SupportedXep>
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0231.html"/>

17
lib/moxl/src/Moxl/Stanza/ExternalServices.php

@ -0,0 +1,17 @@
<?php
namespace Moxl\Stanza;
use Moxl\Utils;
class ExternalServices
{
public static function request($to)
{
$dom = new \DOMDocument('1.0', 'UTF-8');
$query = $dom->createElementNS('urn:xmpp:extdisco:2', 'services');
$xml = \Moxl\API::iqWrapper($query, $to, 'get');
\Moxl\API::request($xml);
}
}

44
lib/moxl/src/Moxl/Xec/Action/ExternalServices/Get.php

@ -0,0 +1,44 @@
<?php
namespace Moxl\Xec\Action\ExternalServices;
use Moxl\Xec\Action;
use Moxl\Stanza\ExternalServices;
class Get extends Action
{
protected $_to;
public function request()
{
$this->store();
ExternalServices::request($this->_to);
}
public function handle($stanza, $parent = false)
{
\Utils::debug($stanza->asXML());
$services = [];
foreach ($stanza->services->service as $service) {
$item = [
'host' => (string)$service['host'],
'port' => (string)$service['port'],
'transport' => (string)$service['transport'],
'type' => (string)$service['type']
];
if ($service['username'] && $service['password']) {
$item['username'] = (string)$service['username'];
$item['password'] = (string)$service['password'];
}
array_push($services, $item);
}
if (!empty($services)) {
$this->pack($services);
$this->deliver();
}
}
}
Loading…
Cancel
Save