How to automatically call a (browser) Client from a Twilio Conference Call? - ruby

Here is the scenario:
Assume we have a client with a capability to allow incoming calls, named "Roger".
James calls our Twilio number
conferenceName = "conftest"
caller_id = "+15555555555"
response = Twilio::TwiML::Response.new do |r|
r.Dial :callerId => caller_id do |d|
d.Client 'Roger'
end
end
Now we want Roger to get the incoming call on his browser, but we want the call to be a conference call, rather than a phone-to-browser call (not sure if there is a technical name for this). How can I connect James to Roger in a conference call?

Twilio developer evangelist here.
Sadly, this is not as simple as a single TwiML response. What you need to do is drop James into a conference call and, at the same time, initiate a call to Roger's client, which on answering would drop him into the conference call too.
With code (in a pseudo-sinatra format) that would look like:
conference_name = "conftest"
caller_id = "+15555555555"
# Set the Twilio number endpoint URL to /dial, this will drop James into
# the conference and initiate the call to Roger.
post '/dial' do
response = Twilio::TwiML::Response.new do |r|
r.Dial do |d|
d.Conference conference_name
end
end
# create a REST API client with your Account SID and Auth token
client = Twilio::REST::Client.new "AC123...", "XYZ456..."
client.calls.create from: caller_id, to: "Roger", url: "/client_dial"
response.to_xml
end
# This endpoint is the one that Twilio will hit when Roger answers the
# client incoming call. All we need to do is drop him into the same
# conference call.
post "/client_dial" do
response = Twilio::TwiML::Response.new do |r|
r.Dial do |d|
d.Conference conference_name
end
end
response.to_xml
end
Let me know if this helps!

Related

What do I write to Slack's Socket-Mode websocket endpoint to send a chat message using Ruby?

I am trying to write a simple Slack chatbot for my team using Ruby. It's a bit rough because Slack doesn't have official support for Ruby. Nevertheless, I've been able to open a websocket and listen to Slack events using this code I wrote:
# frozen_string_literal: true
require "async"
require "async/io/stream"
require "async/http/endpoint"
require "async/websocket/client"
require "excon"
require "json"
module Slack
class Client
Error = Class.new(StandardError)
AquisitionError = Class.new(Error)
ConnectionError = Class.new(Error)
CONNECTION_AQUISITION_ENDPOINT = "https://slack.com/api/apps.connections.open"
def initialize
#token = "my-app-token"
end
def connect
connection_info = Excon.post(CONNECTION_AQUISITION_ENDPOINT, headers: {
"Content-type": "application/x-www-form-urlencoded",
Authorization: "Bearer #{#token}",
})
result = JSON.parse(connection_info.body)
raise(AquisitionError) unless result["ok"] # better error later
websocket = Async::HTTP::Endpoint.parse(result["url"])
Async do |_task|
Async::WebSocket::Client.connect(websocket) do |connection|
payload = connection.read
raise(ConnectionError) unless connection_check(payload)
puts "Listening..."
handle(payload) while (payload = connection.read)
end
end
end
private
def connection_check(payload)
payload[:type] == "hello"
end
def handle(payload)
puts payload.inspect
end
end
end
The documentation leads me to believe that I can write JSON to this connection e.g.
connection.write({
# JSON to send a message in Slack here
# Probably need to specify the channel somehow
# Probably need to specify if I'm using markdown
# Have no idea what the form should be
})
But I haven't been able to figure out what form that JSON needs to take.
I was also running into this and trying to determine why the docs do not provide a clear answer. It appears that you do not infact send requests back over websockets, and instead use websockets only to accept requests.
Which would mean that you would use something like the webAPI to perform responsive actions, you can see this pattern in the PythonSDK with websockets example provided by Slack.
eg:
if req.type == "events_api":
# Acknowledge the request, this ack is sent back over websockets
# the format is: { 'envelope_id': req['envelope_id'] }
response = SocketModeResponse(envelope_id=req.envelope_id)
client.send_socket_mode_response(response)
# Add a reaction to the message if it's a new message
# notice that this request uses the web_client here and not the socket one
if req.payload["event"]["type"] == "message" \
and req.payload["event"].get("subtype") is None:
client.web_client.reactions_add(
name="eyes",
channel=req.payload["event"]["channel"],
timestamp=req.payload["event"]["ts"],
)

