summary refs log tree commit diff
path: root/contrib/vertobot
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--contrib/vertobot/.gitignore2
-rwxr-xr-xcontrib/vertobot/bot.pl309
-rwxr-xr-xcontrib/vertobot/bridge.pl493
-rw-r--r--contrib/vertobot/config.yaml32
-rw-r--r--contrib/vertobot/cpanfile14
-rw-r--r--contrib/vertobot/verto-example.json207
6 files changed, 0 insertions, 1057 deletions
diff --git a/contrib/vertobot/.gitignore b/contrib/vertobot/.gitignore
deleted file mode 100644

index 071a780574..0000000000 --- a/contrib/vertobot/.gitignore +++ /dev/null
@@ -1,2 +0,0 @@ -vucbot.yaml -vertobot.yaml diff --git a/contrib/vertobot/bot.pl b/contrib/vertobot/bot.pl deleted file mode 100755
index 31eed40925..0000000000 --- a/contrib/vertobot/bot.pl +++ /dev/null
@@ -1,309 +0,0 @@ -#!/usr/bin/env perl - -use strict; -use warnings; -use 5.010; # // -use IO::Socket::SSL qw(SSL_VERIFY_NONE); -use IO::Async::Loop; -use Net::Async::WebSocket::Client; -use Net::Async::Matrix 0.11_002; -use JSON; -use YAML; -use Data::UUID; -use Getopt::Long; -use Data::Dumper; - -binmode STDOUT, ":encoding(UTF-8)"; -binmode STDERR, ":encoding(UTF-8)"; - -my $loop = IO::Async::Loop->new; -# Net::Async::HTTP + SSL + IO::Poll doesn't play well. See -# https://rt.cpan.org/Ticket/Display.html?id=93107 -ref $loop eq "IO::Async::Loop::Poll" and - warn "Using SSL with IO::Poll causes known memory-leaks!!\n"; - -GetOptions( - 'C|config=s' => \my $CONFIG, - 'eval-from=s' => \my $EVAL_FROM, -) or exit 1; - -if( defined $EVAL_FROM ) { - # An emergency 'eval() this file' hack - $SIG{HUP} = sub { - my $code = do { - open my $fh, "<", $EVAL_FROM or warn( "Cannot read - $!" ), return; - local $/; <$fh> - }; - - eval $code or warn "Cannot eval() - $@"; - }; -} - -defined $CONFIG or die "Must supply --config\n"; - -my %CONFIG = %{ YAML::LoadFile( $CONFIG ) }; - -my %MATRIX_CONFIG = %{ $CONFIG{matrix} }; -# No harm in always applying this -$MATRIX_CONFIG{SSL_verify_mode} = SSL_VERIFY_NONE; - -# Track every Room object, so we can ->leave them all on shutdown -my %bot_matrix_rooms; - -my $bridgestate = {}; -my $roomid_by_callid = {}; - -my $bot_verto = Net::Async::WebSocket::Client->new( - on_frame => sub { - my ( $self, $frame ) = @_; - warn "[Verto] receiving $frame"; - on_verto_json($frame); - }, -); -$loop->add( $bot_verto ); - -my $sessid = lc new Data::UUID->create_str(); - -my $bot_matrix = Net::Async::Matrix->new( - %MATRIX_CONFIG, - on_log => sub { warn "log: @_\n" }, - on_invite => sub { - my ($matrix, $invite) = @_; - warn "[Matrix] invited to: " . $invite->{room_id} . " by " . $invite->{inviter} . "\n"; - - $matrix->join_room( $invite->{room_id} )->get; - }, - on_room_new => sub { - my ($matrix, $room) = @_; - - warn "[Matrix] have a room ID: " . $room->room_id . "\n"; - - $bot_matrix_rooms{$room->room_id} = $room; - - # log in to verto on behalf of this room - $bridgestate->{$room->room_id}->{sessid} = $sessid; - - $room->configure( - on_message => \&on_room_message, - ); - - my $f = send_verto_json_request("login", { - 'login' => $CONFIG{'verto-dialog-params'}{'login'}, - 'passwd' => $CONFIG{'verto-config'}{'passwd'}, - 'sessid' => $sessid, - }); - $matrix->adopt_future($f); - - # we deliberately don't paginate the room, as we only care about - # new calls - }, - on_unknown_event => \&on_unknown_event, - on_error => sub { - print STDERR "Matrix failure: @_\n"; - }, -); -$loop->add( $bot_matrix ); - -sub on_unknown_event -{ - my ($matrix, $event) = @_; - print Dumper($event); - - my $room_id = $event->{room_id}; - my %dp = %{$CONFIG{'verto-dialog-params'}}; - $dp{callID} = $bridgestate->{$room_id}->{callid}; - - if ($event->{type} eq 'm.call.invite') { - $bridgestate->{$room_id}->{matrix_callid} = $event->{content}->{call_id}; - $bridgestate->{$room_id}->{callid} = lc new Data::UUID->create_str(); - $bridgestate->{$room_id}->{offer} = $event->{content}->{offer}->{sdp}; - $bridgestate->{$room_id}->{gathered_candidates} = 0; - $roomid_by_callid->{ $bridgestate->{$room_id}->{callid} } = $room_id; - # no trickle ICE in verto apparently - } - elsif ($event->{type} eq 'm.call.candidates') { - # XXX: compare call IDs - if (!$bridgestate->{$room_id}->{gathered_candidates}) { - $bridgestate->{$room_id}->{gathered_candidates} = 1; - my $offer = $bridgestate->{$room_id}->{offer}; - my $candidate_block = { - audio => '', - video => '', - }; - foreach (@{$event->{content}->{candidates}}) { - if ($_->{sdpMid}) { - $candidate_block->{$_->{sdpMid}} .= "a=" . $_->{candidate} . "\r\n"; - } - else { - $candidate_block->{audio} .= "a=" . $_->{candidate} . "\r\n"; - $candidate_block->{video} .= "a=" . $_->{candidate} . "\r\n"; - } - } - - # XXX: assumes audio comes first - #$offer =~ s/(a=rtcp-mux[\r\n]+)/$1$candidate_block->{audio}/; - #$offer =~ s/(a=rtcp-mux[\r\n]+)/$1$candidate_block->{video}/; - - $offer =~ s/(m=video)/$candidate_block->{audio}$1/; - $offer =~ s/(.$)/$1\n$candidate_block->{video}$1/; - - my $f = send_verto_json_request("verto.invite", { - "sdp" => $offer, - "dialogParams" => \%dp, - "sessid" => $bridgestate->{$room_id}->{sessid}, - }); - $matrix->adopt_future($f); - } - else { - # ignore them, as no trickle ICE, although we might as well - # batch them up - # foreach (@{$event->{content}->{candidates}}) { - # push @{$bridgestate->{$room_id}->{candidates}}, $_; - # } - } - } - elsif ($event->{type} eq 'm.call.hangup') { - if ($bridgestate->{$room_id}->{matrix_callid} eq $event->{content}->{call_id}) { - my $f = send_verto_json_request("verto.bye", { - "dialogParams" => \%dp, - "sessid" => $bridgestate->{$room_id}->{sessid}, - }); - $matrix->adopt_future($f); - } - else { - warn "Ignoring unrecognised callid: ".$event->{content}->{call_id}; - } - } - else { - warn "Unhandled event: $event->{type}"; - } -} - -sub on_room_message -{ - my ($room, $from, $content) = @_; - my $room_id = $room->room_id; - warn "[Matrix] in $room_id: $from: " . $content->{body} . "\n"; -} - -Future->needs_all( - $bot_matrix->login( %{ $CONFIG{"matrix-bot"} } )->then( sub { - $bot_matrix->start; - }), - - $bot_verto->connect( - %{ $CONFIG{"verto-bot"} }, - on_connect_error => sub { die "Cannot connect to verto - $_[-1]" }, - on_resolve_error => sub { die "Cannot resolve to verto - $_[-1]" }, - )->on_done( sub { - warn("[Verto] connected to websocket"); - }), -)->get; - -$loop->attach_signal( - PIPE => sub { warn "pipe\n" } -); -$loop->attach_signal( - INT => sub { $loop->stop }, -); -$loop->attach_signal( - TERM => sub { $loop->stop }, -); - -eval { - $loop->run; -} or my $e = $@; - -# When the bot gets shut down, have it leave the rooms so it's clear to observers -# that it is no longer running. -# if( $CONFIG{"leave-on-shutdown"} // 1 ) { -# print STDERR "Removing bot from Matrix rooms...\n"; -# Future->wait_all( map { $_->leave->else_done() } values %bot_matrix_rooms )->get; -# } -# else { -# print STDERR "Leaving bot users in Matrix rooms.\n"; -# } - -die $e if $e; - -exit 0; - -{ - my $json_id; - my $requests; - - sub send_verto_json_request - { - $json_id ||= 1; - - my ($method, $params) = @_; - my $json = { - jsonrpc => "2.0", - method => $method, - params => $params, - id => $json_id, - }; - my $text = JSON->new->encode( $json ); - warn "[Verto] sending $text"; - $bot_verto->send_frame ( $text ); - my $request = $loop->new_future; - $requests->{$json_id} = $request; - $json_id++; - return $request; - } - - sub send_verto_json_response - { - my ($result, $id) = @_; - my $json = { - jsonrpc => "2.0", - result => $result, - id => $id, - }; - my $text = JSON->new->encode( $json ); - warn "[Verto] sending $text"; - $bot_verto->send_frame ( $text ); - } - - sub on_verto_json - { - my $json = JSON->new->decode( $_[0] ); - if ($json->{method}) { - if (($json->{method} eq 'verto.answer' && $json->{params}->{sdp}) || - $json->{method} eq 'verto.media') { - - my $room_id = $roomid_by_callid->{$json->{params}->{callID}}; - my $room = $bot_matrix_rooms{$room_id}; - - if ($json->{params}->{sdp}) { - # HACK HACK HACK HACK - $room->_do_POST_json( "/send/m.call.answer", { - call_id => $bridgestate->{$room_id}->{matrix_callid}, - version => 0, - answer => { - sdp => $json->{params}->{sdp}, - type => "answer", - }, - })->then( sub { - send_verto_json_response( { - method => $json->{method}, - }, $json->{id}); - })->get; - } - } - else { - warn ("[Verto] unhandled method: " . $json->{method}); - send_verto_json_response( { - method => $json->{method}, - }, $json->{id}); - } - } - elsif ($json->{result}) { - $requests->{$json->{id}}->done($json->{result}); - } - elsif ($json->{error}) { - $requests->{$json->{id}}->fail($json->{error}->{message}, $json->{error}); - } - } -} - diff --git a/contrib/vertobot/bridge.pl b/contrib/vertobot/bridge.pl deleted file mode 100755
index a551850f40..0000000000 --- a/contrib/vertobot/bridge.pl +++ /dev/null
@@ -1,493 +0,0 @@ -#!/usr/bin/env perl - -use strict; -use warnings; -use 5.010; # // -use IO::Socket::SSL qw(SSL_VERIFY_NONE); -use IO::Async::Loop; -use Net::Async::WebSocket::Client; -use Net::Async::HTTP; -use Net::Async::HTTP::Server; -use JSON; -use YAML; -use Data::UUID; -use Getopt::Long; -use Data::Dumper; -use URI::Encode qw(uri_encode uri_decode); - -binmode STDOUT, ":encoding(UTF-8)"; -binmode STDERR, ":encoding(UTF-8)"; - -my $msisdn_to_matrix = { - '447417892400' => '@matthew:matrix.org', -}; - -my $matrix_to_msisdn = {}; -foreach (keys %$msisdn_to_matrix) { - $matrix_to_msisdn->{$msisdn_to_matrix->{$_}} = $_; -} - - -my $loop = IO::Async::Loop->new; -# Net::Async::HTTP + SSL + IO::Poll doesn't play well. See -# https://rt.cpan.org/Ticket/Display.html?id=93107 -# ref $loop eq "IO::Async::Loop::Poll" and -# warn "Using SSL with IO::Poll causes known memory-leaks!!\n"; - -GetOptions( - 'C|config=s' => \my $CONFIG, - 'eval-from=s' => \my $EVAL_FROM, -) or exit 1; - -if( defined $EVAL_FROM ) { - # An emergency 'eval() this file' hack - $SIG{HUP} = sub { - my $code = do { - open my $fh, "<", $EVAL_FROM or warn( "Cannot read - $!" ), return; - local $/; <$fh> - }; - - eval $code or warn "Cannot eval() - $@"; - }; -} - -defined $CONFIG or die "Must supply --config\n"; - -my %CONFIG = %{ YAML::LoadFile( $CONFIG ) }; - -my %MATRIX_CONFIG = %{ $CONFIG{matrix} }; -# No harm in always applying this -$MATRIX_CONFIG{SSL_verify_mode} = SSL_VERIFY_NONE; - -my $bridgestate = {}; -my $roomid_by_callid = {}; - -my $sessid = lc new Data::UUID->create_str(); -my $as_token = $CONFIG{"matrix-bot"}->{as_token}; -my $hs_domain = $CONFIG{"matrix-bot"}->{domain}; - -my $http = Net::Async::HTTP->new(); -$loop->add( $http ); - -sub create_virtual_user -{ - my ($localpart) = @_; - my ( $response ) = $http->do_request( - method => "POST", - uri => URI->new( - $CONFIG{"matrix"}->{server}. - "/_matrix/client/api/v1/register?". - "access_token=$as_token&user_id=$localpart" - ), - content_type => "application/json", - content => <<EOT -{ - "type": "m.login.application_service", - "user": "$localpart" -} -EOT - )->get; - warn $response->as_string if ($response->code != 200); -} - -my $http_server = Net::Async::HTTP::Server->new( - on_request => sub { - my $self = shift; - my ( $req ) = @_; - - my $response; - my $path = uri_decode($req->path); - warn("request: $path"); - if ($path =~ m#/users/\@(\+.*)#) { - # when queried about virtual users, auto-create them in the HS - my $localpart = $1; - create_virtual_user($localpart); - $response = HTTP::Response->new( 200 ); - $response->add_content('{}'); - $response->content_type( "application/json" ); - } - elsif ($path =~ m#/transactions/(.*)#) { - my $event = JSON->new->decode($req->body); - print Dumper($event); - - my $room_id = $event->{room_id}; - my %dp = %{$CONFIG{'verto-dialog-params'}}; - $dp{callID} = $bridgestate->{$room_id}->{callid}; - - if ($event->{type} eq 'm.room.membership') { - my $membership = $event->{content}->{membership}; - my $state_key = $event->{state_key}; - my $room_id = $event->{state_id}; - - if ($membership eq 'invite') { - # autojoin invites - my ( $response ) = $http->do_request( - method => "POST", - uri => URI->new( - $CONFIG{"matrix"}->{server}. - "/_matrix/client/api/v1/rooms/$room_id/join?". - "access_token=$as_token&user_id=$state_key" - ), - content_type => "application/json", - content => "{}", - )->get; - warn $response->as_string if ($response->code != 200); - } - } - elsif ($event->{type} eq 'm.call.invite') { - my $room_id = $event->{room_id}; - $bridgestate->{$room_id}->{matrix_callid} = $event->{content}->{call_id}; - $bridgestate->{$room_id}->{callid} = lc new Data::UUID->create_str(); - $bridgestate->{$room_id}->{sessid} = $sessid; - # $bridgestate->{$room_id}->{offer} = $event->{content}->{offer}->{sdp}; - my $offer = $event->{content}->{offer}->{sdp}; - # $bridgestate->{$room_id}->{gathered_candidates} = 0; - $roomid_by_callid->{ $bridgestate->{$room_id}->{callid} } = $room_id; - # no trickle ICE in verto apparently - - my $f = send_verto_json_request("verto.invite", { - "sdp" => $offer, - "dialogParams" => \%dp, - "sessid" => $bridgestate->{$room_id}->{sessid}, - }); - $self->adopt_future($f); - } - # elsif ($event->{type} eq 'm.call.candidates') { - # # XXX: this could fire for both matrix->verto and verto->matrix calls - # # and races as it collects candidates. much better to just turn off - # # candidate gathering in the webclient entirely for now - # - # my $room_id = $event->{room_id}; - # # XXX: compare call IDs - # if (!$bridgestate->{$room_id}->{gathered_candidates}) { - # $bridgestate->{$room_id}->{gathered_candidates} = 1; - # my $offer = $bridgestate->{$room_id}->{offer}; - # my $candidate_block = ""; - # foreach (@{$event->{content}->{candidates}}) { - # $candidate_block .= "a=" . $_->{candidate} . "\r\n"; - # } - # # XXX: collate using the right m= line - for now assume audio call - # $offer =~ s/(a=rtcp.*[\r\n]+)/$1$candidate_block/; - # - # my $f = send_verto_json_request("verto.invite", { - # "sdp" => $offer, - # "dialogParams" => \%dp, - # "sessid" => $bridgestate->{$room_id}->{sessid}, - # }); - # $self->adopt_future($f); - # } - # else { - # # ignore them, as no trickle ICE, although we might as well - # # batch them up - # # foreach (@{$event->{content}->{candidates}}) { - # # push @{$bridgestate->{$room_id}->{candidates}}, $_; - # # } - # } - # } - elsif ($event->{type} eq 'm.call.answer') { - # grab the answer and relay it to verto as a verto.answer - my $room_id = $event->{room_id}; - - my $answer = $event->{content}->{answer}->{sdp}; - my $f = send_verto_json_request("verto.answer", { - "sdp" => $answer, - "dialogParams" => \%dp, - "sessid" => $bridgestate->{$room_id}->{sessid}, - }); - $self->adopt_future($f); - } - elsif ($event->{type} eq 'm.call.hangup') { - my $room_id = $event->{room_id}; - if ($bridgestate->{$room_id}->{matrix_callid} eq $event->{content}->{call_id}) { - my $f = send_verto_json_request("verto.bye", { - "dialogParams" => \%dp, - "sessid" => $bridgestate->{$room_id}->{sessid}, - }); - $self->adopt_future($f); - } - else { - warn "Ignoring unrecognised callid: ".$event->{content}->{call_id}; - } - } - else { - warn "Unhandled event: $event->{type}"; - } - - $response = HTTP::Response->new( 200 ); - $response->add_content('{}'); - $response->content_type( "application/json" ); - } - else { - warn "Unhandled path: $path"; - $response = HTTP::Response->new( 404 ); - } - - $req->respond( $response ); - }, -); -$loop->add( $http_server ); - -$http_server->listen( - addr => { family => "inet", socktype => "stream", port => 8009 }, - on_listen_error => sub { die "Cannot listen - $_[-1]\n" }, -); - -my $bot_verto = Net::Async::WebSocket::Client->new( - on_frame => sub { - my ( $self, $frame ) = @_; - warn "[Verto] receiving $frame"; - on_verto_json($frame); - }, -); -$loop->add( $bot_verto ); - -my $verto_connecting = $loop->new_future; -$bot_verto->connect( - %{ $CONFIG{"verto-bot"} }, - on_connected => sub { - warn("[Verto] connected to websocket"); - if (not $verto_connecting->is_done) { - $verto_connecting->done($bot_verto); - - send_verto_json_request("login", { - 'login' => $CONFIG{'verto-dialog-params'}{'login'}, - 'passwd' => $CONFIG{'verto-config'}{'passwd'}, - 'sessid' => $sessid, - }); - } - }, - on_connect_error => sub { die "Cannot connect to verto - $_[-1]" }, - on_resolve_error => sub { die "Cannot resolve to verto - $_[-1]" }, -); - -# die Dumper($verto_connecting); - -my $as_url = $CONFIG{"matrix-bot"}->{as_url}; - -Future->needs_all( - $http->do_request( - method => "POST", - uri => URI->new( $CONFIG{"matrix"}->{server}."/_matrix/appservice/v1/register" ), - content_type => "application/json", - content => <<EOT -{ - "as_token": "$as_token", - "url": "$as_url", - "namespaces": { "users": [ { "regex": "\@\\\\+.*", "exclusive": false } ] } -} -EOT - )->then( sub{ - my ($response) = (@_); - warn $response->as_string if ($response->code != 200); - return Future->done; - }), - $verto_connecting, -)->get; - -$loop->attach_signal( - PIPE => sub { warn "pipe\n" } -); -$loop->attach_signal( - INT => sub { $loop->stop }, -); -$loop->attach_signal( - TERM => sub { $loop->stop }, -); - -eval { - $loop->run; -} or my $e = $@; - -die $e if $e; - -exit 0; - -{ - my $json_id; - my $requests; - - sub send_verto_json_request - { - $json_id ||= 1; - - my ($method, $params) = @_; - my $json = { - jsonrpc => "2.0", - method => $method, - params => $params, - id => $json_id, - }; - my $text = JSON->new->encode( $json ); - warn "[Verto] sending $text"; - $bot_verto->send_frame ( $text ); - my $request = $loop->new_future; - $requests->{$json_id} = $request; - $json_id++; - return $request; - } - - sub send_verto_json_response - { - my ($result, $id) = @_; - my $json = { - jsonrpc => "2.0", - result => $result, - id => $id, - }; - my $text = JSON->new->encode( $json ); - warn "[Verto] sending $text"; - $bot_verto->send_frame ( $text ); - } - - sub on_verto_json - { - my $json = JSON->new->decode( $_[0] ); - if ($json->{method}) { - if (($json->{method} eq 'verto.answer' && $json->{params}->{sdp}) || - $json->{method} eq 'verto.media') { - - my $caller = $json->{dialogParams}->{caller_id_number}; - my $callee = $json->{dialogParams}->{destination_number}; - my $caller_user = '@+' . $caller . ':' . $hs_domain; - my $callee_user = $msisdn_to_matrix->{$callee} || warn "unrecogised callee: $callee"; - my $room_id = $roomid_by_callid->{$json->{params}->{callID}}; - - if ($json->{params}->{sdp}) { - $http->do_request( - method => "POST", - uri => URI->new( - $CONFIG{"matrix"}->{server}. - "/_matrix/client/api/v1/send/m.call.answer?". - "access_token=$as_token&user_id=$caller_user" - ), - content_type => "application/json", - content => JSON->new->encode({ - call_id => $bridgestate->{$room_id}->{matrix_callid}, - version => 0, - answer => { - sdp => $json->{params}->{sdp}, - type => "answer", - }, - }), - )->then( sub { - send_verto_json_response( { - method => $json->{method}, - }, $json->{id}); - })->get; - } - } - elsif ($json->{method} eq 'verto.invite') { - my $caller = $json->{dialogParams}->{caller_id_number}; - my $callee = $json->{dialogParams}->{destination_number}; - my $caller_user = '@+' . $caller . ':' . $hs_domain; - my $callee_user = $msisdn_to_matrix->{$callee} || warn "unrecogised callee: $callee"; - - my $alias = ($caller lt $callee) ? ($caller.'-'.$callee) : ($callee.'-'.$caller); - my $room_id; - - # create a virtual user for the caller if needed. - create_virtual_user($caller); - - # create a room of form #peer-peer and invite the callee - $http->do_request( - method => "POST", - uri => URI->new( - $CONFIG{"matrix"}->{server}. - "/_matrix/client/api/v1/createRoom?". - "access_token=$as_token&user_id=$caller_user" - ), - content_type => "application/json", - content => JSON->new->encode({ - room_alias_name => $alias, - invite => [ $callee_user ], - }), - )->then( sub { - my ( $response ) = @_; - my $resp = JSON->new->decode($response->content); - $room_id = $resp->{room_id}; - $roomid_by_callid->{$json->{params}->{callID}} = $room_id; - })->get; - - # join it - my ($response) = $http->do_request( - method => "POST", - uri => URI->new( - $CONFIG{"matrix"}->{server}. - "/_matrix/client/api/v1/join/$room_id?". - "access_token=$as_token&user_id=$caller_user" - ), - content_type => "application/json", - content => '{}', - )->get; - - $bridgestate->{$room_id}->{matrix_callid} = lc new Data::UUID->create_str(); - $bridgestate->{$room_id}->{callid} = $json->{dialogParams}->{callID}; - $bridgestate->{$room_id}->{sessid} = $sessid; - - # put the m.call.invite in there - $http->do_request( - method => "POST", - uri => URI->new( - $CONFIG{"matrix"}->{server}. - "/_matrix/client/api/v1/send/m.call.invite?". - "access_token=$as_token&user_id=$caller_user" - ), - content_type => "application/json", - content => JSON->new->encode({ - call_id => $bridgestate->{$room_id}->{matrix_callid}, - version => 0, - answer => { - sdp => $json->{params}->{sdp}, - type => "offer", - }, - }), - )->then( sub { - # acknowledge the verto - send_verto_json_response( { - method => $json->{method}, - }, $json->{id}); - })->get; - } - elsif ($json->{method} eq 'verto.bye') { - my $caller = $json->{dialogParams}->{caller_id_number}; - my $callee = $json->{dialogParams}->{destination_number}; - my $caller_user = '@+' . $caller . ':' . $hs_domain; - my $callee_user = $msisdn_to_matrix->{$callee} || warn "unrecogised callee: $callee"; - my $room_id = $roomid_by_callid->{$json->{params}->{callID}}; - - # put the m.call.hangup into the room - $http->do_request( - method => "POST", - uri => URI->new( - $CONFIG{"matrix"}->{server}. - "/_matrix/client/api/v1/send/m.call.hangup?". - "access_token=$as_token&user_id=$caller_user" - ), - content_type => "application/json", - content => JSON->new->encode({ - call_id => $bridgestate->{$room_id}->{matrix_callid}, - version => 0, - }), - )->then( sub { - # acknowledge the verto - send_verto_json_response( { - method => $json->{method}, - }, $json->{id}); - })->get; - } - else { - warn ("[Verto] unhandled method: " . $json->{method}); - send_verto_json_response( { - method => $json->{method}, - }, $json->{id}); - } - } - elsif ($json->{result}) { - $requests->{$json->{id}}->done($json->{result}); - } - elsif ($json->{error}) { - $requests->{$json->{id}}->fail($json->{error}->{message}, $json->{error}); - } - } -} - diff --git a/contrib/vertobot/config.yaml b/contrib/vertobot/config.yaml deleted file mode 100644
index 555d9389d7..0000000000 --- a/contrib/vertobot/config.yaml +++ /dev/null
@@ -1,32 +0,0 @@ -# Generic Matrix connection params -matrix: - server: 'matrix.org' - SSL: 1 - -# Bot-user connection details -matrix-bot: - user_id: '@vertobot:matrix.org' - password: '' - domain: 'matrix.org" - as_url: 'http://localhost:8009' - as_token: 'vertobot123' - -verto-bot: - host: webrtc.freeswitch.org - service: 8081 - url: "ws://webrtc.freeswitch.org:8081/" - -verto-config: - passwd: 1234 - -verto-dialog-params: - useVideo: false - useStereo: false - tag: "webcam" - login: "1008@webrtc.freeswitch.org" - destination_number: "9664" - caller_id_name: "FreeSWITCH User" - caller_id_number: "1008" - callID: "" - remote_caller_id_name: "Outbound Call" - remote_caller_id_number: "9664" diff --git a/contrib/vertobot/cpanfile b/contrib/vertobot/cpanfile deleted file mode 100644
index 800dc288ed..0000000000 --- a/contrib/vertobot/cpanfile +++ /dev/null
@@ -1,14 +0,0 @@ -requires 'parent', 0; -requires 'Future', '>= 0.29'; -requires 'Net::Async::Matrix', '>= 0.11_002'; -requires 'Net::Async::Matrix::Utils'; -requires 'Net::Async::WebSocket::Protocol', 0; -requires 'Data::UUID', 0; -requires 'IO::Async', '>= 0.63'; -requires 'IO::Async::SSL', 0; -requires 'IO::Socket::SSL', 0; -requires 'YAML', 0; -requires 'JSON', 0; -requires 'Getopt::Long', 0; - - diff --git a/contrib/vertobot/verto-example.json b/contrib/vertobot/verto-example.json deleted file mode 100644
index e0230498a6..0000000000 --- a/contrib/vertobot/verto-example.json +++ /dev/null
@@ -1,207 +0,0 @@ -# JSON is shown in *reverse* chronological order. -# Send v. Receive is implicit. - -{ - "jsonrpc": "2.0", - "id": 7, - "result": { - "callID": "12795aa6-2a8d-84ee-ce63-2e82ffe825ef", - "message": "CALL ENDED", - "causeCode": 16, - "cause": "NORMAL_CLEARING", - "sessid": "03a11060-3e14-23b6-c620-51b892c52983" - } -} - -{ - "jsonrpc": "2.0", - "method": "verto.bye", - "params": { - "dialogParams": { - "useVideo": false, - "useStereo": true, - "tag": "webcam", - "login": "1008@webrtc.freeswitch.org", - "destination_number": "9664", - "caller_id_name": "FreeSWITCH User", - "caller_id_number": "1008", - "callID": "12795aa6-2a8d-84ee-ce63-2e82ffe825ef", - "remote_caller_id_name": "Outbound Call", - "remote_caller_id_number": "9664" - }, - "sessid": "03a11060-3e14-23b6-c620-51b892c52983" - }, - "id": 7 -} - -{ - "jsonrpc": "2.0", - "id": 6, - "result": { - "callID": "12795aa6-2a8d-84ee-ce63-2e82ffe825ef", - "action": "toggleHold", - "holdState": "active", - "sessid": "03a11060-3e14-23b6-c620-51b892c52983" - } -} - -{ - "jsonrpc": "2.0", - "method": "verto.modify", - "params": { - "action": "toggleHold", - "dialogParams": { - "useVideo": false, - "useStereo": true, - "tag": "webcam", - "login": "1008@webrtc.freeswitch.org", - "destination_number": "9664", - "caller_id_name": "FreeSWITCH User", - "caller_id_number": "1008", - "callID": "12795aa6-2a8d-84ee-ce63-2e82ffe825ef", - "remote_caller_id_name": "Outbound Call", - "remote_caller_id_number": "9664" - }, - "sessid": "03a11060-3e14-23b6-c620-51b892c52983" - }, - "id": 6 -} - -{ - "jsonrpc": "2.0", - "id": 5, - "result": { - "callID": "12795aa6-2a8d-84ee-ce63-2e82ffe825ef", - "action": "toggleHold", - "holdState": "held", - "sessid": "03a11060-3e14-23b6-c620-51b892c52983" - } -} - -{ - "jsonrpc": "2.0", - "method": "verto.modify", - "params": { - "action": "toggleHold", - "dialogParams": { - "useVideo": false, - "useStereo": true, - "tag": "webcam", - "login": "1008@webrtc.freeswitch.org", - "destination_number": "9664", - "caller_id_name": "FreeSWITCH User", - "caller_id_number": "1008", - "callID": "12795aa6-2a8d-84ee-ce63-2e82ffe825ef", - "remote_caller_id_name": "Outbound Call", - "remote_caller_id_number": "9664" - }, - "sessid": "03a11060-3e14-23b6-c620-51b892c52983" - }, - "id": 5 -} - -{ - "jsonrpc": "2.0", - "id": 349819, - "result": { - "method": "verto.answer" - } -} - -{ - "jsonrpc": "2.0", - "id": 349819, - "method": "verto.answer", - "params": { - "callID": "12795aa6-2a8d-84ee-ce63-2e82ffe825ef", - "sdp": "v=0\no=FreeSWITCH 1417101432 1417101433 IN IP4 209.105.235.10\ns=FreeSWITCH\nc=IN IP4 209.105.235.10\nt=0 0\na=msid-semantic: WMS jA3rmwLVwUq1iE6TYEYHeLk2YTUlh1Vq\nm=audio 30134 RTP/SAVPF 111 126\na=rtpmap:111 opus/48000/2\na=fmtp:111 minptime=10; stereo=1\na=rtpmap:126 telephone-event/8000\na=silenceSupp:off - - - -\na=ptime:20\na=sendrecv\na=fingerprint:sha-256 F8:72:18:E9:72:89:99:22:5B:F8:B6:C6:C6:0D:C5:9B:B2:FB:BC:CA:8D:AB:13:8A:66:E1:37:38:A0:16:AA:41\na=rtcp-mux\na=rtcp:30134 IN IP4 209.105.235.10\na=ssrc:210967934 cname:rOIEajpw4FocakWY\na=ssrc:210967934 msid:jA3rmwLVwUq1iE6TYEYHeLk2YTUlh1Vq a0\na=ssrc:210967934 mslabel:jA3rmwLVwUq1iE6TYEYHeLk2YTUlh1Vq\na=ssrc:210967934 label:jA3rmwLVwUq1iE6TYEYHeLk2YTUlh1Vqa0\na=ice-ufrag:OKwTmGLapwmxn7OF\na=ice-pwd:MmaMwq8rVmtWxfLbQ7U2Ew3T\na=candidate:2372654928 1 udp 659136 209.105.235.10 30134 typ host generation 0\n" - } -} - -{ - "jsonrpc": "2.0", - "id": 4, - "result": { - "message": "CALL CREATED", - "callID": "12795aa6-2a8d-84ee-ce63-2e82ffe825ef", - "sessid": "03a11060-3e14-23b6-c620-51b892c52983" - } -} - -{ - "jsonrpc": "2.0", - "method": "verto.invite", - "params": { - "sdp": "v=0\r\no=- 1381685806032722557 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio\r\na=msid-semantic: WMS 6OOMyGAyJakjwaOOBtV7WcBCCuIW6PpuXsNg\r\nm=audio 63088 RTP/SAVPF 111 103 104 0 8 106 105 13 126\r\nc=IN IP4 81.138.8.249\r\na=rtcp:63088 IN IP4 81.138.8.249\r\na=candidate:460398169 1 udp 2122260223 10.10.79.10 49945 typ host generation 0\r\na=candidate:460398169 2 udp 2122260223 10.10.79.10 49945 typ host generation 0\r\na=candidate:3460887983 1 udp 2122194687 192.168.1.64 63088 typ host generation 0\r\na=candidate:3460887983 2 udp 2122194687 192.168.1.64 63088 typ host generation 0\r\na=candidate:945327227 1 udp 1685987071 81.138.8.249 63088 typ srflx raddr 192.168.1.64 rport 63088 generation 0\r\na=candidate:945327227 2 udp 1685987071 81.138.8.249 63088 typ srflx raddr 192.168.1.64 rport 63088 generation 0\r\na=candidate:1441981097 1 tcp 1518280447 10.10.79.10 0 typ host tcptype active generation 0\r\na=candidate:1441981097 2 tcp 1518280447 10.10.79.10 0 typ host tcptype active generation 0\r\na=candidate:2160789855 1 tcp 1518214911 192.168.1.64 0 typ host tcptype active generation 0\r\na=candidate:2160789855 2 tcp 1518214911 192.168.1.64 0 typ host tcptype active generation 0\r\na=ice-ufrag:cP4qeRhn0LpcpA88\r\na=ice-pwd:fREmgSkXsDLGUUH1bwfrBQhW\r\na=ice-options:google-ice\r\na=fingerprint:sha-256 AF:35:64:1B:62:8A:EF:27:AE:2B:88:2E:FE:78:29:0B:08:DA:64:6C:DE:02:57:E3:EE:B1:D7:86:B8:36:8F:B0\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=sendrecv\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=fmtp:111 minptime=10; stereo=1\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:126 telephone-event/8000\r\na=maxptime:60\r\na=ssrc:558827154 cname:vdKHBNqa17t2gmE3\r\na=ssrc:558827154 msid:6OOMyGAyJakjwaOOBtV7WcBCCuIW6PpuXsNg bf1303fb-9833-4d7d-b9e4-b32cfe04acc3\r\na=ssrc:558827154 mslabel:6OOMyGAyJakjwaOOBtV7WcBCCuIW6PpuXsNg\r\na=ssrc:558827154 label:bf1303fb-9833-4d7d-b9e4-b32cfe04acc3\r\n", - "dialogParams": { - "useVideo": false, - "useStereo": true, - "tag": "webcam", - "login": "1008@webrtc.freeswitch.org", - "destination_number": "9664", - "caller_id_name": "FreeSWITCH User", - "caller_id_number": "1008", - "callID": "12795aa6-2a8d-84ee-ce63-2e82ffe825ef", - "remote_caller_id_name": "Outbound Call", - "remote_caller_id_number": "9664" - }, - "sessid": "03a11060-3e14-23b6-c620-51b892c52983" - }, - "id": 4 -} - -{ - "jsonrpc": "2.0", - "id": 3, - "result": { - "message": "logged in", - "sessid": "03a11060-3e14-23b6-c620-51b892c52983" - } -} - -{ - "jsonrpc": "2.0", - "id": 1, - "error": { - "code": -32000, - "message": "Authentication Required" - } -} - -{ - "jsonrpc": "2.0", - "method": "login", - "params": { - "login": "1008@webrtc.freeswitch.org", - "passwd": "1234", - "sessid": "03a11060-3e14-23b6-c620-51b892c52983" - }, - "id": 3 -} - -{ - "jsonrpc": "2.0", - "id": 2, - "error": { - "code": -32000, - "message": "Authentication Required" - } -} - -{ - "jsonrpc": "2.0", - "method": "login", - "params": { - "sessid": "03a11060-3e14-23b6-c620-51b892c52983" - }, - "id": 1 -} - -{ - "jsonrpc": "2.0", - "method": "login", - "params": { - "sessid": "03a11060-3e14-23b6-c620-51b892c52983" - }, - "id": 2 -}