20141208

How to Get a Restaurant Reservation with only 57 lines of Code

The restaurant I wanted takes reservations six weeks in advance, every Monday at 10:30am.  So every Monday I would call a few times, and then give up. I don't have time for this nonsense!

Then I got mad and realized I could use Twilio.  Twilio is a neat system that provides programmatic access to the phone system — making calls, receiving calls, conference calls, recording calls and sending/receiving text messages.

Twilio was fun to learn. Once you get it working, you can make phone calls from the command line! I wrote a little script that would call any number, and if it was busy, hang up and try again right away. Once it gets through, then it adds them to a conference call, which I'm already in.

So this morning, the moment of truth came and we started dialing away.  Six minutes and seventy call attempts later, I was in!

Easy :)


#!/usr/bin/env ruby
# Usage conf.rb <number>
#
# Will call the number, repeatedly if necessary, and join them to a conference call when they join.
require 'rubygems' # not necessary with ruby 1.9 but included for completeness
require 'twilio-ruby'
# put your own credentials here
account_sid = 'foo'
auth_token = 'bar'
# set up a client to talk to the Twilio REST API
@client = Twilio::REST::Client.new account_sid, auth_token
def confcall(num)
@client.account.calls.create({
:to => num,
:from => '+14153673283',
:url => 'http://twimlets.com/echo?Twiml=%3CResponse%3E%0A%3CDial%3E%0A%3CConference%20waitUrl%3D%22http%3A%2F%2Ftwimlets.com%2Fholdmusic%3FBucket%3Dcom.twilio.music.electronica%22%20waitMethod%3D%22GET%22%3Ed41d8cd98f00b204e9800998ecf8427e%3C%2FConference%3E%0A%3C%2FDial%3E%0A%3C%2FResponse%3E&#38;',
:method => 'GET',
:fallback_method => 'GET',
:status_callback_method => 'GET',
:record => 'false'
})
end
# call the given number repeatedly until its not busy (or ringing)
def repeatocall(num)
status = 'busy'
while ['busy', 'ringing'].include?(status)
$stdout.puts("#{Time.now}: Calling #{num}")
call = confcall(num)
$stdout.puts("Call is #{call.uri}")
sleep(1)
# wait until call is no longer ringing
loop do
status = @client.get(call.uri.gsub('.json',''))['status']
$stdout.puts("#{Time.now}: Call is #{status}")
break if status != 'ringing'
end
# if call is busy, hang up
if status == 'busy'
$stdout.puts("#{Time.now}: Hanging up.")
call.cancel
end
end
$stdout.puts "#{Time.now}: OMG something interesting happened. Status is #{status}"
end
call = repeatocall ARGV[0]
view raw conf_call.rb hosted with ❤ by GitHub