How do I send two SMS messages in a chain to the same receiver with twilio?

I am working on a project that returns SMS messages to a user who has just sent a SMS message to the server.
The process is:
The user sends a SMS message to the server.
The server will send two SMS messages back to this user. Note that these are two separate short messages and will be sent pretty much at the same time.
I've got the sending part working, but just for sending one SMS message, not two. When I add more code to send another message only the second message part works, which means only the second message has been sent out, the first message has been ignored.
The code looks pretty much like:
else
sms = SMS.create(:body => params['Body'], :from => params['From'], :to => params['To'], :created_at => Time.now)
#return a random saved sms
return_secret = SMS.first(:offset => rand(SMS.count))
twiml = Twilio::TwiML::Response.new do |r|
r.Sms return_secret.body
#send another message to remind user for rating
ask_rating = remind_rating
if ask_rating
twiml = Twilio::TwiML::Response.new do |r|
r.Sms ask_rating
end
twiml.text
end
Does anyone know how to send two messages in Twilio?
You've got some variable shadowing going on with twiml. As you wrote it, the second message's code is inside of the first message's block. Yet, you refer to a variable with the same name as one outside of the block. I would try flattening your code so you aren't nesting like that.
I think the issue here is you're instantiating a second TwiML::Response object when you already have one, so you can just references the previous one which you assigned to r in the first block. You also called it r in the second block so you just remove the block that encloses it:
sms = SMS.create(:body => params['Body'], :from => params['From'], :to => params['To'], :created_at => Time.now)
#return a random saved sms
return_secret = SMS.first(:offset => rand(SMS.count))
twiml = Twilio::TwiML::Response.new do |r|
r.Sms return_secret.body
#send another message to remind user for rating
ask_rating = remind_rating
if ask_rating
r.Sms ask_rating
end
end
Also the blocks weren't balanced in the initial code snippet so I stripped out the else to make it syntactically accurate.
Thank you all, really appreciate your replies.
After consulting with twilio team, they gave me an example like this:
require 'rubygems'
require 'twilio-ruby'
require 'sinatra'
get '/sms-quickstart' do
twiml = Twilio::TwiML::Response.new do |r|
r.Message "Hey Monkey. Thanks for the message!"
r.Message "this is the 2nd message"
end
twiml.text
end
I just deleted
if ask_rating
twiml = Twilio::TwiML::Response.new do |r|
everything works...

Retrieving CallSid for incoming call

When my ruby script makes outgoing calls through Twilio, it's a piece of cake for me to find, output, and reuse the Call Sid for later as such :
#client = Twilio::REST:Client.new account_sid, auth_token
call = #client.account.calls.create({ :from=>'INC', :to=>'OUT', :url=>'URL', :method=>'GET'})
puts call.sid
This works fine for outgoing calls that I make myself.
The issue is when I try to get the call SID for incoming calls.
get '/greeting' do
Twilio::TwiML::Response.new do |r|
r.Say 'Hello. Welcome.'
r.Gather :numDigits => '1', :action => '/greeting/handle-gather', :method => 'get' do |g|
g.Say 'For X, press 1. For Y, press 2. For Z, press 3.'
end
end.text
puts Twilio::TwiML::Request.CallSid
CallSid = incoming_Cid
end
The incoming_Cid is then stored in a MYSQL database for later. I'm not sure if Twilio::TwiML::Request.CallSid is the correct way to get the request parameters that Twilio passes to my application.
How would I properly retrieve the CallSid for incoming calls?
Nevermind, the issue was been solved by simply using Ruby's params instead of the Twilio HTTP Request object:
puts params['CallSid']

sinatra, ruby and twilio [facilitating a CALLBACK mechanism]

