twilio, sinatra ruby force hangup and then callback - ruby

I want to call my Twilio number which hangs up immediately and then calls me back. This is similar (but not identical) to a previous question of mine.
The problem lies with forcing Twilio to hang up.
The ruby code is:
get '/callback' do
to = params['From']
from = 'my Twilio number'
"<Response><Hangup/></Response>"
sleep 5
# 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
This produces a message: "We are sorry but a system error has occurred". The problem lies with the hangup instruction. I have tried as above and also
<Response><Hangup/></Response> #without enclosing double or single quotes
and
Twilio::TwiML::Response.new do |r|
r.Hangup
end.text
Neither produces the desired result of hangup.
What's wrong?
Many thanks in advance!

Definitely go with #Kevin's advice and get in touch with Twilio support. But one comment I would like to add. At the end of your /callback action, the last value is the #call variable you are assigning when you create a call, Ruby will be trying to return this value as the result of the HTTP request.
Ruby returns the last value evaluated at the end of a method. In this case, that value is what Sinatra responds to the HTTP Get request with by default.
Judging by the literal string you have <Response><Hangup/></Response>, I'm guessing you are not using a view, and expect that to be the result of the get request. You should place that at the very end of your method as below. I've also added a content_type which just sets the response header to say the response is XML.
get '/callback' do
to = params['From']
from = 'my Twilio number'
# 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')
#ruby returns the last value in a method:
content_type 'text/xml'
"<Response><Hangup/></Response>"
end
Make sure that you have your Twilio Voice Callback set to a Get request as well (the default is post).
I've also removed the sleep 5 that you had in there. I can see where you are going with it. Respond with the hangup TwiML, wait a few seconds, then make a new call. Sadly, Sinatra doesn't quite work that way. It will not respond to the HTTP request until the end of the method. So you're just going to have it sit and wait for 5 seconds with no reason.
This does pose a bit of an issue, as you tell Twilio to make an outbound call to the number that you are about to hangup on, so you basically have a race condition. Does the call disconnect first, or does the outbound start ringing to a busy number.
There are a number of ways of doing this, but I'd suggest a thread. It's a little tricky, but this SO answer goes into some detail.

You should check your Twilio Debugger at twilio.com/user/account/debugger. This will give more information about the failure.

Related

How to reference "from" field in TWIML to make a simple call b/w two phones

Trying to follow this tutorial:
https://www.twilio.com/docs/quickstart/ruby/rest/call-request
This code only dials the to number for me:
#call = #client.calls.create(
:from => '+14159341234', # From your Twilio number
:to => '+18004567890', # To any number
# Fetch instructions from this URL when the call connects
:url => 'http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient'
)
For me, this code never dials the from phone. Just the "to:" number gets called, when answered, it plays music. The "from" number doesn't never rings. I'm guessing I have to write TWIML to dial the first number (to), but I don't see any reference to the variable "to" in TWIML, is there a sample twiml that will simply connect two phones?
You're dealing with three numbers in this picture. One is your Twilio number from where the call is made '+14159341234', then, you have the two numbers you'd like to call and connect.
Let's be clear, you won't hear your Twilio number ring, it's at Twilio and it's kind of virtual.
The code you have so far, when you run it, uses your Twilio number :from => '+14159341234' to make a call :to => '+18004567890'.
So, what happens when people at :to => '+18004567890' answer? Twilio's system (the platform) makes a request to :url => 'http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient' from where is served some XML, some TWIML. You can actually see what is served if you go with your browser to http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient
To do what you want to do, to dial another number instead of playing music, you need to change that url to some place from where you serve this kind of TWIML:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Hello. Please wait.</Say>
<Dial>+12223334444</Dial>
</Response>
If you don't have your public server from where you can serve XML, you can use a native TwiML bin, that you create in your Twilio account console here: https://www.twilio.com/console/runtime/twiml-bins .
Once you create your TwiML bin, under properties for the bin, you'll have a URL to put in place of http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient, something like https://handler.twilio.com/twiml/EH7e58b64f8488ff8c022bf83c910fb49b.
P.S. You might want to also google twilio click to call and/or twilio conference as other way to connect two phones.

