Skip to content

Commit

Permalink
creating GeoIP lookup serve for Heroku
Browse files Browse the repository at this point in the history
  • Loading branch information
JackDanger committed Nov 28, 2010
0 parents commit 354a212
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gems
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
sinatra
geoip
30 changes: 30 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# GeoIP Server

This simple Rack server is useful as a self-hosted service for making lookups to the GeoIP database from MaxMind.com


## Instant installation and deploy

* Clone this: `git clone git://github.com/JackDanger/geoip_server.git`
* Download the free GeoIP data files: `rake geoip:update_city_lite`
* Signup for an account at Heroku ([better details here](http://github.com/sinatra/heroku-sinatra-app))
* Create and name a new app where you want to host this
* push it to Heroku.com: `git push heroku master`


## HowTo

Once the server is running you can make a GET request to the server and receive lookup results in JSON format.

ip = request.remote_ip
require 'open-uri'
data = JSON.decode(open("http://my-geoip-service-app.heroku.com/#{ip}").read)
render :text => "You're in: #{data[:city]}"

Or, straight from a terminal:

curl -X POST http://my-geoip-service-app.heroku.com/207.97.227.239

Patches welcome, forks celebrated.

Copyright (c) 2010 [Jack Danger Canty](http://jåck.com). Released under the MIT License.
46 changes: 46 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
begin
require 'jeweler'
Jeweler::Tasks.new do |gem|
gem.name = "geoip_server"
gem.summary = %Q{Query the MaxMind GeoIP data records via a web service}
gem.description = %Q{Query the MaxMind GeoIP data records via a web service}
gem.email = "gitcommit@6brand.com"
gem.homepage = "http://github.com/JackDanger/geoip_server"
gem.authors = ["Jack Danger Canty"]
gem.add_development_dependency "shoulda", ">= 0"
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
end
Jeweler::GemcutterTasks.new
rescue LoadError
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
end



task :default => :test

require 'rake/testtask'
Rake::TestTask.new(:test) do |test|
test.libs << '.'
test.pattern = 'test.rb'
test.verbose = true
end




namespace :geoip do
desc "Update GeoIP City data file"
task :update_city_lite => :vendor do
%x{wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz && gzip -d GeoLiteCity.dat.gz && mv GeoLiteCity.dat ./vendor}
end

desc "Update GeoIP Country data file"
task :update_country_lite => :vendor do
%x{wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz && gzip -d GeoIP.dat.gz && mv GeoIP.dat ./vendor}
end

task :vendor do
%x{mkdir -p vendor}
end
end
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.9.0
6 changes: 6 additions & 0 deletions config.ru
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require 'lib/geoip_server'

## There is no need to set directories here anymore;
## Just run the application

run Sinatra::Application
69 changes: 69 additions & 0 deletions lib/geoip_server.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
## Resources
gem 'sinatra', :version => '1.0'
require 'sinatra'
require 'geoip'
require 'json'



## Application

get '/' do
%Q{
<body style='line-height: 1.8em; font-family: Archer, Museo, Helvetica, Georgia; font-size 25px; text-align: center; padding-top: 20%;'>
Get to '/' with an ip address to lookup the server location in JSON. Example:
<pre style='font-family: Iconsolata, monospace;background-color:#EEE'>curl http://#{request.host}/207.97.227.239</pre>
<br />
<form action=/ method=GET onsubmit='if(\"\"==this.url.value)return false;else{this.action=\"/\"+this.ip.value}'>
<label for='ip'>IP address: </label>
<input type=text name='ip'/>
<input type=submit value='Lookup!' />
</form>
</body
}
end

get '/:ip' do
pass unless params[:ip] =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/

data = GeoIP.new('vendor/GeoLiteCity.dat').city(params[:ip])

content_type 'application/json'

encode(data).to_json

end

def encode data
{
# * The host or IP address string as requested
:ip => data.shift,
# * The IP address string after looking up the host
:ip_lookup => data.shift,
# * The GeoIP country-ID as an integer
# :country_id => data.shift,
# * The ISO3166-1 two-character country code
:country_code => data.shift,
# * The ISO3166-2 three-character country code
:country_code_long => data.shift,
# * The ISO3166 English-language name of the country
:country => data.shift,
# * The two-character continent code
:continent => data.shift,
# * The region name
:region => data.shift,
# * The city name
:city => data.shift,
# * The postal code
:postal_code => data.shift,
# * The latitude
:lat => data.shift,
# * The longitude
:lng => data.shift,
# * The USA dma_code and area_code, if available (REV1 City database)
:dma_code => data.shift,
:area_code => data.shift,
# Timezone, if available
:timezone => data.shift
}
end
73 changes: 73 additions & 0 deletions test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
ENV['RACK_ENV'] = 'test'

require 'rubygems'
require 'test/unit'
require 'shoulda'
require 'rack/test'
require 'geoip_server'

class GeoipServerTest < Test::Unit::TestCase
include Rack::Test::Methods

def app
Sinatra::Application
end

context "on GET to /" do
setup {
get '/'
}
should "return ok" do
assert last_response.ok?
end
should "have some kind of welcome" do
assert last_response.body =~ /curl/
end
end

context "on GET to /:ip" do
setup {
get '/67.161.92.71'
}
should "return ok" do
assert last_response.ok?
end
should "return json content-type" do
assert_equal 'application/json', last_response.headers['Content-Type']
end
end

context "converting array" do
setup {
array = [
"67.161.92.71",
"67.161.92.71",
"US",
"USA",
"United States",
"NA",
"WA",
"Seattle",
"98117",
47.6847,
-122.3848,
819,
206,
"America/Los_Angeles"
]
@hash = encode(array)
}
should "find city" do
assert_equal 'Seattle', @hash[:city]
end
should "find country" do
assert_equal 'United States', @hash[:country]
end
should "find lat" do
assert_equal 47.6847, @hash[:lat]
end
should "find lng" do
assert_equal -122.3848, @hash[:lng]
end
end
end
1 change: 1 addition & 0 deletions vendor/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.dat

0 comments on commit 354a212

Please sign in to comment.