thin_async 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # Thin Asynchronous Response API
2
+ A nice wrapper around Thin's obscure async callback used to send response body asynchronously.
3
+ Which means you can send the response in chunks while allowing Thin to process other requests.
4
+
5
+ Crazy delicious with em-http-request for file upload, image processing, proxying, etc.
6
+
7
+ ## _WARNING_
8
+ You should not use long blocking operations (Net::HTTP or slow shell calls) with this as it
9
+ will prevent the EventMachine event loop from running and block all other requests.
10
+
11
+ ## Usage
12
+ Inside your Rack app #call(env):
13
+
14
+ Thin::AsyncResponse.new(env) do |response|
15
+ response << "this is ... "
16
+ EM.add_timer(1) do
17
+ # This will be sent to the client 1 sec later without blocking other requests.
18
+ response << "async!"
19
+ response.done
20
+ end
21
+ end
22
+
23
+ See example/ dir for more.
24
+
25
+ (c) macournoyer
data/example/simple.ru ADDED
@@ -0,0 +1,19 @@
1
+ require File.dirname(__FILE__) + "/../lib/thin/async"
2
+
3
+ class Simple
4
+ def call(env)
5
+ response = Thin::AsyncResponse.new(env)
6
+
7
+ response << " " * 1024
8
+
9
+ response << "this is ... "
10
+ EM.add_timer(1) do
11
+ response << "async stuff!"
12
+ response.done
13
+ end
14
+
15
+ response.finish
16
+ end
17
+ end
18
+
19
+ run Simple.new
data/lib/thin/async.rb ADDED
@@ -0,0 +1,72 @@
1
+ module Thin
2
+ unless defined?(DeferrableBody)
3
+ # Based on version from James Tucker <raggi@rubyforge.org>
4
+ class DeferrableBody
5
+ include EM::Deferrable
6
+
7
+ def initialize
8
+ @queue = []
9
+ end
10
+
11
+ def call(body)
12
+ @queue << body
13
+ schedule_dequeue
14
+ end
15
+
16
+ def each(&blk)
17
+ @body_callback = blk
18
+ schedule_dequeue
19
+ end
20
+
21
+ private
22
+ def schedule_dequeue
23
+ return unless @body_callback
24
+ EM.next_tick do
25
+ next unless body = @queue.shift
26
+ body.each do |chunk|
27
+ @body_callback.call(chunk)
28
+ end
29
+ schedule_dequeue unless @queue.empty?
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ # Response whos body is sent asynchronously.
36
+ class AsyncResponse
37
+ include Rack::Response::Helpers
38
+
39
+ Marker = [-1, {}, []].freeze
40
+
41
+ attr_reader :headers
42
+ attr_accessor :status
43
+
44
+ def initialize(env)
45
+ @callback = env['async.callback']
46
+ @body = DeferrableBody.new
47
+ @status = 200
48
+ @headers = {}
49
+
50
+ if block_given?
51
+ yield self
52
+ finish
53
+ end
54
+ end
55
+
56
+ def write(body)
57
+ @body.call(body.respond_to?(:each) ? body : [body])
58
+ end
59
+ alias :<< :write
60
+
61
+ def done
62
+ EM.next_tick do
63
+ @body.succeed
64
+ end
65
+ end
66
+
67
+ def finish
68
+ @callback.call [@status, @headers, @body]
69
+ Marker
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,13 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "thin_async"
3
+ s.version = "0.0.1"
4
+ s.summary = "A nice wrapper to send response body asynchronously with Thin"
5
+
6
+ s.author = "Marc-Andre Cournoyer"
7
+ s.email = "macournoyer@gmail.com"
8
+ s.files = Dir["**/*"]
9
+ s.homepage = "http://github.com/macournoyer/thin_async"
10
+ s.require_paths = ["lib"]
11
+
12
+ s.add_dependency "thin", ">= 1.2.1"
13
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: thin_async
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Marc-Andre Cournoyer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-13 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: thin
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.1
24
+ version:
25
+ description:
26
+ email: macournoyer@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - example/simple.ru
35
+ - lib/thin/async.rb
36
+ - README.md
37
+ - thin_async-0.0.1.gem
38
+ - thin_async.gemspec
39
+ has_rdoc: true
40
+ homepage: http://github.com/macournoyer/thin_async
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options: []
45
+
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ requirements: []
61
+
62
+ rubyforge_project:
63
+ rubygems_version: 1.3.5
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: A nice wrapper to send response body asynchronously with Thin
67
+ test_files: []
68
+