I don't understand the Twilio URL Parameter on Voice

I understand the purpose of this for more complex functionality, but I'm trying to make a simple app that does nothing more than forwards to a phone number. I don't want to hard code the forward via a Twimlet because I want to build a web app that dynamically allows me to assign the numbers. Can someone tell me what I'd put for URL parameter in this situation?
get '/forward-call' do
#client = Twilio::REST::Client.new
#call = #client.account.calls.create(
{:to => "+15127778888",
:from => "+15122222222",
:url => "What in the foo should I put here?"})
end
Twilio developer evangelist here.
Does your /forward-call endpoint get called when someone makes a call to your Twilio number?
If so, you don't want to be calling the REST API right now, you want to respond to the webhook with some TwiML. In your case, you'd want something like this:
get '/forward-call' do
content_type 'text/xml'
"<Response>
<Dial><Number>#{NUMBER_TO_FORWARD_TO}</Number></Dial>
</Response>"
end
Does that help at all? Let me know if I can help out any more at all.

how can i store/retrieve files in owncloud from a webapp written in opal/ruby?

I have a webapp written mostly in ruby compiled with opal. I now would like to store/retrieve file in my owncloud, maybe using WebDAV. I am looking for an example how to do this using HTTP module.
I tried
HTTP.get("https://owncloud/foo.abc") do |req|
req.username= "user"
...
end.then do |response|
puts response
end
But that does not work. no method then for module HTTP.
So it seem that if I pass a block to HTTP.get it no longer returns a promise.
When I do not pass a block I don' know
how to configure the request.
Best if I could find an full example how to use HTTP from opal.
The small example in opal blog die not hell out.
I think username/password should be passed in the options hash (see the opal-jquery README).
HTTP.get("https://owncloud/foo.abc", username: 'user').then do |response|
puts response
end
A note about the Promise-style:
The block is used as the default form of callback. To switch to promise-style you should not pass any block, instead try assigning the result of HTTP.get to a variable to modify the request options:
req = HTTP.get("https://owncloud/foo.abc")
puts req.inspect # <= do something with the request
req.then do |response|
puts response
end

Grab Facebook signed_request with Sinatra

I'm trying to figure out whether or not a user likes our brand page. Based off of that, we want to show either a like button or some 'thank you' text.
I'm working with a sinatra application hosted on heroku.
I tried the code from this thread: Decoding Facebook's signed request in Ruby/Sinatra
However, it doesn't seem to grab the signed_request and I can't figure out why.
I have the following methods:
get "/tab" do
#encoded_request = params[:signed_request]
#json_request = decode_data(#encoded_request)
#signed_request = Crack::JSON.parse(#json_request)
erb :index
end
# used by Canvas apps - redirect the POST to be a regular GET
post "/tab" do
#encoded_request = params[:signed_request]
#json_request = decode_data(#encoded_request)
#signed_request = Crack::JSON.parse(#json_request)
redirect '/tab'
end
I also have the helper messages from that thread, as they seem to make sense to me:
helpers do
def base64_url_decode(payload)
encoded_str = payload.gsub('-','+').gsub('_','/')
encoded_str += '=' while !(encoded_str.size % 4).zero?
Base64.decode64(encoded_str)
end
def decode_data(signed_request)
payload = signed_request.split('.')
data = base64_url_decode(payload)
end
end
However, when I just do
#encoded_request = params[:signed_request]
and read that out in my view with:
<%= #encoded_request %>
I get nothing at all.
Shouldn't this return at least something? My app seems to be crashing because well, there's nothing to be decoded.
I can't seem to find a lot of information about this around the internet so I'd be glad if someone could help me out.
Are there better ways to know whether or not a user likes our page? Or, is this the way to go and am I just overlooking something obvious?
Thanks!
The hint should be in your app crashing because there's nothing to decode.
I suspect the parameters get lost when redirecting. Think about it at the HTTP level:
The client posts to /tab with the signed_request in the params.
The app parses the signed_request and stores the result in instance variables.
The app redirects to /tab, i.e. sends a response with code 302 (or similar) and a Location header pointing to /tab. This completes the request/response cycle and the instance variables get discarded.
The client makes a new request: a GET to /tab. Because of the way redirects work, this will no longer have the params that were sent with the original POST.
The app tries to parse the signed_request param but crashes because no such param was sent.
The simplest solution would be to just render the template in response to the POST instead of redirecting.
If you really need to redirect, you need to carefully pass along the signed_request as query parameters in the redirect path. At least that's a solution I've used in the past. There may be simpler ways to solve this, or libraries that handle some of this for you.

