upr 0.1.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.
Files changed (48) hide show
  1. data/.document +5 -0
  2. data/.gitignore +18 -0
  3. data/COPYING +339 -0
  4. data/GIT-VERSION-GEN +40 -0
  5. data/GNUmakefile +150 -0
  6. data/LICENSE +55 -0
  7. data/README +108 -0
  8. data/Rakefile +119 -0
  9. data/bin/upr-drb +6 -0
  10. data/examples/rails_app-2.3.4/Rakefile +10 -0
  11. data/examples/rails_app-2.3.4/app/controllers/application_controller.rb +3 -0
  12. data/examples/rails_app-2.3.4/app/controllers/files_controller.rb +41 -0
  13. data/examples/rails_app-2.3.4/app/helpers/application_helper.rb +3 -0
  14. data/examples/rails_app-2.3.4/app/models/upr_status.rb +35 -0
  15. data/examples/rails_app-2.3.4/app/views/files/index.html.erb +66 -0
  16. data/examples/rails_app-2.3.4/config.ru +3 -0
  17. data/examples/rails_app-2.3.4/config/boot.rb +110 -0
  18. data/examples/rails_app-2.3.4/config/database.yml +22 -0
  19. data/examples/rails_app-2.3.4/config/environment.rb +52 -0
  20. data/examples/rails_app-2.3.4/config/environments/development.rb +17 -0
  21. data/examples/rails_app-2.3.4/config/environments/production.rb +28 -0
  22. data/examples/rails_app-2.3.4/config/environments/test.rb +28 -0
  23. data/examples/rails_app-2.3.4/config/initializers/new_rails_defaults.rb +21 -0
  24. data/examples/rails_app-2.3.4/config/routes.rb +43 -0
  25. data/examples/rails_app-2.3.4/db/.gitignore +2 -0
  26. data/examples/rails_app-2.3.4/db/migrate/19700000000000_add_upr_status.rb +14 -0
  27. data/examples/rails_app-2.3.4/db/seeds.rb +7 -0
  28. data/examples/rails_app-2.3.4/lib/tasks/upr_status.rake +8 -0
  29. data/examples/rails_app-2.3.4/public/404.html +30 -0
  30. data/examples/rails_app-2.3.4/public/422.html +30 -0
  31. data/examples/rails_app-2.3.4/public/500.html +30 -0
  32. data/examples/rails_app-2.3.4/public/favicon.ico +0 -0
  33. data/examples/rails_app-2.3.4/public/javascripts/application.js +2 -0
  34. data/examples/rails_app-2.3.4/public/javascripts/controls.js +963 -0
  35. data/examples/rails_app-2.3.4/public/javascripts/dragdrop.js +973 -0
  36. data/examples/rails_app-2.3.4/public/javascripts/effects.js +1128 -0
  37. data/examples/rails_app-2.3.4/public/javascripts/prototype.js +4320 -0
  38. data/examples/rails_app-2.3.4/public/javascripts/upr.js +119 -0
  39. data/examples/rails_app-2.3.4/public/robots.txt +5 -0
  40. data/examples/rails_app-2.3.4/rainbows_config.rb +13 -0
  41. data/examples/rails_app-2.3.4/test/test_helper.rb +38 -0
  42. data/lib/upr.rb +35 -0
  43. data/lib/upr/input_wrapper.rb +110 -0
  44. data/lib/upr/monitor.rb +41 -0
  45. data/local.mk.sample +30 -0
  46. data/setup.rb +1586 -0
  47. data/upr.gemspec +40 -0
  48. metadata +127 -0
