path_router 0.0.1

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,6 @@
1
+ /*.gem
2
+ /.bundle
3
+ /Gemfile.lock
4
+ /pkg/*
5
+
6
+ /path_router.rb
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # see path_router.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,22 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ eventmachine (0.12.10)
6
+ proxymachine (1.2.4)
7
+ eventmachine (>= 0.12.10)
8
+ rspec (2.6.0)
9
+ rspec-core (~> 2.6.0)
10
+ rspec-expectations (~> 2.6.0)
11
+ rspec-mocks (~> 2.6.0)
12
+ rspec-core (2.6.4)
13
+ rspec-expectations (2.6.0)
14
+ diff-lcs (~> 1.1.2)
15
+ rspec-mocks (2.6.0)
16
+
17
+ PLATFORMS
18
+ ruby
19
+
20
+ DEPENDENCIES
21
+ proxymachine
22
+ rspec
data/README.md ADDED
@@ -0,0 +1,67 @@
1
+ path_router
2
+ ===========
3
+
4
+ HTTP routing by URL path, built on the excellent [ProxyMachine](https://github.com/mojombo/proxymachine) by the GitHub guys.
5
+
6
+ GitHub uses ProxyMachine to service millions of git connections every day.
7
+
8
+
9
+ Install
10
+ -------
11
+
12
+ ```
13
+ gem install path_router # installs path_router and proxymachine
14
+ path_router init # creates example path_router.rb
15
+ vim path_router.rb # specify your backends and URL patterns
16
+ path_router # fire it up, optionally with -h host and -p port
17
+ ```
18
+
19
+ Routes
20
+ ------
21
+
22
+ See `example_path_router.rb` to get the general idea.
23
+
24
+ ```ruby
25
+ PathRouter::Router.instance.reset.tap do |r|
26
+
27
+ r.backends = {
28
+ rails: "127.0.0.1:3000", # default
29
+ static: "127.0.0.1:8080",
30
+ wordpress: "10.0.0.1:80",
31
+ }
32
+
33
+ r.connect :static,
34
+ %r{^/robots.txt},
35
+ %r{^/(?:images|stylesheets|javascripts)/}
36
+
37
+ r.connect :wordpress,
38
+ %r{^/blog/},
39
+ %r{^/feed}
40
+
41
+ end
42
+ ```
43
+
44
+ The only non-obvious point is that the first backend in the hash is the default catch-all.
45
+ Ruby 1.8 users get random default backend; think of it as an easter egg ;)
46
+
47
+
48
+ Tests
49
+ -----
50
+
51
+ ```
52
+ $ rspec spec/*_spec.rb
53
+
54
+ PathRouter::Router
55
+ routes by specified patterns
56
+ defaults to first backend for unmatched requests
57
+
58
+ Finished in 0.00056 seconds
59
+ 2 examples, 0 failures
60
+ ```
61
+
62
+
63
+ Meh.
64
+ ----
65
+
66
+ (c) 2011 Paul Annesley, MIT licence.
67
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/bin/path_router ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ BASEDIR = File.realpath(File.join(File.dirname(__FILE__), ".."))
6
+
7
+ if ARGV.include? "init"
8
+ require "fileutils"
9
+ dest = "./path_router.rb"
10
+ FileUtils.cp File.join(BASEDIR, "example_path_router.rb"), dest
11
+ puts "Created example #{dest}"
12
+ exit
13
+ end
14
+
15
+ args = [ "--config", File.join(BASEDIR, "proxymachine_config.rb") ]
16
+
17
+ OptionParser.new do |opts|
18
+ opts.banner = <<-EOF
19
+
20
+ path_router init
21
+ Creates example path_router.rb into the current directory.
22
+
23
+ path_router [-h <host>] [-p <port>]
24
+ Start ProxyMachine with path_router config loaded from path_router.rb in
25
+ the current directory.
26
+
27
+ Options:
28
+ EOF
29
+ opts.on("-hHOST", "--host HOST", "Hostname to bind. Default 0.0.0.0") do |host|
30
+ args += [ "--host", host ]
31
+ end
32
+ opts.on("-pPORT", "--port PORT", "Port to listen on. Default 5432") do |port|
33
+ args += [ "--port", port ]
34
+ end
35
+ end.parse!
36
+
37
+ exec "proxymachine", *args
@@ -0,0 +1,17 @@
1
+ PathRouter::Router.instance.reset.tap do |r|
2
+
3
+ r.backends = {
4
+ rails: "127.0.0.1:3000", # default
5
+ static: "127.0.0.1:8080",
6
+ wordpress: "10.0.0.1:80",
7
+ }
8
+
9
+ r.connect :static,
10
+ %r{^/robots.txt},
11
+ %r{^/(?:images|stylesheets|javascripts)/}
12
+
13
+ r.connect :wordpress,
14
+ %r{^/blog/},
15
+ %r{^/feed}
16
+
17
+ end
@@ -0,0 +1,46 @@
1
+ module PathRouter
2
+ class Router
3
+
4
+ def self.instance
5
+ @instance ||= new
6
+ end
7
+
8
+ def initialize
9
+ reset
10
+ end
11
+
12
+ def reset
13
+ @backends = {}
14
+ @routes = {}
15
+ self
16
+ end
17
+
18
+ def load_routes(file = "path_router.rb")
19
+ puts "Loading routes from #{file}"
20
+ load file
21
+ rescue LoadError => e
22
+ puts "Failed to load routes: " << e.message
23
+ end
24
+
25
+ # Hash of backends, { Regexp => "ip:port", ... }
26
+ def backends=(backends)
27
+ backends.default = backends.values.first
28
+ @backends = backends
29
+ end
30
+
31
+ # Connect patterns to the given backend.
32
+ def connect(backend, *patterns)
33
+ patterns.each { |p| @routes[p] = backend }
34
+ end
35
+
36
+ # method e.g. "GET", currently unused
37
+ # path e.g. "/some/path?including=query+string"
38
+ def lookup(method, path)
39
+ _, backend = @routes.detect do |pattern, _|
40
+ path =~ pattern
41
+ end
42
+ @backends[backend]
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,3 @@
1
+ module PathRouter
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,2 @@
1
+ module PathRouter
2
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "path_router/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "path_router"
7
+ s.version = PathRouter::VERSION
8
+ s.authors = ["Paul Annesley"]
9
+ s.email = ["paul@annesley.cc"]
10
+ s.homepage = ""
11
+ s.summary = %q{HTTP routing by URL path, built on ProxyMachine.}
12
+ s.description = %q{Easily route HTTP requests to different backends by pattern matching the URL path.}
13
+
14
+ s.rubyforge_project = "path_router"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency "proxymachine", "~> 1.2.4"
22
+ s.add_development_dependency "rspec"
23
+ end
@@ -0,0 +1,18 @@
1
+ $LOAD_PATH.unshift "./lib"
2
+ require "path_router/router"
3
+
4
+ module PathRouter
5
+
6
+ Signal.trap("USR2") { Router.instance.load_routes }
7
+
8
+ Router.instance.load_routes
9
+
10
+ proxy do |data|
11
+ if data =~ %r{^(\w+) (\S+) HTTP/\d.\d\r\n}
12
+ { remote: Router.instance.lookup($1, $2) }
13
+ else
14
+ { noop: true }
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,36 @@
1
+ require_relative "spec_helper"
2
+
3
+ module PathRouter
4
+ describe Router do
5
+
6
+ let(:router) do
7
+ Router.new.tap do |r|
8
+
9
+ r.backends = {
10
+ rails: "127.0.0.1:3000",
11
+ static: "127.0.0.1:8080",
12
+ api: "api:80"
13
+ }
14
+
15
+ r.connect :static,
16
+ %r{^/robots.txt},
17
+ %r{^/(?:images|stylesheets|javascripts)/}
18
+
19
+ r.connect :api,
20
+ %r{^/api/}
21
+
22
+ end
23
+ end
24
+
25
+ it "routes by specified patterns" do
26
+ router.lookup("GET", "/robots.txt").should == "127.0.0.1:8080"
27
+ router.lookup("GET", "/images/logo.png").should == "127.0.0.1:8080"
28
+ router.lookup("GET", "/api/list").should == "api:80"
29
+ end
30
+
31
+ it "defaults to first backend for unmatched requests" do
32
+ router.lookup("GET", "/anything/else").should == "127.0.0.1:3000"
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH.unshift "./lib"
2
+
3
+ require "path_router/router"
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: path_router
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Paul Annesley
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-06-17 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: proxymachine
16
+ requirement: &2169316300 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.2.4
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2169316300
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &2169315880 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2169315880
36
+ description: Easily route HTTP requests to different backends by pattern matching
37
+ the URL path.
38
+ email:
39
+ - paul@annesley.cc
40
+ executables:
41
+ - path_router
42
+ extensions: []
43
+ extra_rdoc_files: []
44
+ files:
45
+ - .gitignore
46
+ - .rspec
47
+ - Gemfile
48
+ - Gemfile.lock
49
+ - README.md
50
+ - Rakefile
51
+ - bin/path_router
52
+ - example_path_router.rb
53
+ - lib/path_router.rb
54
+ - lib/path_router/router.rb
55
+ - lib/path_router/version.rb
56
+ - path_router.gemspec
57
+ - proxymachine_config.rb
58
+ - spec/path_router_spec.rb
59
+ - spec/spec_helper.rb
60
+ homepage: ''
61
+ licenses: []
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project: path_router
80
+ rubygems_version: 1.8.5
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: HTTP routing by URL path, built on ProxyMachine.
84
+ test_files:
85
+ - spec/path_router_spec.rb
86
+ - spec/spec_helper.rb