upr 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +1 -1
- data/LICENSE +9 -4
- data/README +29 -13
- data/examples/rails_app-2.3.4/app/controllers/application_controller.rb +8 -1
- data/examples/rails_app-2.3.4/app/controllers/files_controller.rb +35 -12
- data/examples/rails_app-2.3.4/app/controllers/progress_controller.rb +11 -0
- data/examples/rails_app-2.3.4/app/models/upr_status.rb +34 -10
- data/examples/rails_app-2.3.4/app/views/files/index.html.erb +14 -4
- data/examples/rails_app-2.3.4/app/views/files/new.html.erb +71 -0
- data/examples/rails_app-2.3.4/app/views/files/pull.html.erb +60 -0
- data/examples/rails_app-2.3.4/config.ru +3 -0
- data/examples/rails_app-2.3.4/config/initializers/ruby_19_compat.rb +26 -0
- data/examples/rails_app-2.3.4/public/javascripts/ajax_pull/ajax_pull.js +85 -0
- data/examples/rails_app-2.3.4/public/javascripts/ajax_pull/prototype-1_5_1.js +3271 -0
- data/examples/rails_app-2.3.4/public/javascripts/ajax_pull/upload_progress.js +139 -0
- data/examples/rails_app-2.3.4/public/javascripts/jquery.js +32 -0
- data/examples/rails_app-2.3.4/public/javascripts/jquery.uploadProgress.js +116 -0
- data/examples/rails_app-2.3.4/public/stylesheets/site.css +41 -0
- data/examples/rails_app-2.3.4/rainbows_config.rb +1 -1
- data/examples/rails_app-2.3.4/test/fixtures/upr_statuses.yml +22 -0
- data/examples/rails_app-2.3.4/test/unit/upr_status_test.rb +41 -0
- data/lib/upr.rb +4 -5
- data/lib/upr/input_wrapper.rb +17 -13
- data/lib/upr/json.rb +143 -0
- data/lib/upr/monitor.rb +18 -6
- data/lib/upr/params.rb +24 -0
- data/lib/upr/status.rb +9 -0
- data/lib/upr/status_methods.rb +13 -0
- data/test/test_monitor.rb +58 -0
- data/upr.gemspec +1 -0
- metadata +37 -5
data/lib/upr/json.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
begin
|
3
|
+
require 'json'
|
4
|
+
rescue LoadError
|
5
|
+
raise LoadError, "either json or json-pure is required"
|
6
|
+
end
|
7
|
+
require 'rack'
|
8
|
+
|
9
|
+
module Upr
|
10
|
+
|
11
|
+
# JSON protocol based on Lighttpd's mod_uploadprogress
|
12
|
+
# http://trac.lighttpd.net/trac/wiki/Docs:ModUploadProgress
|
13
|
+
class JSON < Struct.new(:frequency, :backend, :upload_id)
|
14
|
+
|
15
|
+
include Params
|
16
|
+
|
17
|
+
# We use this in case length is nil when clients send chunked uploads
|
18
|
+
INT_MAX = 0x7fffffff
|
19
|
+
|
20
|
+
SLEEP_CLASS = defined?(Actor) ? Actor : Kernel
|
21
|
+
|
22
|
+
# our default response headers, we need to set no-transform to
|
23
|
+
# prevent deflaters from compressing our already-small small input
|
24
|
+
# and also to prevent buffering/corking of the response inside
|
25
|
+
# deflater buffers.
|
26
|
+
RESPONSE_HEADERS = {
|
27
|
+
'Content-Type' => 'application/json',
|
28
|
+
'Cache-Control' => 'no-cache, no-transform',
|
29
|
+
}
|
30
|
+
|
31
|
+
def initialize(options = {})
|
32
|
+
super(options[:frequency] || 1, options[:backend], options[:upload_id])
|
33
|
+
|
34
|
+
# support :drb for compatibility with mongrel_upload_progress
|
35
|
+
if options[:drb]
|
36
|
+
backend and raise ArgumentError, ":backend and :drb are incompatible"
|
37
|
+
require 'drb'
|
38
|
+
DRb.start_service
|
39
|
+
self.backend = DRbObject.new(nil, options[:drb])
|
40
|
+
elsif String === backend
|
41
|
+
# allow people to use strings in case their backend gets
|
42
|
+
# lazy-loaded (like an ActiveRecord model)
|
43
|
+
self.backend = eval(backend)
|
44
|
+
elsif backend.nil?
|
45
|
+
raise ArgumentError, "backend MUST be specified"
|
46
|
+
end
|
47
|
+
|
48
|
+
# only for use with rails_proc
|
49
|
+
upload_id.nil? and self.upload_id = options[:env]
|
50
|
+
end
|
51
|
+
|
52
|
+
def rails_render_options
|
53
|
+
env = upload_id
|
54
|
+
self.upload_id = extract_upload_id(env)
|
55
|
+
text = if Rack::Request.new(env).GET.include?("long")
|
56
|
+
Proc.new { |response,output| each { |line| output.write(line) } }
|
57
|
+
else
|
58
|
+
_once
|
59
|
+
end
|
60
|
+
{ :content_type => 'application/json', :text => text }
|
61
|
+
end
|
62
|
+
|
63
|
+
def _once
|
64
|
+
if status = backend.read(upload_id)
|
65
|
+
if status.done?
|
66
|
+
_json_object(:state => 'done')
|
67
|
+
elsif status.seen == 0
|
68
|
+
_json_object(:state => 'starting')
|
69
|
+
elsif status.error?
|
70
|
+
_error_msg("upload failed")
|
71
|
+
else
|
72
|
+
_update_msg(status)
|
73
|
+
end
|
74
|
+
else
|
75
|
+
timeout = Time.now + 2
|
76
|
+
until status = backend.read(upload_id)
|
77
|
+
SLEEP_CLASS.sleep(0.1)
|
78
|
+
return _error_msg("couldn't get status") if Time.now > timeout
|
79
|
+
end
|
80
|
+
_json_object(:state => 'starting')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Rack interface reservced for future use with streaming AJAX
|
85
|
+
def call(env)
|
86
|
+
if uid = extract_upload_id(env)
|
87
|
+
_wrap(env, uid)
|
88
|
+
else
|
89
|
+
[ 400, RESPONSE_HEADERS.dup, [ _error_msg("upload_id not given") ] ]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Rack interface reservced for future use with streaming AJAX
|
94
|
+
def each(&block)
|
95
|
+
sleeper = defined?(Actor) ? Actor : Kernel
|
96
|
+
timeout = Time.now + 2
|
97
|
+
eol = ";\n"
|
98
|
+
yield _json_object(:state => 'starting') << eol
|
99
|
+
begin
|
100
|
+
until status = backend.read(upload_id)
|
101
|
+
sleeper.sleep(0.1)
|
102
|
+
break if Time.now > timeout
|
103
|
+
end
|
104
|
+
if status
|
105
|
+
begin
|
106
|
+
yield _update_msg(status) << eol
|
107
|
+
break if status.done?
|
108
|
+
sleeper.sleep(frequency)
|
109
|
+
end while status = backend.read(upload_id)
|
110
|
+
yield _json_object(:state => 'done') << eol
|
111
|
+
else
|
112
|
+
yield _error_msg("couldn't get status") << eol
|
113
|
+
end
|
114
|
+
rescue => e
|
115
|
+
yield _error_msg(e.message) << eol
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Rack interface reservced for future use with streaming AJAX
|
120
|
+
def _wrap(env, uid)
|
121
|
+
_self = dup
|
122
|
+
_self.upload_id = uid
|
123
|
+
[ 200, RESPONSE_HEADERS.dup, _self ]
|
124
|
+
end
|
125
|
+
|
126
|
+
def _error_msg(msg)
|
127
|
+
_json_object(:state => 'error', :status => 400, :message => msg)
|
128
|
+
end
|
129
|
+
|
130
|
+
def _json_object(options)
|
131
|
+
# $stderr.syswrite "#{options.inspect} #{$upr.inspect}\n"
|
132
|
+
options.to_json
|
133
|
+
end
|
134
|
+
|
135
|
+
def _update_msg(status)
|
136
|
+
raise "client error" if status.error?
|
137
|
+
received = status.seen
|
138
|
+
size = status.length || INT_MAX
|
139
|
+
_json_object(:state => 'uploading', :size => size, :received => received)
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|
data/lib/upr/monitor.rb
CHANGED
@@ -8,11 +8,11 @@ module Upr
|
|
8
8
|
# Usage (in config.ru with Moneta::Memory store):
|
9
9
|
# require 'upr'
|
10
10
|
# require 'moneta/memory'
|
11
|
-
# use Upr, :backend => Upr::
|
11
|
+
# use Upr, :backend => Upr::Monitor.new(Moneta::Memory.new)
|
12
12
|
# run YourApplication.new
|
13
13
|
class Monitor < Struct.new(:moneta)
|
14
|
-
# nuke anything not read/updated in
|
15
|
-
OPT = { :expires_in =>
|
14
|
+
# nuke anything not read/updated in 60 seconds
|
15
|
+
OPT = { :expires_in => 60 }
|
16
16
|
|
17
17
|
def initialize(moneta_store = nil)
|
18
18
|
super
|
@@ -27,13 +27,25 @@ module Upr
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def read(upid)
|
30
|
-
moneta.update_key(upid, OPT)
|
31
30
|
moneta[upid]
|
32
31
|
end
|
33
32
|
|
34
33
|
def incr(upid, nr)
|
35
|
-
status = moneta[upid]
|
36
|
-
status.seen += nr
|
34
|
+
status = moneta[upid] or return
|
35
|
+
status.seen += nr if status.seen >= 0
|
36
|
+
moneta.store(upid, status, OPT)
|
37
|
+
end
|
38
|
+
|
39
|
+
def finish(upid)
|
40
|
+
status = moneta[upid] or return
|
41
|
+
status.length ||= status.seen
|
42
|
+
status.seen = status.length
|
43
|
+
moneta.store(upid, status, OPT)
|
44
|
+
end
|
45
|
+
|
46
|
+
def error!(upid)
|
47
|
+
status = moneta[upid] or return
|
48
|
+
status.seen = -1
|
37
49
|
moneta.store(upid, status, OPT)
|
38
50
|
end
|
39
51
|
|
data/lib/upr/params.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require 'rack'
|
3
|
+
|
4
|
+
module Upr
|
5
|
+
|
6
|
+
module Params
|
7
|
+
|
8
|
+
# we'll add compatibility for existing upload progress modules
|
9
|
+
# we find here, but under no circumstances will we help
|
10
|
+
# proliferate new and subtly incompatible mechanisms.
|
11
|
+
# X-Progress-ID is used in both lighttpd and nginx (3rd party module)
|
12
|
+
# "upload_id" is used by mongrel_upload_progress
|
13
|
+
def extract_upload_id(env)
|
14
|
+
upid = env['HTTP_X_PROGRESS_ID'] and return upid
|
15
|
+
|
16
|
+
# can't blindly parse params here since we don't want to read
|
17
|
+
# the POST body if there is one, so only parse stuff in the
|
18
|
+
# query string...
|
19
|
+
params = Rack::Request.new(env).GET
|
20
|
+
env["upr.upload_id"] = params["X-Progress-ID"] || params["upload_id"]
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
data/lib/upr/status.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'upr'
|
3
|
+
|
4
|
+
class MonitorTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@monitor = Upr::Monitor.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_start_with_length
|
10
|
+
assert_kind_of Upr::Status, @monitor.start('abcde', 5)
|
11
|
+
status = @monitor.read('abcde')
|
12
|
+
assert_equal 5, status.length
|
13
|
+
assert_equal 0, status.seen
|
14
|
+
assert ! status.error?
|
15
|
+
assert ! status.done?
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_start_without_length
|
19
|
+
assert_kind_of Upr::Status, @monitor.start('abcde', nil)
|
20
|
+
status = @monitor.read('abcde')
|
21
|
+
assert_nil status.length
|
22
|
+
assert_equal 0, status.seen
|
23
|
+
assert ! status.error?
|
24
|
+
assert ! status.done?
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_to_incr
|
28
|
+
assert_kind_of Upr::Status, @monitor.start('abcde', 5)
|
29
|
+
status = @monitor.incr('abcde', 2)
|
30
|
+
assert_kind_of Upr::Status, status
|
31
|
+
assert_equal 2, status.seen
|
32
|
+
assert ! status.error?
|
33
|
+
assert ! status.done?
|
34
|
+
@monitor.incr('abcde', 3)
|
35
|
+
assert_equal 5, status.seen
|
36
|
+
assert ! status.error?
|
37
|
+
assert status.done?
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_finish_with_length
|
41
|
+
assert_kind_of Upr::Status, status = @monitor.start('abcde', 5)
|
42
|
+
@monitor.finish('abcde')
|
43
|
+
assert ! status.error?
|
44
|
+
assert status.done?
|
45
|
+
assert_equal 5, status.seen
|
46
|
+
assert_equal 5, status.length
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_finish_without_length
|
50
|
+
assert_kind_of Upr::Status, status = @monitor.start('abcde', nil)
|
51
|
+
@monitor.finish('abcde')
|
52
|
+
assert ! status.error?
|
53
|
+
assert status.done?
|
54
|
+
assert_equal 0, status.seen
|
55
|
+
assert_equal 0, status.length
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/upr.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: upr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- upr hackers
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-14 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -22,11 +22,22 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: "0"
|
24
24
|
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rack
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
25
35
|
description: |-
|
26
36
|
upr is Rack middleware that allows browser-side upload progress
|
27
|
-
monitoring. It is based on
|
28
|
-
|
29
|
-
|
37
|
+
monitoring. It is based on (and should be client-side compatible with)
|
38
|
+
several upload progress modules including ones used by leading web
|
39
|
+
servers. It allows any Moneta backing store in addition to DRb. There
|
40
|
+
is also a packaged example for using an ActiveRecord model for Rails.
|
30
41
|
email: upr@librelist.com
|
31
42
|
executables:
|
32
43
|
- upr-drb
|
@@ -36,7 +47,11 @@ extra_rdoc_files:
|
|
36
47
|
- ChangeLog
|
37
48
|
- lib/upr.rb
|
38
49
|
- lib/upr/input_wrapper.rb
|
50
|
+
- lib/upr/json.rb
|
39
51
|
- lib/upr/monitor.rb
|
52
|
+
- lib/upr/params.rb
|
53
|
+
- lib/upr/status.rb
|
54
|
+
- lib/upr/status_methods.rb
|
40
55
|
- LICENSE
|
41
56
|
- NEWS
|
42
57
|
- README
|
@@ -57,9 +72,12 @@ files:
|
|
57
72
|
- examples/rails_app-2.3.4/Rakefile
|
58
73
|
- examples/rails_app-2.3.4/app/controllers/application_controller.rb
|
59
74
|
- examples/rails_app-2.3.4/app/controllers/files_controller.rb
|
75
|
+
- examples/rails_app-2.3.4/app/controllers/progress_controller.rb
|
60
76
|
- examples/rails_app-2.3.4/app/helpers/application_helper.rb
|
61
77
|
- examples/rails_app-2.3.4/app/models/upr_status.rb
|
62
78
|
- examples/rails_app-2.3.4/app/views/files/index.html.erb
|
79
|
+
- examples/rails_app-2.3.4/app/views/files/new.html.erb
|
80
|
+
- examples/rails_app-2.3.4/app/views/files/pull.html.erb
|
63
81
|
- examples/rails_app-2.3.4/config.ru
|
64
82
|
- examples/rails_app-2.3.4/config/boot.rb
|
65
83
|
- examples/rails_app-2.3.4/config/database.yml
|
@@ -68,6 +86,7 @@ files:
|
|
68
86
|
- examples/rails_app-2.3.4/config/environments/production.rb
|
69
87
|
- examples/rails_app-2.3.4/config/environments/test.rb
|
70
88
|
- examples/rails_app-2.3.4/config/initializers/new_rails_defaults.rb
|
89
|
+
- examples/rails_app-2.3.4/config/initializers/ruby_19_compat.rb
|
71
90
|
- examples/rails_app-2.3.4/config/routes.rb
|
72
91
|
- examples/rails_app-2.3.4/db/.gitignore
|
73
92
|
- examples/rails_app-2.3.4/db/migrate/19700000000000_add_upr_status.rb
|
@@ -78,20 +97,33 @@ files:
|
|
78
97
|
- examples/rails_app-2.3.4/public/422.html
|
79
98
|
- examples/rails_app-2.3.4/public/500.html
|
80
99
|
- examples/rails_app-2.3.4/public/favicon.ico
|
100
|
+
- examples/rails_app-2.3.4/public/javascripts/ajax_pull/ajax_pull.js
|
101
|
+
- examples/rails_app-2.3.4/public/javascripts/ajax_pull/prototype-1_5_1.js
|
102
|
+
- examples/rails_app-2.3.4/public/javascripts/ajax_pull/upload_progress.js
|
81
103
|
- examples/rails_app-2.3.4/public/javascripts/application.js
|
82
104
|
- examples/rails_app-2.3.4/public/javascripts/controls.js
|
83
105
|
- examples/rails_app-2.3.4/public/javascripts/dragdrop.js
|
84
106
|
- examples/rails_app-2.3.4/public/javascripts/effects.js
|
107
|
+
- examples/rails_app-2.3.4/public/javascripts/jquery.js
|
108
|
+
- examples/rails_app-2.3.4/public/javascripts/jquery.uploadProgress.js
|
85
109
|
- examples/rails_app-2.3.4/public/javascripts/prototype.js
|
86
110
|
- examples/rails_app-2.3.4/public/javascripts/upr.js
|
87
111
|
- examples/rails_app-2.3.4/public/robots.txt
|
112
|
+
- examples/rails_app-2.3.4/public/stylesheets/site.css
|
88
113
|
- examples/rails_app-2.3.4/rainbows_config.rb
|
114
|
+
- examples/rails_app-2.3.4/test/fixtures/upr_statuses.yml
|
89
115
|
- examples/rails_app-2.3.4/test/test_helper.rb
|
116
|
+
- examples/rails_app-2.3.4/test/unit/upr_status_test.rb
|
90
117
|
- lib/upr.rb
|
91
118
|
- lib/upr/input_wrapper.rb
|
119
|
+
- lib/upr/json.rb
|
92
120
|
- lib/upr/monitor.rb
|
121
|
+
- lib/upr/params.rb
|
122
|
+
- lib/upr/status.rb
|
123
|
+
- lib/upr/status_methods.rb
|
93
124
|
- local.mk.sample
|
94
125
|
- setup.rb
|
126
|
+
- test/test_monitor.rb
|
95
127
|
- upr.gemspec
|
96
128
|
has_rdoc: true
|
97
129
|
homepage: http://upr.bogomips.org/
|