rack-rekon 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.2@rack-rekon --create
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rack-rekon.gemspec
4
+ gemspec
5
+
6
+ gem 'ruby-debug19', :platform => :mri_19
7
+ gem 'ruby-debug', :platform => :mri_18
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 SEOmoz
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # Rack::Rekon
2
+
3
+ [Riak](http://wiki.basho.com/) is awesome.
4
+ [Rekon](https://github.com/adamhunter/rekon/) is an awesome to browse
5
+ your riak data.
6
+
7
+ Rack::Rekon provides a simple way to serve rekon from your
8
+ rack/sinatra/rails app.
9
+
10
+ ## Usage
11
+
12
+ Example `config.ru`:
13
+
14
+ require 'rack-rekon'
15
+
16
+ require 'rack/rekon'
17
+ use Rack::Lint
18
+ map '/rekon' do
19
+ run Rack::Rekon::App.new
20
+ end
21
+
22
+ ## Copyright
23
+
24
+ Copyright 2011 SEOmoz. See LICENSE for details.
25
+
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ desc "Start rack-rekon on port 3200"
5
+ task :start do
6
+ sh "bundle exec shotgun config.ru -p 3200"
7
+ end
data/config.ru ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ require 'bundler'
3
+ Bundler.setup
4
+
5
+ require 'rack/rekon'
6
+ use Rack::Lint
7
+ map '/rekon' do
8
+ run Rack::Rekon::App.new
9
+ end
data/lib/rack-rekon.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rack/rekon'
data/lib/rack/rekon.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rack/rekon/app'
@@ -0,0 +1,82 @@
1
+ require 'rack/rekon/proxy'
2
+ require 'rack/rekon/response_rewriters/html'
3
+ require 'rack/rekon/response_rewriters/rekon_js'
4
+ require 'rack/rekon/response_rewriters/sammy_template'
5
+ require 'zlib'
6
+
7
+ module Rack
8
+ module Rekon
9
+ class App < Proxy
10
+ attr_accessor :riak_host
11
+ attr_accessor :riak_port
12
+ attr_accessor :riak_protocol
13
+
14
+ RIAK_BUCKET = 'riak'
15
+
16
+ def initialize
17
+ yield self if block_given?
18
+
19
+ # set defaults
20
+ self.riak_host ||= 'localhost'
21
+ self.riak_port ||= 8098
22
+ self.riak_protocol ||= 'http'
23
+ end
24
+
25
+ def call(env)
26
+ request = Rack::Request.new(env)
27
+
28
+ # redirect to the rekon app root
29
+ if path_and_query_for(request) == ''
30
+ uri = URI(request.url)
31
+ uri.path = request.script_name + '/riak/rekon/go'
32
+ [301, { 'Location' => uri.to_s, 'Content-Type' => 'text/html' }, []]
33
+ else
34
+ super
35
+ end
36
+ end
37
+
38
+ def riak_root
39
+ @riak_root ||= "#{riak_protocol}://#{riak_host}:#{riak_port}"
40
+ end
41
+
42
+ def rekon_root
43
+ @rekon_root ||= riak_root + "/#{RIAK_BUCKET}/rekon"
44
+ end
45
+
46
+ def path_and_query_for(request)
47
+ start_index = request.url.index(request.script_name) + request.script_name.size
48
+ request.url[start_index..-1]
49
+ end
50
+
51
+ def uri_for(request)
52
+ riak_root + path_and_query_for(request)
53
+ end
54
+
55
+ def rewrite_response(request, status, headers, body)
56
+ rewriter = case headers['content-type']
57
+ when 'text/html'; ResponseRewriters::HTML
58
+ when 'application/x-sammy-template'; ResponseRewriters::SammyTemplate
59
+ when 'application/javascript'
60
+ case request.path.split('/').last
61
+ when 'rekon.js'; ResponseRewriters::RekonJS
62
+ end
63
+ end
64
+
65
+ if rewriter
66
+ rewriter = rewriter.new(request.env['SCRIPT_NAME'], plain_text_body(headers, body))
67
+ body = [rewriter.rewritten_body]
68
+ end
69
+
70
+ [status, headers, body]
71
+ end
72
+
73
+ def plain_text_body(headers, body)
74
+ body = body.first if body.is_a?(Array) && body.size == 1
75
+ return body unless headers['content-encoding'] == 'gzip'
76
+ headers.delete('content-encoding')
77
+ io = StringIO.new(body)
78
+ Zlib::GzipReader.new(io).read
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,48 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+
4
+ module Rack
5
+ module Rekon
6
+ class Proxy
7
+ def call(env)
8
+ req = Rack::Request.new(env)
9
+ method = req.request_method.downcase
10
+ method[0..0] = method[0..0].upcase
11
+
12
+ uri = URI(uri_for(req))
13
+
14
+ sub_request = Net::HTTP.const_get(method).new("#{uri.path}#{"?" if uri.query}#{uri.query}")
15
+
16
+ if sub_request.request_body_permitted? and req.body
17
+ sub_request.body_stream = req.body
18
+ sub_request.content_length = req.content_length
19
+ sub_request.content_type = req.content_type
20
+ end
21
+
22
+ sub_request["X-Forwarded-For"] = (req.env["X-Forwarded-For"].to_s.split(/, +/) + [req.env['REMOTE_ADDR']]).join(", ")
23
+ sub_request["X-Requested-With"] = req.env['HTTP_X_REQUESTED_WITH'] if req.env['HTTP_X_REQUESTED_WITH']
24
+ sub_request["Accept-Encoding"] = req.accept_encoding
25
+ sub_request["Referer"] = req.referer
26
+ sub_request.basic_auth *uri.userinfo.split(':') if (uri.userinfo && uri.userinfo.index(':'))
27
+
28
+ sub_response = Net::HTTP.start(uri.host, uri.port) do |http|
29
+ http.request(sub_request)
30
+ end
31
+
32
+ headers = {}
33
+ sub_response.each_header do |k,v|
34
+ headers[k] = v unless k.to_s =~ /cookie|content-length|transfer-encoding/i
35
+ end
36
+
37
+ response_triplet = [sub_response.code.to_i, headers, [sub_response.read_body]]
38
+
39
+ if respond_to?(:rewrite_response)
40
+ rewrite_response(req, *response_triplet)
41
+ else
42
+ response_triplet
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
@@ -0,0 +1,42 @@
1
+ require 'nokogiri'
2
+
3
+ module Rack
4
+ module Rekon
5
+ module ResponseRewriters
6
+ class HTML
7
+ attr_reader :doc, :app_root
8
+ def initialize(app_root, body)
9
+ @app_root, @doc = app_root, Nokogiri::HTML(body)
10
+ end
11
+
12
+ def rewritten_body
13
+ ensure_rewritten!
14
+ doc.to_html
15
+ end
16
+
17
+ private
18
+
19
+ def ensure_rewritten!
20
+ return if @rewritten
21
+ rewrite_javascripts!
22
+ rewrite_link_tags!
23
+ @rewritten = true
24
+ end
25
+
26
+ def rewrite_javascripts!
27
+ doc.css('script').each do |script|
28
+ src = script['src']
29
+ script['src'] = [app_root, 'riak', 'rekon', src].join('/')
30
+ end
31
+ end
32
+
33
+ def rewrite_link_tags!
34
+ doc.css('link').each do |link_tag|
35
+ href = link_tag['href']
36
+ link_tag['href'] = [app_root, 'riak', 'rekon', href].join('/')
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,41 @@
1
+ module Rack
2
+ module Rekon
3
+ module ResponseRewriters
4
+ class RekonJS
5
+ attr_reader :js, :app_root
6
+ def initialize(app_root, js)
7
+ @app_root, @js = app_root, js
8
+ end
9
+
10
+ def rewritten_body
11
+ ensure_rewritten!
12
+ js
13
+ end
14
+
15
+ private
16
+
17
+ def ensure_rewritten!
18
+ return if @rewritten
19
+ rewrite_templates_paths!
20
+ rewrite_base_urls!
21
+ @rewritten = true
22
+ end
23
+
24
+ def rewrite_templates_paths!
25
+ js.gsub!(/([^\.\(\)\']+)\.html\.template/, [app_root, 'riak', 'rekon'].join("/") + '/\1.html.template')
26
+ end
27
+
28
+ def rewrite_base_urls!
29
+ js << <<-EOJS
30
+ Rekon.client = new RiakClient(
31
+ '#{app_root}/#{Rack::Rekon::App::RIAK_BUCKET}',
32
+ '#{app_root}/mapred'
33
+ );
34
+ EOJS
35
+
36
+ js.gsub!("'/stats'", "'#{app_root}/stats'")
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,44 @@
1
+ require 'nokogiri'
2
+
3
+ module Rack
4
+ module Rekon
5
+ module ResponseRewriters
6
+ class SammyTemplate
7
+ attr_reader :body, :app_root
8
+ def initialize(app_root, body)
9
+ @app_root, @body = app_root, body
10
+ end
11
+
12
+ def doc
13
+ @doc ||= Nokogiri::HTML::DocumentFragment.parse(body)
14
+ end
15
+
16
+ def rewritten_body
17
+ return body if ejs?
18
+
19
+ ensure_rewritten!
20
+ doc.to_html
21
+ end
22
+
23
+ private
24
+
25
+ def ejs?
26
+ body.include?('<%=')
27
+ end
28
+
29
+ def ensure_rewritten!
30
+ return if @rewritten
31
+ rewrite_images!
32
+ @rewritten = true
33
+ end
34
+
35
+ def rewrite_images!
36
+ doc.css('img').each do |img|
37
+ src = img['src']
38
+ img['src'] = [app_root, 'riak', 'recon', src].join('/')
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ module Rekon
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rack/rekon/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rack-rekon"
7
+ s.version = Rack::Rekon::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Myron Marston"]
10
+ s.email = ["myron@seomoz.org"]
11
+ s.homepage = ""
12
+ s.summary = %q{Mount rekon as a rack app.}
13
+ s.description = %q{Proxies rekon as a rack app so you can include it in your rack-based riak application.}
14
+
15
+ s.rubyforge_project = "rack-rekon"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_runtime_dependency 'nokogiri', '~> 1.4'
23
+ s.add_development_dependency 'shotgun', '0.9'
24
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-rekon
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Myron Marston
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-04-19 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: nokogiri
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 1
32
+ - 4
33
+ version: "1.4"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: shotgun
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - "="
43
+ - !ruby/object:Gem::Version
44
+ hash: 25
45
+ segments:
46
+ - 0
47
+ - 9
48
+ version: "0.9"
49
+ type: :development
50
+ version_requirements: *id002
51
+ description: Proxies rekon as a rack app so you can include it in your rack-based riak application.
52
+ email:
53
+ - myron@seomoz.org
54
+ executables: []
55
+
56
+ extensions: []
57
+
58
+ extra_rdoc_files: []
59
+
60
+ files:
61
+ - .gitignore
62
+ - .rvmrc
63
+ - Gemfile
64
+ - LICENSE
65
+ - README.md
66
+ - Rakefile
67
+ - config.ru
68
+ - lib/rack-rekon.rb
69
+ - lib/rack/rekon.rb
70
+ - lib/rack/rekon/app.rb
71
+ - lib/rack/rekon/proxy.rb
72
+ - lib/rack/rekon/response_rewriters/html.rb
73
+ - lib/rack/rekon/response_rewriters/rekon_js.rb
74
+ - lib/rack/rekon/response_rewriters/sammy_template.rb
75
+ - lib/rack/rekon/version.rb
76
+ - rack-rekon.gemspec
77
+ has_rdoc: true
78
+ homepage: ""
79
+ licenses: []
80
+
81
+ post_install_message:
82
+ rdoc_options: []
83
+
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 3
92
+ segments:
93
+ - 0
94
+ version: "0"
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ hash: 3
101
+ segments:
102
+ - 0
103
+ version: "0"
104
+ requirements: []
105
+
106
+ rubyforge_project: rack-rekon
107
+ rubygems_version: 1.5.2
108
+ signing_key:
109
+ specification_version: 3
110
+ summary: Mount rekon as a rack app.
111
+ test_files: []
112
+