I would like to do the following:
Call my twilio number from my cell phone
My twilio number identifies the incoming number then immediately hangs up
My twilio number calls back the identified number (my cell phone number)
When I pick up, twilio asks me to enter the number I wish to call
Twilio gathers the input of the number I want to call and connects me.
So I can make cheap international calls (or roaming calls) from my cell phone.
So far, taken from the twilio website api docs, I have:
require 'rubygems'
require 'sinatra'
require 'twilio-ruby'
get '/' do
account_sid = 'xxxxxxx'
auth_token = 'zzzzzzz'
to = params['From']
#to = '+447928344246'
#to = '441903773807'
from = '442033222327'
Twilio::TwiML::Response.new do |r|
r.Hangup
end.text
# set up a client to talk to the Twilio REST API
#client = Twilio::REST::Client.new account_sid, auth_token
#call = #client.account.calls.create(
:from => from, # From your Twilio number
:to => to, # To any number
:timeout => "20",
# Fetch instructions from this URL when the call connects
:url => 'https://dl.dropboxusercontent.com/u/85088004/twilio/twilio.xml'
)
end
post '/makecall' do
warn params.inspect
account_sid = ' ACaf2b951ae6f7424da036ea9dcd5b0d91'
auth_token = 'my token'
#client = Twilio::REST::Client.new account_sid, auth_token
call = #client.account.calls.create(:url => "https://dl.dropboxusercontent.com/u/85088004/twilio/callback.xml",
:to => params[:Digits],
:from => "+442033222327")
puts call.to
end
The twilio.xml, in the '/' section url file is:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather action="/makecall" method="POST">
<Say timeout="10">Enter the number you wish to call</Say>
</Gather>
</Response>
I get "Sorry an application error has occurred." Then it just hangs up.
warn params.inspect
does not produce anything when I inspect the heroku logs. So I think (one of) the problem(s) is that the params of the number I am dialling is not passed.
Is there any other problem with logic or scripting that seems obvious?
Does the problem lie with the url in the '/makecall' snippet? It si:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
</Hangup>
</Response>
Many, many thanks!
SOLVED!! Thank you for help from the T evangelist. Here is the solution:
require 'rubygems'
require 'sinatra'
require 'twilio-ruby'
account_sid = 'my sid'
auth_token = 'my token'
get '/' do
from = 'my T number'
to = params[:From]
Twilio::TwiML::Response.new do |r|
r.Hangup
end.text
sleep 10
# set up a client to talk to the Twilio REST API
#client = Twilio::REST::Client.new account_sid, auth_token
#call = #client.account.calls.create(
:from => from, # From your Twilio number
:to => to, # To any number
# Fetch instructions from this URL when the call connects
:url => 'https://dl.dropboxusercontent.com/u/85088004/twilio/twilio.xml'
)
end
# the xml file. It is VERY IMPORTANT that you have the absolute url in the action=""
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather timeout="20" action="http://dry-journey-9071.herokuapp.com/makecall" method="GET">
<Say voice="alice">Enter the destination number, please.</Say>
</Gather>
<Say voice="alice">Input not received. Thank you</Say>
</Response>
#Back to the app:
get '/makecall' do
number = params[:Digits]
Twilio::TwiML::Response.new do |r|
r.Dial number ### Connect the caller to Koko, or your cell
r.Say 'The call failed or the remote party hung up. Goodbye.'
end.text
end
Yay!
Twilio Developer Evangelist here.
When you detect that it is your own number, you want to return some TwiML (XML) to Twilio, this should suffice: <Response> <Hangup/> </Response>
You would then need to make a REST API call to Twilio to make a new outbound call to yourself:
#client.account.calls.create(to: my_number, from: "+sometiwilionumber", url: "http://example.com/make-other-call-twiml")
Then use the URL of some TwiML to <Gather> the number you want to dial, and simply <Dial> to that number...
The thing you want to avoid is having Twilio call you back before the first call ends. As you will need to make the API call first, we need to use threading to get around it. I'm not bad with Ruby/Sinatra, but I'm no expert with threading here, but this should work:
twilio_call_thread = Thread.new{
sleep 3 #3 Seconds should be plenty, but you may want to experiment.
#client.account.calls.create(to: mynumber, from: some_twilio_number, url: "http://example.com/gather-and-dial")
}
#Then return the TwiML to hangup...
"<Response><Hangup/></Response>"
You call your number, it creates a thread, then goes to sleep. It responds with a <Hangup> to disconnect the call. A few seconds later, the thread wakes up and you'll get the return call. You will need some TwiML on that call to do a <Gather> to get the phone number to dial, and then <Dial> to make the actual call.
I wasn't sure about the threading, so before checking on that, I had two other ideas you could use:
Use SMS. Send you Twilio number the other number you want to dial, and just have Twilio make the call directly between your number, and the other number.
Secondly, just use a URL, presuming you have data on your phone you can just open a URL which does the same without the initial call or SMS.
Oh - and a third option, if you don't want to muck about with threads, or that's not working for you: set the Status Callback URL on your Twilio number (click 'Optional Voice Settings'). This is fired after the call completes, and from there you can make the new call to yourself.
Hope you get it sorted, it's going to be awesome.