data/LICENSE ADDED
@@ -0,0 +1,55 @@
1
+ Upload Progress for Rack (upr) is copyrighted Free Software by all
2
+ contributors, see the logs in revision control for all of them. You can
3
+ redistribute it and/or modify it under either the terms of the
4
+ {GPL2}[http://www.gnu.org/licenses/gpl-2.0.txt] (see link:COPYING) or
5
+ the conditions below:
6
+
7
+ 1. You may make and give away verbatim copies of the source form of the
8
+ software without restriction, provided that you duplicate all of the
9
+ original copyright notices and associated disclaimers.
10
+
11
+ 2. You may modify your copy of the software in any way, provided that
12
+ you do at least ONE of the following:
13
+
14
+ a) place your modifications in the Public Domain or otherwise make them
15
+ Freely Available, such as by posting said modifications to Usenet or an
16
+ equivalent medium, or by allowing the author to include your
17
+ modifications in the software.
18
+
19
+ b) use the modified software only within your corporation or
20
+ organization.
21
+
22
+ c) rename any non-standard executables so the names do not conflict with
23
+ standard executables, which must also be provided.
24
+
25
+ d) make other distribution arrangements with the author.
26
+
27
+ 3. You may distribute the software in object code or executable
28
+ form, provided that you do at least ONE of the following:
29
+
30
+ a) distribute the executables and library files of the software,
31
+ together with instructions (in the manual page or equivalent) on where
32
+ to get the original distribution.
33
+
34
+ b) accompany the distribution with the machine-readable source of the
35
+ software.
36
+
37
+ c) give non-standard executables non-standard names, with
38
+ instructions on where to get the original software distribution.
39
+
40
+ d) make other distribution arrangements with the author.
41
+
42
+ 4. You may modify and include the part of the software into any other
43
+ software (possibly commercial). But some files in the distribution
44
+ are not written by the author, so that they are not under this terms.
45
+
46
+ 5. The scripts and library files supplied as input to or produced as
47
+ output from the software do not automatically fall under the
48
+ copyright of the software, but belong to whomever generated them,
49
+ and may be sold commercially, and may be aggregated with this
50
+ software.
51
+
52
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
53
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
54
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
55
+ PURPOSE.
data/README ADDED
@@ -0,0 +1,108 @@
1
+ = upr - Upload Progress for Rack
2
+
3
+ upr is Rack middleware that allows browser-side upload progress
4
+ monitoring. It is based on the "mongrel_upload_progress" module, but
5
+ allows any Moneta-backing store in additon to DRb. There is also a
6
+ packaged example for using an ActiveRecord model for Rails.
7
+
8
+ == Demo
9
+
10
+ You can see upr it in action at http://upr-demo.bogomips.org/
11
+ It will report the size and SHA1 of the file you've uploaded.
12
+ Much of the demo was stolen from mongrel_upload_progress.
13
+
14
+ == Web Server Compatibility
15
+
16
+ While upr is completely Rack::Lint-compatible, upr is only compatible
17
+ with Rack web servers that support a streaming "rack.input". Currently
18
+ this is limited to {Rainbows!}[http://rainbows.rubyforge.org/] with a
19
+ handful of concurrency models:
20
+
21
+ * ThreadSpawn
22
+ * ThreadPool
23
+ * Revactor*
24
+
25
+ For use with Revactor, the use of network-based Moneta stores or DRb is
26
+ only advised if those stores are using Revactor-aware sockets.
27
+
28
+ == JavaScript/HTML Compatibility
29
+
30
+ The current developer does not react well with GUIs. Thus all (R)HTML
31
+ and Prototype JavaScript code was stolen from mongrel_upload_progress.
32
+
33
+ Contributions to add compatibility for more modern things like JQuery
34
+ and HTML5 are very welcome.
35
+
36
+
37
+ == Backend Compatibility
38
+
39
+ We depend on {Moneta}[http://github.com/wycats/moneta], which allows the
40
+ use of a multitude of key-value stores. We also provide a
41
+ DRb+Moneta::Memory server to ease transitions from
42
+ mongrel_upload_progress.
43
+
44
+ Additionally, there is an example for using Rails ActiveRecord as a
45
+ backend storage mechanism. Cookie-based upload tracking may eventually
46
+ be used, too (contributions very welcome).
47
+
48
+ == Proxy Compatibility
49
+
50
+ No proxy is required when used with Rainbows!
51
+
52
+ The only incompatible HTTP proxy we know of is nginx. nginx will buffer
53
+ large requests to the filesystem before sending them to the backend.
54
+ nginx has its own 3rd-party module for
55
+ {upload progress}[http://wiki.nginx.org/NginxHttpUploadProgressModule]
56
+ and may be used instead of upr.
57
+
58
+ Most other HTTP-aware and all TCP-only proxies should be compatible.
59
+ Disabling Nagle's algorithm in both the Rack web server and proxy is
60
+ advised for lower latency, especially with stunnel.
61
+
62
+ == Unicorn Compatibility
63
+
64
+ While {Unicorn}[http://unicorn.bogomips.org/] provides the streaming
65
+ "rack.input" for Rainbows!, using Unicorn with upr is generally NOT
66
+ recommended. Unicorn only supports fast clients and progress reporting
67
+ is unnecessary unless clients are uploading files that are hundreds of
68
+ megabyte in size or larger.
69
+
70
+ == Getting Started
71
+
72
+ gem install upr
73
+
74
+ For Rails, look at the Rails application
75
+ {example}[http://git.bogomips.org/cgit/upr.git/tree/examples/rails_app-2.3.4]
76
+ and RDoc. More documentation is on the way.
77
+
78
+ == Disclaimer
79
+
80
+ There is NO WARRANTY whatsoever if anything goes wrong, but let us know
81
+ and we'll try our best to fix it.
82
+
83
+ == License
84
+
85
+ upr is copyright 2009 by all contributors (see logs in git). It is
86
+ based on mongrel_upload_progress and carries the same license (Ruby +
87
+ GPL2). See the included LICENSE file for details.
88
+
89
+ upr is 100% Free Software. We will never support the proliferation of
90
+ non-Free browsers or plugins.
91
+
92
+ == Contact
93
+
94
+ All feedback (bug reports, user/development dicussion, patches, pull
95
+ requests) go to the mailing list/newsgroup. Patches must be sent inline
96
+ (git format-patch -M + git send-email). No top posting.
97
+
98
+ To subscribe or post to the mailing list, just send an email to
99
+ upr@librelist.com and follow the instructions in the automated reply.
100
+
101
+ * email: mailto:upr@librelist.com
102
+ * git: git://git.bogomips.org/upr.git
103
+ * cgit: http://git.bogomips.org/cgit/upr.git
104
+
105
+ We will adhere to mostly the same conventions for patch submissions as
106
+ git itself. See the Documentation/SubmittingPatches document
107
+ distributed with git on on patch submission guidelines to follow. Just
108
+ don't email the git mailing list with upr patches :)
data/Rakefile ADDED
@@ -0,0 +1,119 @@
1
+ # -*- encoding: binary -*-
2
+
3
+ # most tasks are in the GNUmakefile which offers better parallelism
4
+
5
+ def tags
6
+ timefmt = '%Y-%m-%dT%H:%M:%SZ'
7
+ @tags ||= `git tag -l`.split(/\n/).map do |tag|
8
+ if %r{\Av[\d\.]+\z} =~ tag
9
+ header, subject, body = `git cat-file tag #{tag}`.split(/\n\n/, 3)
10
+ header = header.split(/\n/)
11
+ tagger = header.grep(/\Atagger /).first
12
+ body ||= "initial"
13
+ {
14
+ :time => Time.at(tagger.split(/ /)[-2].to_i).utc.strftime(timefmt),
15
+ :tagger_name => %r{^tagger ([^<]+)}.match(tagger)[1].strip,
16
+ :tagger_email => %r{<([^>]+)>}.match(tagger)[1].strip,
17
+ :id => `git rev-parse refs/tags/#{tag}`.chomp!,
18
+ :tag => tag,
19
+ :subject => subject,
20
+ :body => body,
21
+ }
22
+ end
23
+ end.compact.sort { |a,b| b[:time] <=> a[:time] }
24
+ end
25
+
26
+ cgit_url = "http://git.bogomips.org/cgit/upr.git"
27
+
28
+ desc 'prints news as an Atom feed'
29
+ task :news_atom do
30
+ require 'nokogiri'
31
+ new_tags = tags[0,10]
32
+ puts(Nokogiri::XML::Builder.new do
33
+ feed :xmlns => "http://www.w3.org/2005/Atom" do
34
+ id! "http://upr.bogomips.org/NEWS.atom.xml"
35
+ title "upr news"
36
+ subtitle "Upload Progress for Rack"
37
+ link! :rel => 'alternate', :type => 'text/html',
38
+ :href => 'http://upr.bogomips.org/NEWS.html'
39
+ updated(new_tags.empty? ? "1970-01-01T00:00:00Z" : new_tags.first[:time])
40
+ new_tags.each do |tag|
41
+ entry do
42
+ title tag[:subject]
43
+ updated tag[:time]
44
+ published tag[:time]
45
+ author {
46
+ name tag[:tagger_name]
47
+ email tag[:tagger_email]
48
+ }
49
+ url = "#{cgit_url}/tag/?id=#{tag[:tag]}"
50
+ link! :rel => "alternate", :type => "text/html", :href =>url
51
+ id! url
52
+ content({:type => 'text'}, tag[:body])
53
+ end
54
+ end
55
+ end
56
+ end.to_xml)
57
+ end
58
+
59
+ desc 'prints RDoc-formatted news'
60
+ task :news_rdoc do
61
+ tags.each do |tag|
62
+ time = tag[:time].tr!('T', ' ').gsub!(/:\d\dZ/, ' UTC')
63
+ puts "=== #{tag[:tag].sub(/^v/, '')} / #{time}"
64
+ puts ""
65
+
66
+ body = tag[:body]
67
+ puts tag[:body].gsub(/^/sm, " ").gsub(/[ \t]+$/sm, "")
68
+ puts ""
69
+ end
70
+ end
71
+
72
+ desc "print release changelog for Rubyforge"
73
+ task :release_changes do
74
+ version = ENV['VERSION'] or abort "VERSION= needed"
75
+ version = "v#{version}"
76
+ vtags = tags.map { |tag| tag[:tag] =~ /\Av/ and tag[:tag] }.sort
77
+ prev = vtags[vtags.index(version) - 1]
78
+ if prev
79
+ system('git', 'diff', '--stat', prev, version) or abort $?
80
+ puts ""
81
+ system('git', 'log', "#{prev}..#{version}") or abort $?
82
+ else
83
+ system('git', 'log', version) or abort $?
84
+ end
85
+ end
86
+
87
+ desc "print release notes for Rubyforge"
88
+ task :release_notes do
89
+ require 'rubygems'
90
+
91
+ git_url = ENV['GIT_URL'] || 'git://git.bogomips.org/upr.git'
92
+
93
+ spec = Gem::Specification.load('upr.gemspec')
94
+ puts spec.description.strip
95
+ puts ""
96
+ puts "* #{spec.homepage}"
97
+ puts "* #{spec.email}"
98
+ puts "* #{git_url}"
99
+
100
+ _, _, body = `git cat-file tag v#{spec.version}`.split(/\n\n/, 3)
101
+ print "\nChanges:\n\n"
102
+ puts body
103
+ end
104
+
105
+ desc "read news article from STDIN and post to rubyforge"
106
+ task :publish_news do
107
+ require 'rubyforge'
108
+ IO.select([STDIN], nil, nil, 1) or abort "E: news must be read from stdin"
109
+ msg = STDIN.readlines
110
+ subject = msg.shift
111
+ blank = msg.shift
112
+ blank == "\n" or abort "no newline after subject!"
113
+ subject.strip!
114
+ body = msg.join("").strip!
115
+
116
+ rf = RubyForge.new.configure
117
+ rf.login
118
+ rf.post_news('rainbows', subject, body)
119
+ end
data/bin/upr-drb ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'drb'
3
+ require 'upr'
4
+ url = ARGV.shift or abort "#$0 URL\n e.g.: #$0 druby://0.0.0.0:2999"
5
+ DRb.start_service(url, Upr::Monitor.new)
6
+ DRb.thread.join
@@ -0,0 +1,10 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require(File.join(File.dirname(__FILE__), 'config', 'boot'))
5
+
6
+ require 'rake'
7
+ require 'rake/testtask'
8
+ require 'rake/rdoctask'
9
+
10
+ require 'tasks/rails'
@@ -0,0 +1,3 @@
1
+ class ApplicationController < ActionController::Base
2
+ helper :all # include all helpers, all the time
3
+ end
@@ -0,0 +1,41 @@
1
+ require 'digest/sha1'
2
+
3
+ class FilesController < ApplicationController
4
+ defined?($upr) or before_filter do
5
+ # grab the backend in case we forget to set it (or if we're using DRb)
6
+ defined?($upr) or ObjectSpace.each_object(Upr::InputWrapper) do |x|
7
+ $upr ||= x.backend
8
+ end
9
+ end
10
+
11
+ def index
12
+ end
13
+
14
+ def status
15
+ tmp = $upr.read(params[:upload_id]).inspect
16
+ render :text => "#{Rack::Utils.escape_html(tmp)}\n"
17
+ end
18
+
19
+ def progress
20
+ render :update do |page|
21
+ status = $upr.read(params[:upload_id]) and
22
+ page.upload_progress.update(status.length, status.seen)
23
+ end
24
+ end
25
+
26
+ def upload
27
+ file = params[:data]
28
+ digest = Digest::SHA1.new
29
+ if buf = file.read(16384)
30
+ begin
31
+ digest.update(buf)
32
+ end while file.read(16384, buf)
33
+ end
34
+ size = file.stat.size
35
+ File.unlink(file.path)
36
+ render :text => "sha1: #{digest.hexdigest}<br />" \
37
+ "size: #{size}<br />" \
38
+ '<script type="text/javascript">' \
39
+ 'window.parent.UploadProgress.finish();</script>'
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ # Methods added to this helper will be available to all templates in the application.
2
+ module ApplicationHelper
3
+ end
@@ -0,0 +1,35 @@
1
+ class UprStatus < ActiveRecord::Base
2
+ cattr_accessor :gc_cutoff
3
+ @@gc_cutoff = 10
4
+
5
+ class << self
6
+ def read(upid)
7
+ if rv = find_by_upid(upid)
8
+ rv.time = Time.now.to_i
9
+ rv.save
10
+ rv
11
+ end
12
+ end
13
+
14
+ def start(upid, length)
15
+ # this must be a find_or_create_by since some users have twitchy
16
+ # fingers and hit the upload button prematurely
17
+ find_or_create_by_upid(upid) do |x|
18
+ x.length = length
19
+ x.time = Time.now.to_i
20
+ x.seen = 0
21
+ end
22
+ end
23
+
24
+ def incr(upid, nr)
25
+ update_all("seen = seen + #{nr.to_i}, time = #{Time.now.to_i}",
26
+ { :upid => upid })
27
+ end
28
+
29
+ def gc
30
+ cutoff = Time.now.to_i - @@gc_cutoff
31
+ delete_all "time < #{cutoff}"
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,66 @@
1
+ <html>
2
+ <head>
3
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
4
+ <title>upr test, http://upr.bogomips.org/</title>
5
+ <%= javascript_include_tag :all %>
6
+ <style type="text/css">
7
+ #progress-bar {
8
+ width:500px;
9
+ height:25px;
10
+ margin:15px;
11
+ border:solid 1px #000;
12
+ position:relative;
13
+ }
14
+
15
+ #progress-bar #status-bar {
16
+ display:block;
17
+ height:25px;
18
+ width:0;
19
+ background-color:#00f;
20
+ border-right:solid 1px #000;
21
+ position:absolute;
22
+ top:0; left:0;
23
+ }
24
+
25
+ #progress-bar #status-text {
26
+ display:block;
27
+ padding: 0 15px;
28
+ line-height:25px;
29
+ position:absolute;
30
+ top:0; left:0;
31
+ }
32
+ </style>
33
+ </head>
34
+ <body>
35
+ <%
36
+ upid = "#{Time.now.to_i}.#{rand}"
37
+ act = { :action => 'upload', :upload_id => upid }
38
+ opt = {
39
+ :multipart => true,
40
+ :target => 'upload',
41
+ :onsubmit => "UploadProgress.monitor('#{escape_javascript(upid)}')"
42
+ }
43
+ -%>
44
+ <p>
45
+ This is a demo of <a href="http://upr.bogomips.org/">upr</a> in action.
46
+ Much of this (including all JS) was stolen from the mongrel_upload_progress
47
+ examples.
48
+ </p>
49
+ <p><%= link_to upid, :action => 'status', :upload_id => upid %></p>
50
+ <% form_tag(act, opt) do %>
51
+ <div id="file-fields">
52
+ <p><%= file_field_tag :data %></p>
53
+ </div>
54
+ <p><%= link_to_function 'Add File Field', 'UploadProgress.FileField.add()' %>
55
+ </p>
56
+ <p><%= submit_tag :Upload %></p>
57
+ <% end %>
58
+
59
+ <div id="results"></div>
60
+ <div id="progress-bar"></div>
61
+
62
+ <p>The size and SHA1 of the file you uploaded should appear here</p>
63
+ <iframe id="upload" name="upload" src="about:blank"></iframe>
64
+
65
+ </body>
66
+ </html>