upr 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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>