How do I read only x number of bytes of the body using Net::HTTP?

It seems like the methods of Ruby's Net::HTTP are all or nothing when it comes to reading the body of a web page. How can I read, say, the just the first 100 bytes of the body?
I am trying to read from a content server that returns a short error message in the body of the response if the file requested isn't available. I need to read enough of the body to determine whether the file is there. The files are huge, so I don't want to get the whole body just to check if the file is available.
This is an old thread, but the question of how to read only a portion of a file via HTTP in Ruby is still a mostly unanswered one according to my research. Here's a solution I came up with by monkey-patching Net::HTTP a bit:
require 'net/http'
# provide access to the actual socket
class Net::HTTPResponse
attr_reader :socket
end
uri = URI("http://www.example.com/path/to/file")
begin
Net::HTTP.start(uri.host, uri.port) do |http|
request = Net::HTTP::Get.new(uri.request_uri)
# calling request with a block prevents body from being read
http.request(request) do |response|
# do whatever limited reading you want to do with the socket
x = response.socket.read(100);
# be sure to call finish before exiting the block
http.finish
end
end
rescue IOError
# ignore
end
The rescue catches the IOError that's thrown when you call HTTP.finish prematurely.
FYI, the socket within the HTTPResponse object isn't a true IO object (it's an internal class called BufferedIO), but it's pretty easy to monkey-patch that, too, to mimic the IO methods you need. For example, another library I was using (exifr) needed the readchar method, which was easy to add:
class Net::BufferedIO
def readchar
read(1)[0].ord
end
end
Shouldn't you just use an HTTP HEAD request (Ruby Net::HTTP::Head method) to see if the resource is there, and only proceed if you get a 2xx or 3xx response? This presumes your server is configured to return a 4xx error code if the document is not available. I would argue this was the correct solution.
An alternative is to request the HTTP head and look at the content-length header value in the result: if your server is correctly configured, you should easily be able to tell the difference in length between a short message and a long document. Another alternative: set the content-range header field in the request (which again assumes that the server is behaving correctly WRT the HTTP spec).
I don't think that solving the problem in the client after you've sent the GET request is the way to go: by that time, the network has done the heavy lifting, and you won't really save any wasted resources.
Reference: http header definitions
I wanted to do this once, and the only thing that I could think of is monkey patching the Net::HTTP#read_body and Net::HTTP#read_body_0 methods to accept a length parameter, and then in the former just pass the length parameter to the read_body_0 method, where you can read only as much as length bytes.
To read the body of an HTTP request in chunks, you'll need to use Net::HTTPResponse#read_body like this:
http.request_get('/large_resource') do |response|
response.read_body do |segment|
print segment
end
end
Are you sure the content server only returns a short error page?
Doesn't it also set the HTTPResponse to something appropriate like 404. In which case you can trap the HTTPClientError derived exception (most likely HTTPNotFound) which is raised when accessing Net::HTTP.value().
If you get an error then your file wasn't there if you get 200 the file is starting to download and you can close the connection.
You can't. But why do you need to? Surely if the page just says that the file isn't available then it won't be a huge page (i.e. by definition, the file won't be there)?

Resources