Class: Tap::Server
- Inherits:
-
Object
- Object
- Tap::Server
- Includes:
- Configurable, Rack::Utils
- Defined in:
- lib/tap/server.rb
Overview
:::- Server is a Rack application that dispatches calls to other Rack apps, most commonly a Tap::Controller.
Routes
Routing is fixed and very simple:
/:controller/path/to/resource
Server dispatches the request to the controller keyed by :controller after shifting the key from PATH_INFO to SCRIPT_NAME.
server = Server.new
server.controllers['sample'] = lambda do |env|
[200, {}, ["Sample got #{env['SCRIPT_NAME']} : #{env['PATH_INFO']}"]]
end
req = Rack::MockRequest.new(server)
req.get('/sample/path/to/resource').body # => "Sample got /sample : /path/to/resource"
Server automatically maps unknown keys to controllers discovered via the env.controllers manifest. The only requirement is that the controller constant is a Rack application. For instance:
# [lib/example.rb] => %q{
# ::controller
# class Example
# def self.call(env)
# [200, {}, ["Example got #{env['SCRIPT_NAME']} : #{env['PATH_INFO']}"]]
# end
# end
# }
req.get('/example/path/to/resource').body # => "Example got /example : /path/to/resource"
If desired, controllers can be set with aliases to map a path key to a lookup key.
server.controllers['sample'] = 'example'
req.get('/sample/path/to/resource').body # => "Example got /sample : /path/to/resource"
If no controller can be found, the request is routed using the default_controller_key and the request is NOT adjusted.
server.default_controller_key = 'app'
server.controllers['app'] = lambda do |env|
[200, {}, ["App got #{env['SCRIPT_NAME']} : #{env['PATH_INFO']}"]]
end
req.get('/unknown/path/to/resource').body # => "App got : /unknown/path/to/resource"
In development mode, the controller constant is removed and the constant require path is reloaded each time it gets called. This system allows many web frameworks to be hooked into a Tap server.
:::+
Instance Attribute Summary collapse
-
#env ⇒ Object
readonly
Returns the value of attribute env.
-
#handler ⇒ Object
readonly
Returns the value of attribute handler.
Class Method Summary collapse
-
.instantiate(root, shutdown_key = false) ⇒ Object
Instantiates a Server in the specified directory, configured as specified in root/server.yml.
-
.run(server) ⇒ Object
Runs the server.
Instance Method Summary collapse
-
#app(id = nil) ⇒ Object
Returns the session-specific App, or the server app if id is nil.
-
#call(rack_env) ⇒ Object
The Rack interface method.
-
#initialize(env = Env.new, app = Tap::App.instance, config = {}) ⇒ Server
constructor
A new instance of Server.
-
#initialize_session ⇒ Object
Currently a stub for initializing a session.
-
#root(id = nil) ⇒ Object
Returns the session-specific Root, or the server env.root if id is nil.
-
#run!(handler = rack_handler) ⇒ Object
Runs self as configured, on the specified server, host, and port.
-
#search(dir, path) ⇒ Object
Searches env for the first matching file, directories are not matched.
-
#stop! ⇒ Object
Stops the server if running (ie a handler is set).
-
#uri(controller = nil, action = nil, params = {}) ⇒ Object
Returns a uri mapping to the specified controller and action.
Constructor Details
#initialize(env = Env.new, app = Tap::App.instance, config = {}) ⇒ Server
Returns a new instance of Server.
135 136 137 138 139 140 141 |
# File 'lib/tap/server.rb', line 135 def initialize(env=Env.new, app=Tap::App.instance, config={}) @env = env @app = app @cache = {} @handler = nil initialize_config(config) end |
Instance Attribute Details
#env ⇒ Object (readonly)
Returns the value of attribute env.
132 133 134 |
# File 'lib/tap/server.rb', line 132 def env @env end |
#handler ⇒ Object (readonly)
Returns the value of attribute handler.
133 134 135 |
# File 'lib/tap/server.rb', line 133 def handler @handler end |
Class Method Details
.instantiate(root, shutdown_key = false) ⇒ Object
Instantiates a Server in the specified directory, configured as specified in root/server.yml. If shutdown_key is specified, a random shutdown key will be generated and set on the sever.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/tap/server.rb', line 80 def instantiate(root, shutdown_key=false) # setup the server directory root = File.(root) FileUtils.mkdir_p(root) unless File.exists?(root) # initialize the server app = Tap::App.instance env = Tap::Exe.instantiate(root) env.activate config = Configurable::Utils.load_file(env.root['server.yml']) server = new(env, app, config) server.config[:shutdown_key] = rand(1000000) if shutdown_key server end |
.run(server) ⇒ Object
Runs the server
97 98 99 100 |
# File 'lib/tap/server.rb', line 97 def run(server) = Rack::Session::Pool.new(server) server.run! end |
Instance Method Details
#app(id = nil) ⇒ Object
Returns the session-specific App, or the server app if id is nil.
203 204 205 |
# File 'lib/tap/server.rb', line 203 def app(id=nil) @app end |
#call(rack_env) ⇒ Object
The Rack interface method.
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/tap/server.rb', line 225 def call(rack_env) if development? env.reset @cache.clear end # route to a controller blank, key, path_info = rack_env['PATH_INFO'].split("/", 3) controller = lookup(unescape(key)) if controller # adjust env if key routes to a controller rack_env['SCRIPT_NAME'] = ["#{rack_env['SCRIPT_NAME'].chomp('/')}/#{key}"] rack_env['PATH_INFO'] = ["/#{path_info}"] else # use default controller key controller = lookup(default_controller_key) unless controller raise ServerError.new("404 Error: could not route to controller", 404) end end # handle the request rack_env['tap.server'] = self controller.call(rack_env) rescue ServerError $!.response rescue Exception ServerError.response($!) end |
#initialize_session ⇒ Object
Currently a stub for initializing a session. initialize_session returns an integer session id.
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/tap/server.rb', line 168 def initialize_session id = 0 session_app = app(id) session_root = root(id) # setup expiration information... # setup a session log log_path = session_root.prepare(:log, 'session.log') session_app.logger = Logger.new(log_path) session_app.on_complete do |_result| # find the template class_name = _result.key.class.to_s.underscore pattern = "#{class_name}/result\.*" template = nil env.each do |e| templates = e.root.glob(views_dir, pattern) unless templates.empty? template = templates[0] break end end if template extname = File.extname(template) env.root.prepare(:results, id.to_s, "#{class_name}#{extname}") do |file| file << Support::Templater.new(File.read(template)).build(:_result => _result) end end end unless session_app.on_complete_block id end |
#root(id = nil) ⇒ Object
Returns the session-specific Root, or the server env.root if id is nil.
208 209 210 |
# File 'lib/tap/server.rb', line 208 def root(id=nil) @env.root end |
#run!(handler = rack_handler) ⇒ Object
Runs self as configured, on the specified server, host, and port. Use an INT signal to interrupt.
145 146 147 148 149 150 151 |
# File 'lib/tap/server.rb', line 145 def run!(handler=rack_handler) app.log :run, "#{host}:#{port} (#{handler})" handler.run self, :Host => host, :Port => port do |handler_instance| @handler = handler_instance trap(:INT) { stop! } end end |
#search(dir, path) ⇒ Object
Searches env for the first matching file, directories are not matched.
258 259 260 |
# File 'lib/tap/server.rb', line 258 def search(dir, path) env.search(dir, path) {|file| File.file?(file) } end |
#stop! ⇒ Object
Stops the server if running (ie a handler is set). Returns true if the server was stopped, and false otherwise.
155 156 157 158 159 160 161 162 163 164 |
# File 'lib/tap/server.rb', line 155 def stop! if handler # Use thins' hard #stop! if available, otherwise just #stop handler.respond_to?(:stop!) ? handler.stop! : handler.stop @handler = nil false else true end end |
#uri(controller = nil, action = nil, params = {}) ⇒ Object
Returns a uri mapping to the specified controller and action. Parameters may be specified; they are built as a query and attached to the uri as normal.
Currenlty uri does not map the controller to a minipath, but in the future it will.
218 219 220 221 222 |
# File 'lib/tap/server.rb', line 218 def uri(controller=nil, action=nil, params={}) query = build_query(params) uri = ["http://#{host}:#{port}", escape(controller), action].compact.join("/") query.empty? ? uri : "#{uri}?#{query}" end |