Version bump and, finally, thread safety and shared request context memory
This commit is contained in:
parent
de59eea736
commit
e1e2154677
|
@ -19,31 +19,28 @@ end
|
|||
|
||||
# Example Landline application as rack middleware
|
||||
class HelloServer < Landline::App
|
||||
setup do
|
||||
get "/test2" do
|
||||
"Hello world from #{self}!"
|
||||
end
|
||||
handle do |status, backtrace: nil|
|
||||
page = ([Landline::Util::HTTP_STATUS[status]] +
|
||||
(backtrace || [""])).join("\n")
|
||||
[
|
||||
{
|
||||
"content-length": page.bytesize,
|
||||
"content-type": "text/plain",
|
||||
"x-cascade": true
|
||||
},
|
||||
page
|
||||
]
|
||||
end
|
||||
get "/test2" do
|
||||
"Hello world from #{self}!"
|
||||
end
|
||||
|
||||
handle do |status, backtrace: nil|
|
||||
page = ([Landline::Util::HTTP_STATUS[status]] +
|
||||
(backtrace || [""])).join("\n")
|
||||
[
|
||||
{
|
||||
"content-length": page.bytesize,
|
||||
"content-type": "text/plain",
|
||||
"x-cascade": true
|
||||
},
|
||||
page
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
# Example Landline app as rack application
|
||||
class CrossCallServer < Landline::App
|
||||
setup do
|
||||
get "/inner_test" do
|
||||
"Hello world, through crosscall!"
|
||||
end
|
||||
get "/inner_test" do
|
||||
"Hello world, through crosscall!"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -52,21 +49,19 @@ class Server < Landline::App
|
|||
use TimerMiddleware
|
||||
use HelloServer
|
||||
|
||||
setup do
|
||||
crosscall_server = CrossCallServer.new
|
||||
crosscall_server = CrossCallServer.new
|
||||
|
||||
get "/test" do
|
||||
"Hello from #{self}!"
|
||||
end
|
||||
get "/test" do
|
||||
"Hello from #{self}!"
|
||||
end
|
||||
|
||||
# Cross-callable application included as a subpath
|
||||
link "/outer", crosscall_server
|
||||
# Cross-callable application included as a subpath
|
||||
link "/outer", crosscall_server
|
||||
|
||||
# Cross calling an application in a probe context
|
||||
get "/crosscall" do
|
||||
request.path = "/inner_test"
|
||||
call(crosscall_server)
|
||||
end
|
||||
# Cross calling an application in a probe context
|
||||
get "/crosscall" do
|
||||
request.path = "/inner_test"
|
||||
call(crosscall_server)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'landline'
|
||||
|
||||
class Application < Landline::App
|
||||
def initialize(*args)
|
||||
puts self
|
||||
super(*args)
|
||||
end
|
||||
|
||||
preprocess do
|
||||
puts Thread.current.inspect
|
||||
end
|
||||
|
||||
get "/long" do
|
||||
before = request
|
||||
sleep 10
|
||||
"Request didn't change mid-execution: #{before == request}"
|
||||
end
|
||||
|
||||
get "/long2" do
|
||||
puts self
|
||||
@instance_property = (rand * 1000).floor
|
||||
response = "Your magic number is #{@instance_property}\n"
|
||||
sleep 20
|
||||
response += "Your magic number after waiting 20 seconds is #{@instance_property}"
|
||||
response
|
||||
end
|
||||
|
||||
get "/magic" do
|
||||
@instance_property = (rand * 1000).floor
|
||||
end
|
||||
|
||||
postprocess do
|
||||
puts "Last value of instance_property: #{@instance_property}"
|
||||
end
|
||||
end
|
||||
|
||||
run Application.new
|
|
@ -4,28 +4,26 @@ require 'landline'
|
|||
require 'landline/extensions/websocket'
|
||||
|
||||
class Test < Landline::App
|
||||
setup do
|
||||
websocket "/test", version: 7 do |socket|
|
||||
socket.on :message do |msg|
|
||||
puts "Client wrote: #{msg}"
|
||||
end
|
||||
socket.on :error do |err|
|
||||
puts "Error occured: #{err.inspect}"
|
||||
puts err.backtrace
|
||||
end
|
||||
socket.on :close do
|
||||
puts "Client closed read connection"
|
||||
end
|
||||
socket.ready
|
||||
socket.write("Hi!")
|
||||
response = socket.read
|
||||
socket.write("You said: #{response}")
|
||||
socket.write("Goodbye!")
|
||||
socket.close
|
||||
rescue Exception => e
|
||||
puts e.inspect
|
||||
puts e.backtrace
|
||||
websocket "/test", version: 7 do |socket|
|
||||
socket.on :message do |msg|
|
||||
puts "Client wrote: #{msg}"
|
||||
end
|
||||
socket.on :error do |err|
|
||||
puts "Error occured: #{err.inspect}"
|
||||
puts err.backtrace
|
||||
end
|
||||
socket.on :close do
|
||||
puts "Client closed read connection"
|
||||
end
|
||||
socket.ready
|
||||
socket.write("Hi!")
|
||||
response = socket.read
|
||||
socket.write("You said: #{response}")
|
||||
socket.write("Goodbye!")
|
||||
socket.close
|
||||
rescue Exception => e
|
||||
puts e.inspect
|
||||
puts e.backtrace
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "landline"
|
||||
spec.version = "0.12.0"
|
||||
spec.version = "0.12.1"
|
||||
spec.summary = "Elegant HTTP DSL"
|
||||
spec.description = <<~DESC
|
||||
Landline is a no-hard-dependencies HTTP routing DSL that was made entirely for fun.
|
||||
|
|
|
@ -12,7 +12,7 @@ require_relative 'landline/app'
|
|||
# Landline is a backend framework born as a by-product of experimentation
|
||||
module Landline
|
||||
# Landline version
|
||||
VERSION = '0.12 "Concrete and Gold" (pre-alpha)'
|
||||
VERSION = '0.12.1 "Concrete and Gold" (pre-alpha)'
|
||||
|
||||
# Landline branding and version
|
||||
VLINE = "Landline/#{Landline::VERSION} (Ruby/#{RUBY_VERSION}/#{RUBY_RELEASE_DATE})\n".freeze
|
||||
|
|
|
@ -3,18 +3,20 @@
|
|||
module Landline
|
||||
# Rack application interface
|
||||
class App
|
||||
# TODO: fix this mess somehow (probably impossible)
|
||||
|
||||
# @!parse include Landline::DSL::PathMethods
|
||||
# @!parse include Landline::DSL::PathConstructors
|
||||
# @!parse include Landline::DSL::ProbeConstructors
|
||||
# @!parse include Landline::DSL::ProbeMethods
|
||||
# @!parse include Landline::DSL::CommonMethods
|
||||
class << self
|
||||
# TODO: fix this mess somehow (probably impossible)
|
||||
# @!parse include Landline::DSL::PathMethods
|
||||
# @!parse include Landline::DSL::PathConstructors
|
||||
# @!parse include Landline::DSL::ProbeConstructors
|
||||
# @!parse include Landline::DSL::ProbeMethods
|
||||
# @!parse include Landline::DSL::CommonMethods
|
||||
|
||||
# Duplicate used middleware for the subclassed app
|
||||
def inherited(subclass)
|
||||
super(subclass)
|
||||
@setup_chain ||= []
|
||||
subclass.middleware = @middleware.dup
|
||||
subclass.setup_chain = @setup_chain.dup
|
||||
end
|
||||
|
||||
# Include a middleware in application
|
||||
|
@ -24,17 +26,30 @@ module Landline
|
|||
@middleware.append(middleware)
|
||||
end
|
||||
|
||||
# Setup block
|
||||
# @param block [#call]
|
||||
def setup(&block)
|
||||
@setup_block = block
|
||||
# Check if Server can respond to given symbol
|
||||
def respond_to_missing?(symbol, _include_private)
|
||||
Landline::ServerContext.instance_methods.include?(symbol) || super
|
||||
end
|
||||
|
||||
attr_accessor :middleware, :setup_block
|
||||
# Store applied app manipulations
|
||||
def method_missing(symbol, *args, **params, &callback)
|
||||
if Landline::ServerContext.instance_methods.include? symbol
|
||||
@setup_chain.append([symbol, args, params, callback])
|
||||
else
|
||||
super(symbol, *args, **params, &callback)
|
||||
end
|
||||
end
|
||||
|
||||
attr_accessor :middleware, :setup_chain
|
||||
end
|
||||
|
||||
def initialize(*args, **opts)
|
||||
@app = ::Landline::Server.new(*args, **opts, &self.class.setup_block)
|
||||
setup_chain = self.class.setup_chain
|
||||
@app = ::Landline::Server.new(*args, **opts) do
|
||||
setup_chain.each do |symbol, cargs, cparams, callback|
|
||||
send(symbol, *cargs, **cparams, &callback)
|
||||
end
|
||||
end
|
||||
self.class.middleware&.reverse_each do |cls|
|
||||
@app = cls.new(@app)
|
||||
end
|
||||
|
|
|
@ -4,23 +4,9 @@ require_relative 'pattern_matching'
|
|||
require_relative 'node'
|
||||
require_relative 'dsl/constructors_path'
|
||||
require_relative 'dsl/methods_path'
|
||||
require_relative 'dsl/methods_common'
|
||||
require_relative 'dsl/methods_probe'
|
||||
require_relative 'dsl/constructors_probe'
|
||||
require_relative 'util/lookup'
|
||||
|
||||
module Landline
|
||||
# Execution context for filters and preprocessors.
|
||||
class ProcessorContext
|
||||
include Landline::DSL::CommonMethods
|
||||
include Landline::DSL::ProbeMethods
|
||||
include Landline::DSL::ProbeConstructors
|
||||
|
||||
def initialize(path)
|
||||
@origin = path
|
||||
end
|
||||
end
|
||||
|
||||
# Execution context for path setup block.
|
||||
class PathContext
|
||||
include Landline::DSL::PathConstructors
|
||||
|
@ -31,21 +17,8 @@ module Landline
|
|||
end
|
||||
end
|
||||
|
||||
# Ephemeral proxy class to which callback execution binds
|
||||
class PathExecutionOrigin
|
||||
def initialize(request, properties)
|
||||
@request = request
|
||||
@properties = Landline::Util::LookupROProxy.new(properties)
|
||||
end
|
||||
|
||||
attr_accessor :response
|
||||
attr_reader :request, :properties
|
||||
end
|
||||
|
||||
# Primary building block of request navigation.
|
||||
class Path < Landline::Node
|
||||
ExecutionOrigin = Landline::PathExecutionOrigin
|
||||
ProcContext = Landline::ProcessorContext
|
||||
Context = Landline::PathContext
|
||||
|
||||
# @param path [Object] Object to generate {Landline::Pattern} from
|
||||
|
@ -108,8 +81,8 @@ module Landline
|
|||
|
||||
# Create an execution context for in-path processing blocks
|
||||
def get_context(request)
|
||||
exec_origin = self.class::ExecutionOrigin.new(request, @properties)
|
||||
self.class::ProcContext.new(exec_origin)
|
||||
request.context.origin.properties.lookup = @properties
|
||||
request.context
|
||||
end
|
||||
|
||||
# Sequentially run through all filters and drop request if one is false
|
||||
|
|
|
@ -24,28 +24,6 @@ module Landline
|
|||
autoload :Link, "landline/probe/crosscall_handler"
|
||||
end
|
||||
|
||||
# Context that provides execution context for Probes.
|
||||
class ProbeContext
|
||||
include Landline::DSL::ProbeConstructors
|
||||
include Landline::DSL::ProbeMethods
|
||||
include Landline::DSL::CommonMethods
|
||||
|
||||
def initialize(origin)
|
||||
@origin = origin
|
||||
end
|
||||
end
|
||||
|
||||
# Ephemeral proxy class to which callback execution binds
|
||||
class ProbeExecutionOrigin
|
||||
def initialize(request, properties)
|
||||
@request = request
|
||||
@properties = Landline::Util::LookupROProxy.new(properties)
|
||||
end
|
||||
|
||||
attr_accessor :response
|
||||
attr_reader :request, :properties
|
||||
end
|
||||
|
||||
# Test probe. Also base for all "reactive" nodes.
|
||||
class Probe < Landline::Node
|
||||
# @param path [Object]
|
||||
|
|
|
@ -29,8 +29,8 @@ module Landline
|
|||
# @return [Boolean] true if further navigation is possible
|
||||
# @raise [UncaughtThrowError] may raise if die() is called.
|
||||
def process(request)
|
||||
origin = Landline::ProbeExecutionOrigin.new(request, @properties)
|
||||
context = Landline::ProbeContext.new(origin)
|
||||
origin, context = get_context(request)
|
||||
|
||||
return reject(request) unless request.path.match?(/^\/?$/)
|
||||
|
||||
response = catch(:break) do
|
||||
|
@ -47,6 +47,14 @@ module Landline
|
|||
end
|
||||
throw :finish, response
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Create a context to run handler in
|
||||
def get_context(request)
|
||||
request.context.origin.properties.lookup = @properties
|
||||
[request.context.origin, request.context]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
require 'uri'
|
||||
require_relative 'util/query'
|
||||
require_relative 'util/cookie'
|
||||
require_relative 'sandbox'
|
||||
|
||||
module Landline
|
||||
# Request wrapper for Rack protocol
|
||||
|
@ -30,13 +31,16 @@ module Landline
|
|||
@states = []
|
||||
# Postprocessors for current request
|
||||
@postprocessors = []
|
||||
# Execution context
|
||||
@context = init_context
|
||||
end
|
||||
|
||||
# Run postprocessors
|
||||
# @param response [Landline::Response]
|
||||
def run_postprocessors(response)
|
||||
@context.origin.properties.lookup = {}
|
||||
@postprocessors.reverse_each do |postproc|
|
||||
postproc.call(self, response)
|
||||
@context.instance_exec(self, response, &postproc)
|
||||
end
|
||||
@postprocessors = []
|
||||
end
|
||||
|
@ -90,11 +94,17 @@ module Landline
|
|||
|
||||
attr_reader :request_method, :script_name, :path_info, :server_name,
|
||||
:server_port, :server_protocol, :headers, :param, :splat,
|
||||
:postprocessors, :cookies, :rack
|
||||
:postprocessors, :cookies, :rack, :context
|
||||
attr_accessor :path, :filepath, :query
|
||||
|
||||
private
|
||||
|
||||
# Initialize execution context
|
||||
def init_context
|
||||
origin = Landline::ProcessorOrigin.new(self, {})
|
||||
Landline::ProcessorContext.new(origin)
|
||||
end
|
||||
|
||||
# Initialize basic rack request parameters
|
||||
# @param env [Hash]
|
||||
def init_request_params(env)
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'dsl/methods_common'
|
||||
require_relative 'dsl/methods_probe'
|
||||
require_relative 'dsl/constructors_probe'
|
||||
require_relative 'util/lookup'
|
||||
|
||||
module Landline
|
||||
# Execution context for filters and preprocessors.
|
||||
class ProcessorContext
|
||||
include Landline::DSL::CommonMethods
|
||||
include Landline::DSL::ProbeMethods
|
||||
include Landline::DSL::ProbeConstructors
|
||||
|
||||
def initialize(path)
|
||||
@origin = path
|
||||
end
|
||||
|
||||
attr_reader :origin
|
||||
end
|
||||
|
||||
# Ephemeral proxy class to which callback execution binds
|
||||
class ProcessorOrigin
|
||||
def initialize(request, properties)
|
||||
@request = request
|
||||
@properties = Landline::Util::LookupROProxy.new(properties)
|
||||
end
|
||||
|
||||
attr_accessor :response
|
||||
attr_reader :request, :properties
|
||||
end
|
||||
end
|
|
@ -14,7 +14,7 @@ module Landline
|
|||
# @param parent [Landline::Node, nil] Parent object to inherit properties to
|
||||
# @param setup [#call] Setup block
|
||||
def initialize(passthrough = nil, parent: nil, **opts, &setup)
|
||||
super("", parent: nil, **opts, &setup)
|
||||
super("", parent: parent, **opts, &setup)
|
||||
return if parent
|
||||
|
||||
@passthrough = passthrough
|
||||
|
|
|
@ -46,6 +46,8 @@ module Landline
|
|||
def [](key)
|
||||
@lookup.[](key)
|
||||
end
|
||||
|
||||
attr_accessor :lookup
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue