nyoibo 0.0.1
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/.gitignore +4 -0
- data/Gemfile +6 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +11 -0
- data/app/helpers/nyoibo_helper.rb +15 -0
- data/lib/generators/nyoibo/install_generator.rb +20 -0
- data/lib/generators/nyoibo/templates/nyoibo.js.coffee +65 -0
- data/lib/generators/nyoibo/templates/nyoibo.rb.erb +4 -0
- data/lib/generators/nyoibo/templates/nyoibo_en.yml +3 -0
- data/lib/nyoibo.rb +17 -0
- data/lib/nyoibo/callback.rb +28 -0
- data/lib/nyoibo/configure.rb +19 -0
- data/lib/nyoibo/daemon.rb +58 -0
- data/lib/nyoibo/rails.rb +4 -0
- data/lib/nyoibo/railtie.rb +8 -0
- data/lib/nyoibo/version.rb +3 -0
- data/nyoibo.gemspec +26 -0
- data/test/fixtures/test.jpg +0 -0
- data/test/test_helper.rb +19 -0
- data/test/unit/callback_test.rb +17 -0
- data/test/unit/configure_test.rb +15 -0
- data/test/unit/daemon_test.rb +60 -0
- data/vendor/html5jp/progress.js +929 -0
- data/vendor/web-socket-js/README.md +157 -0
- data/vendor/web-socket-js/WebSocketMain.swf +0 -0
- data/vendor/web-socket-js/swfobject.js +4 -0
- data/vendor/web-socket-js/web_socket.js +361 -0
- metadata +124 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem "shoulda-matchers", :git => "https://github.com/thoughtbot/shoulda-matchers.git"
|
4
|
+
gem "shoulda-context", :git => "https://github.com/thoughtbot/shoulda-context.git"
|
5
|
+
gem "turn", :git => "https://github.com/yalab/turn.git"
|
6
|
+
gemspec
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2011 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
require 'rake/testtask'
|
4
|
+
desc "Default Task"
|
5
|
+
Rake::TestTask.new do |t|
|
6
|
+
files = FileList['test/test_helper.rb', 'test/**/*test.rb']
|
7
|
+
t.test_files = files
|
8
|
+
t.libs << "test"
|
9
|
+
# t.warning = true
|
10
|
+
end
|
11
|
+
task :default => :test
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module NyoiboHelper
|
2
|
+
def ws_form_for(model, options={}, &block)
|
3
|
+
options[:html] ||= {}
|
4
|
+
options[:html][:id] ||= 'ws-form'
|
5
|
+
output = ''
|
6
|
+
output << javascript_tag(<<EOS)
|
7
|
+
WEB_SOCKET_DEBUG = true;
|
8
|
+
WEB_SOCKET_SWF_LOCATION = '/WebSocketMain.swf';
|
9
|
+
var nyoibo = #{I18n.t('nyoibo').to_json};
|
10
|
+
EOS
|
11
|
+
output << form_for(model, options, &block)
|
12
|
+
output << content_tag(:div, '', :id => 'ws-progress')
|
13
|
+
output.html_safe
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rails'
|
2
|
+
require 'rails/generators'
|
3
|
+
module Nyoibo
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path("../templates", __FILE__)
|
7
|
+
|
8
|
+
desc "Creates a Nyoibo initializer and copy javascript and locale files to your application."
|
9
|
+
def copy_initializer
|
10
|
+
template "nyoibo.rb.erb", "config/initializers/nyoibo.rb"
|
11
|
+
template "nyoibo_en.yml", "config/locales/nyoibo_en.yml"
|
12
|
+
template "nyoibo.js.coffee", "app/assets/javascripts/nyoibo.js.coffee"
|
13
|
+
template "../../../../vendor/html5jp/progress.js", "app/assets/javascripts/progress.js"
|
14
|
+
template "../../../../vendor/web-socket-js/web_socket.js", "app/assets/javascripts/web_socket.js"
|
15
|
+
template "../../../../vendor/web-socket-js/swfobject.js", "app/assets/javascripts/swfobject.js"
|
16
|
+
template "../../../../vendor/web-socket-js/WebSocketMain.swf", "public/WebSocketMain.swf"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
jQuery ($)->
|
2
|
+
progress = new html5jp.progress("ws-progress")
|
3
|
+
progress.draw()
|
4
|
+
|
5
|
+
form = $('#ws-form')
|
6
|
+
progress_bar = $("#ws-progress")
|
7
|
+
|
8
|
+
fire = (obj, name, data) ->
|
9
|
+
event = $.Event(name)
|
10
|
+
obj.trigger(event, data)
|
11
|
+
return event.result != false
|
12
|
+
|
13
|
+
form.bind 'ws:upload', (event) ->
|
14
|
+
file = form.find('input[type=file]').get(0).files[0]
|
15
|
+
try
|
16
|
+
max_length = file.size
|
17
|
+
catch e
|
18
|
+
alert nyoibo.file_not_found
|
19
|
+
return
|
20
|
+
if max_length == 0
|
21
|
+
alert nyoibo.file_not_found
|
22
|
+
return
|
23
|
+
chunk = 102400
|
24
|
+
start = 0
|
25
|
+
ws = new WebSocket("ws://localhost:3030/")
|
26
|
+
|
27
|
+
fire(form, 'ws:before_upload')
|
28
|
+
ws.onclose = ->
|
29
|
+
progress.set_val(100)
|
30
|
+
fire(form, 'ws:after_upload')
|
31
|
+
progress.reset()
|
32
|
+
ws = null
|
33
|
+
|
34
|
+
ws.onmessage = (evt) ->
|
35
|
+
switch evt.data
|
36
|
+
when 'OK Ready'
|
37
|
+
params = {filename: file.name, comment: $('#post_comment').val(), size: max_length, session_string: $('#session_string').val()}
|
38
|
+
ws.send("JSON: " + JSON.stringify(params))
|
39
|
+
when 'OK Bye'
|
40
|
+
ws.close()
|
41
|
+
when 'EMPTY'
|
42
|
+
ws.send("QUIT")
|
43
|
+
when 'NEXT'
|
44
|
+
val = Math.floor(start / max_length * 100)
|
45
|
+
progress.set_val(val)
|
46
|
+
stop = start + chunk - 1
|
47
|
+
if stop >= max_length
|
48
|
+
stop = max_length
|
49
|
+
|
50
|
+
blob = if typeof(file.mozSlice) == "function"
|
51
|
+
file.mozSlice(start, stop)
|
52
|
+
else if typeof(file.webkitSlice) == "function"
|
53
|
+
file.webkitSlice(start, stop)
|
54
|
+
start = stop
|
55
|
+
reader = new FileReader()
|
56
|
+
reader.onloadend = (e) ->
|
57
|
+
ws.send(e.target.result)
|
58
|
+
|
59
|
+
setTimeout ->
|
60
|
+
reader.readAsBinaryString(blob)
|
61
|
+
, 300
|
62
|
+
|
63
|
+
$('#ws-form input[type=submit]').click ->
|
64
|
+
fire(form, 'ws:upload') if fire(form, 'ws:prepare_upload')
|
65
|
+
return false
|
data/lib/nyoibo.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'em-websocket'
|
2
|
+
require 'json'
|
3
|
+
require 'nyoibo/configure'
|
4
|
+
require 'nyoibo/daemon'
|
5
|
+
require 'nyoibo/callback'
|
6
|
+
|
7
|
+
module Nyoibo
|
8
|
+
extend Configure
|
9
|
+
extend Daemon
|
10
|
+
extend Callback::Runner
|
11
|
+
end
|
12
|
+
|
13
|
+
if defined?(Rails)
|
14
|
+
require 'rails'
|
15
|
+
require 'nyoibo/rails'
|
16
|
+
require 'nyoibo/railtie'
|
17
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Nyoibo
|
2
|
+
module Callback
|
3
|
+
def self.callbacks
|
4
|
+
@callbacks ||= {}
|
5
|
+
end
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethod
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethod
|
11
|
+
def uploaded(path, &block)
|
12
|
+
if ENV["NYOIBO_ENV"] == "production" && Nyoibo::Callback.callbacks[path]
|
13
|
+
raise "Already defined '#{path}' updated callback."
|
14
|
+
end
|
15
|
+
Nyoibo::Callback.callbacks[path] = block
|
16
|
+
|
17
|
+
Process.kill(:TERM, Nyoibo.pid) && Nyoibo.run if ENV["NYOIBO_ENV"] == "development"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Runner
|
22
|
+
def run_callback(path="/", *args)
|
23
|
+
block = Nyoibo::Callback.callbacks[path]
|
24
|
+
block.call(*args)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Nyoibo
|
2
|
+
module Configure
|
3
|
+
attr_accessor :config
|
4
|
+
def configure(&block)
|
5
|
+
@config = Config.new
|
6
|
+
@config.instance_exec(&block)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Config
|
11
|
+
[:host, :port].each do |method|
|
12
|
+
module_eval <<-EOS, __FILE__, __LINE__
|
13
|
+
def #{method}(value = nil)
|
14
|
+
(value) ? (@#{method} = value) : @#{method}
|
15
|
+
end
|
16
|
+
EOS
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Nyoibo
|
2
|
+
module Daemon
|
3
|
+
attr_reader :pid
|
4
|
+
CMD_QUIT = /^QUIT$/
|
5
|
+
CMD_JSON = /^JSON: /
|
6
|
+
TYPE_BASE64 = %r|^data:application/octet-stream;base64,|
|
7
|
+
def run
|
8
|
+
return if defined?(IRB)
|
9
|
+
daemon = lambda{
|
10
|
+
EventMachine::WebSocket.start(:host => config.host, :port => config.port) do |ws|
|
11
|
+
ws.onopen{
|
12
|
+
ws.send "OK Ready"
|
13
|
+
}
|
14
|
+
ws.onclose{
|
15
|
+
ws.send "OK Bye"
|
16
|
+
}
|
17
|
+
ws.onmessage{|msg|
|
18
|
+
@binary ||= ""
|
19
|
+
@binary_type ||= 'binary'
|
20
|
+
case msg
|
21
|
+
when CMD_QUIT
|
22
|
+
if @binary_type == 'base64'
|
23
|
+
@binary = Base64.decode64(@binary)
|
24
|
+
elsif @binary.encoding == Encoding::UTF_8
|
25
|
+
@binary = @binary.unpack('U*').pack('c*')
|
26
|
+
end
|
27
|
+
Nyoibo.run_callback(ws.request["path"], @json, @binary)
|
28
|
+
ws.close_connection
|
29
|
+
when CMD_JSON
|
30
|
+
msg.gsub!(CMD_JSON, '')
|
31
|
+
@json = JSON.parse(msg)
|
32
|
+
@json['size'] = @json['size'].to_i
|
33
|
+
ws.send("NEXT")
|
34
|
+
else
|
35
|
+
|
36
|
+
if msg =~ TYPE_BASE64
|
37
|
+
msg.gsub!(TYPE_BASE64, '')
|
38
|
+
@binary_type = 'base64'
|
39
|
+
end
|
40
|
+
|
41
|
+
if msg.length > 0
|
42
|
+
@binary << msg
|
43
|
+
ws.send("NEXT")
|
44
|
+
else
|
45
|
+
ws.send("EMPTY")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
}
|
49
|
+
end
|
50
|
+
}
|
51
|
+
if ENV["NYOIBO_ENV"] == "test"
|
52
|
+
daemon.call
|
53
|
+
else
|
54
|
+
@pid = Process.fork &daemon
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/nyoibo/rails.rb
ADDED
data/nyoibo.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "nyoibo/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "nyoibo"
|
7
|
+
s.version = Nyoibo::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["yalab"]
|
10
|
+
s.email = ["rudeboyjet@gmail.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Websocket uploader with progressbar.}
|
13
|
+
s.description = %q{}
|
14
|
+
s.license = 'MIT'
|
15
|
+
|
16
|
+
s.rubyforge_project = "nyoibo"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
s.add_dependency("em-websocket", "~>0.3.0")
|
23
|
+
s.add_dependency("json", "~>1.5.3")
|
24
|
+
s.add_development_dependency('em-http-request', '~> 0.2.6')
|
25
|
+
s.add_development_dependency('railties')
|
26
|
+
end
|
Binary file
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'socket'
|
3
|
+
require 'bundler'
|
4
|
+
ENV['BUNDLE_GEMFILE'] = File.expand_path("../../Gemfile", __FILE__)
|
5
|
+
require 'bundler/setup'
|
6
|
+
require 'shoulda/context'
|
7
|
+
require 'em-http'
|
8
|
+
require 'turn'
|
9
|
+
|
10
|
+
Dir.glob(File.expand_path("../../lib/**/*.rb", __FILE__)).each {|f| require f }
|
11
|
+
|
12
|
+
ENV["NYOIBO_ENV"] = "test"
|
13
|
+
|
14
|
+
Test::Unit::TestCase.module_eval do
|
15
|
+
def failed
|
16
|
+
EventMachine.stop
|
17
|
+
fail
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
class Nyoibo::CallbackTest < Test::Unit::TestCase
|
3
|
+
class TestApp
|
4
|
+
include Nyoibo::Callback
|
5
|
+
uploaded "/" do
|
6
|
+
"uploaded!"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
context "Run callback" do
|
10
|
+
setup do
|
11
|
+
@response = Nyoibo.run_callback("/")
|
12
|
+
end
|
13
|
+
should "fetch response" do
|
14
|
+
assert_equal "uploaded!", @response
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
class Nyoibo::ConfigureTest < Test::Unit::TestCase
|
3
|
+
context ".configure" do
|
4
|
+
setup do
|
5
|
+
Nyoibo.configure do
|
6
|
+
host 'localhost'
|
7
|
+
port 3030
|
8
|
+
end
|
9
|
+
end
|
10
|
+
should "reflect config" do
|
11
|
+
assert_equal 'localhost', Nyoibo.config.host
|
12
|
+
assert_equal 3030, Nyoibo.config.port
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
class Nyoibo::DaemonTest < Test::Unit::TestCase
|
3
|
+
class TestApp < Test::Unit::TestCase
|
4
|
+
include Nyoibo::Callback
|
5
|
+
uploaded "/" do |json, binary|
|
6
|
+
File.open("/tmp/test.jpg", "w:binary"){|f|
|
7
|
+
f.write(binary)
|
8
|
+
}
|
9
|
+
raise "finame is not 'test.jpg'" if json["filename"] != "test.jpg"
|
10
|
+
raise "Binary size is not '3137' byte" if binary.length != 3137
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "run" do
|
15
|
+
setup do
|
16
|
+
@file = File.new(File.expand_path("../../fixtures/test.jpg", __FILE__), "rb")
|
17
|
+
Nyoibo.configure do
|
18
|
+
host "localhost"
|
19
|
+
port 3030
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
should "listen port" do
|
24
|
+
EM.run do
|
25
|
+
EventMachine.add_timer(0.1) do
|
26
|
+
http = EventMachine::HttpRequest.new('ws://localhost:3030/').get(:timeout => 0)
|
27
|
+
http.errback { failed }
|
28
|
+
@start = 0
|
29
|
+
@sendsize = 1024
|
30
|
+
http.stream{|msg|
|
31
|
+
case msg
|
32
|
+
when "OK Ready"
|
33
|
+
http.send("JSON: " + {:filename => File.basename(@file.path), :size => @file.size}.to_json)
|
34
|
+
when "NEXT"
|
35
|
+
@end = @start + @sendsize
|
36
|
+
@encoded ||= Base64.encode64(@file.read)
|
37
|
+
|
38
|
+
@end = @encoded.size - 1 if @end >= @encoded.size
|
39
|
+
if @start == @encoded.size
|
40
|
+
http.send("QUIT")
|
41
|
+
else
|
42
|
+
chunk = @encoded.slice(@start..@end)
|
43
|
+
if @start == 0
|
44
|
+
chunk = "data:application/octet-stream;base64," + chunk
|
45
|
+
end
|
46
|
+
|
47
|
+
http.send(chunk)
|
48
|
+
end
|
49
|
+
@start = @end + 1
|
50
|
+
end
|
51
|
+
}
|
52
|
+
http.disconnect{
|
53
|
+
EventMachine.stop
|
54
|
+
}
|
55
|
+
end
|
56
|
+
Nyoibo.run
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|