upr 0.1.0 → 0.2.0
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/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/
|