OAuth and HTTParty

Is it possible to use OAuth with HTTParty? I'm trying to do this API call, but, contradictory to the documentation, it needs authentication.
Before you say "Use a Twitter-specific Gem", hear me out--I've tried. I've tried twitter, grackle, and countless others, but none support this specific API call. So, I've turned to HTTParty.
So, how could I use OAuth with HTTParty?
I've been using the vanilla OAuth gem to implement a few simple Twitter API calls. I didn't need a heavyweight gem to do everything, and I was already using OAuth, so a 'roll-your-own' approach seemed reasonable. I know that I haven't mentioned HTTParty, so please don't ding me for that. This may be useful to others for the essence of easy Twitter OAuth if you're already using the OAuth gem.
In case it is helpful, here is the pertinent code (sorry about mixing some constants and other variables / methods at the start - it was the easiest and most accurate way to extract this from my real code):
#Set up the constants, etc required for Twitter OAuth
OAUTH_SITE = "https://api.twitter.com"
TOKEN_REQUEST_METHOD = :post
AUTHORIZATION_SCHEME = :header
def app_request_token_path
"/oauth/request_token"
end
def app_authorize_path
"/oauth/authorize"
end
def app_access_token_path
"/oauth/access_token"
end
def consumer_key
"your twitter API key"
end
def consumer_secret
"your twitter API secret"
end
# Define the OAuth consumer
def consumer meth=:post
#consumer ||= OAuth::Consumer.new(consumer_key,consumer_secret, {
:site => "#{OAUTH_SITE}",
:request_token_path=>app_request_token_path,
:authorize_path=>app_authorize_path,
:access_token_path=>app_access_token_path,
:http_method=>:post,
:scheme=> :header,
:body_hash => ''
})
end
# Essential parts of a generic OAuth request method
def make_request url, method=:get, headers={}, content=''
if method==:get
res = #access_token.get(url, headers)
elsif method==:post
res = #access_token.post(url, content, headers)
end
if res.code.to_s=='200'
jres = ActiveSupport::JSON.decode(res.body)
if jres.nil?
#last_status_text = #prev_error = "Unexpected error making an OAuth API call - response body is #{res.body}"
end
return jres
else
#last_status_text = #prev_error = res if res.code.to_s!='200'
return nil
end
end
# Demonstrate the daily trends API call
# Note the use of memcache to ensure we don't break the rate-limiter
def daily_trends
url = "http://api.twitter.com/1/trends/daily.json"
#last_status_code = -1
#last_status_success = false
res = Rails.cache.fetch(url, :expires_in=> 5.minutes) do
res = make_request(url, :get)
unless res
#last_status_code = #prev_error.code.to_i
end
res
end
if res
#last_status_code = 200
#last_status_success = true
#last_status_text = ""
end
return res
end
I hope this, largely in context of broader use of the OAuth gem, might be useful to others.
I don't think that HTTParty supports OAuth (though I am no expert on HTTParty, it's way too high-level and slow for my taste).
I would just call the Twitter request directly using OAuth gem. Twitter API documentation even has an example of usage: https://dev.twitter.com/docs/auth/oauth/single-user-with-examples#ruby
I used a mix of the OAuth2 gem to get the authentication token and HTTParty to make the query
client = OAuth2::Client.new(apiKey, apiSecret,
:site => "https://SiteForAuthentication.com")
oauthResponse = client.password.get_token(username, password)
token = oauthResponse.token
queryAnswer = HTTParty.get('https://api.website.com/query/location',
:query => {"token" => token})
Not perfect by a long way but it seems to have done the trick so far

Resources