Fire Eagle (not fireeagle) is a new location platform from some of my colleagues here at Yahoo! Brickhouse. I’ve put together a simple sample app called whereis which shows off the power of the platform.
What is whereis?
Each instance of whereis lets you share location within a trusted group of people. Whereis does not update location in Fire Eagle, you should do this using other apps (eg. Fire Eagle automatic device updaters, or other sites). This screenshot basically sums it up -

What can I use it for?
- Run it on your intranet to easily share location between your co-workers
- Run it on the internet so friends and family can share location
Who is whereis intended for?
Whereis is intended for developers who have familiarity with Ruby and access to a server.
Why are you releasing it?
It is a simple app (~200 lines of code) built on top of the camping framework. If you understand Ruby and the MVC pattern, it will give you a good idea of how FE works and can be used. I think the code is pretty self explanatory, drop me a line if you have any suggestions.
What else should I do with it?
- run an instance for your group
- use it to experiment with fireeagle
- skin it with CSS to make it look good
- build a service around it
- add a subscriptions table with acls to have a twitter like mode
- anything else
How do I use it?
- download the files
- make sure you and everyone you want to use whereis have fireeagle accounts
- install camping (via gem)
- install dependencies
- get a fireeagle consumer token and secret from the FE website and set up the correct callback URL
- insert the token and secret in getFEClient - whereis.rb
- change the login password in createTheBasics - whereis.rb
- “camping whereis.rb” on the command line
Caveats
- Whereis uses sqlite as it’s database so it’s probably not suitable for large scale deployments.
- I’m using a very early version of the fireeagle gem, before you write anything make sure to look at the newest version.
- This code might be a bit slow in production if the fireeagle servers are heavily loaded. If you want to take initiative and fix the problem this is how you would do it (via Seth Fitzsimmons) - instead of updating the locations on query, update them periodically using a cron job or some other method.
#!ruby
#whereis - a simple fireeagle demo
#IMPORTANT: make sure to use the version of fireeagle.rb included in the tarball
#Nikhil Bobb (nikhilb at yahoo-inc.com)
#26th Feb 08
require 'camping/session'
require 'FireEagle'
require 'JSON'
Camping.goes :Whereis
module Whereis
include Camping::Session
table_style = "border-width:1px; border-style:outset"
def getFEClient(access_token = "", access_token_secret = "")
client = FireEagle::Client.new \
:consumer_key => "",
:consumer_secret => "",
:access_token => access_token,
:access_token_secret => access_token_secret
end
#gets a user's location from fireEagle and returns a nice
#string
def getFELocation(access_token, access_token_secret)
client = getFEClient(access_token, access_token_secret)
location_obj = client.user
#query the JSON object to get the location
#where best guess = true
hierarchy = location_obj["user"]["location_hierarchy"]
current_loc = hierarchy.select {|l| l["best_guess"]}.first
[current_loc["name"], current_loc["located_at"]]
end
end
module Whereis::Models
class User < Base;
has_one :request_token
serialize :access_token
end
class RequestToken < Base;
belongs_to :user
serialize :bin
end
class Login < Base; end
class CreateTheBasics < V 1.0
def self.up
create_table :whereis_logins do |t|
t.column :username, :string
t.column :password, :string
end
create_table :whereis_users do |t|
t.column :name, :string
t.column :access_token, :text
end
create_table :whereis_request_tokens do |t|
t.column :str, :string
t.column :bin, :text
t.column :user_id, :integer
end
Login.create :username => 'admin', :password => "eagle123"
end
def self.down
drop_table :whereis_users
drop_table :whereis_request_tokens
drop_table :whereis_logins
end
end
end
module Whereis::Controllers
class Style < R '/styles.css'
def get
@headers["Content-Type"] = "text/css; charset=utf-8"
@body = %{
table {
border-width:1px;
border-style: dotted;
}
td {
border-width: 1px 1px 1px 1px;
border-style: solid;
}
}
end
end
class Auth < R '/auth'
def post
@logged_in_user = Login.find :first, :conditions => ['username = ? AND password = ?', input.username, input.password]
if @logged_in_user
@login = 'login success !'
@state.user_id = @logged_in_user.id
redirect R(Index)
else
@login = 'wrong user name or password'
render :id
end
end
def get
render :id
end
end
class Index < R '/'
def get
if @state.user_id.blank?
redirect R(Auth)
return
end
@users = []
User.find(:all).each do |u|
t = u.access_token
if t
location = getFELocation(t.token, t.secret)
@users << [u.name, location[0], location[1]]
end
end
render :whereis
end
def post
if @state.user_id.blank?
redirect R(Auth)
return
end
client = getFEClient
request_token = client.get_access_token_part1
rt = RequestToken.create :bin => request_token, :str => request_token.token
u = User.create :name => input.user, :request_token => rt
redirect "#{FireEagle::AUTHORIZATION_URL}?oauth_token=#{request_token.token}"
end
end
class Callback < R '/callback'
def get
if @state.user_id.blank?
redirect R(Auth)
return
end
client = getFEClient
rt = RequestToken.find_by_str(input.oauth_token)
at = client.get_access_token_part2(rt.bin)
user = rt.user
user.access_token = at
user.save
rt.destroy
redirect "/"
end
end
end
module Whereis::Views
def layout
html do
head do
title { "Where is everyone?" }
link :rel => 'stylesheet', :type => 'text/css',
:href => '/styles.css', :media => 'screen'
end
end
body { self << yield }
end
def id
p @login
form :action => R(Auth), :method => 'post' do
label 'Username', :for => 'username'; br
input :name => 'username', :type => 'text'; br
label 'Password', :for => 'password'; br
input :name => 'password', :type => 'text'; br
input :type => 'submit', :name => 'login', :value => 'Login'
end
end
def whereis
form :method => "post" do
input :type => "text", :name => "user"
input :type => "submit", :value => "add me"
end
table do
tr do
td "name"
td "location"
td "time"
end
tr do
@users.each do |u|
u.each{|c| td c}
end
end
end
end
end
def Whereis.create
Camping::Models::Session.create_schema
Whereis::Models.create_schema :assume => (Whereis::Models::User.table_exists? ? 1.0 : 0.0)
end
James | 07-Mar-08 at 12:21 pm | Permalink
Cool stuff. And nice new style for your blog!
Barce | 26-Mar-08 at 2:15 pm | Permalink
I hope your clean code convinces folks at Yahoo to move away from PHP to Ruby. I didn’t get Fire Eagle until I read this. Thanks!