opal-drb 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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/README.md +4 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/example/Gemfile +11 -0
- data/example/Gemfile.lock +74 -0
- data/example/app/application.rb +14 -0
- data/example/assets/css/application.scss +0 -0
- data/example/bin/console +19 -0
- data/example/config.ru +28 -0
- data/example/server.rb +30 -0
- data/example/views/index.erb +9 -0
- data/lib/opal/drb.rb +15 -0
- data/lib/opal/drb/drb.rb +109 -0
- data/lib/opal/drb/drb_conn.rb +63 -0
- data/lib/opal/drb/drb_message.rb +111 -0
- data/lib/opal/drb/drb_object.rb +103 -0
- data/lib/opal/drb/drb_protocol.rb +43 -0
- data/lib/opal/drb/version.rb +5 -0
- data/lib/opal/drb/websocket.rb +134 -0
- data/opal-drb.gemspec +26 -0
- data/proc.rb +2 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 59cfd003694ff3b5cea5b36890115827c3e5021e
|
4
|
+
data.tar.gz: f1b1ee0b120661e1d119191604d13d6cbc99563e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6d56f0b90def3126209f8d0dbd88bf60d45d0a0ab535787ad26e4b995f9c8ca373ef37261feb6bdb3034837a3a331cbba3d74f044d18aa41956a1c35b6f03d57
|
7
|
+
data.tar.gz: d6a81db3890e07923af570a169103fd82aa83461def8f972af5fcbabe22e95e2b78b3574e3b19278e611038c794d48dc488d3b106d18df672507cb782dd2aab2
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "opal/drb"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/example/Gemfile
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git://github.com/opal/opal-sprockets.git
|
3
|
+
revision: a063dffd884b495ed0c54b4c3b0b1cacc4abb322
|
4
|
+
specs:
|
5
|
+
opal-sprockets (0.4.1.0.11.0.rc1.3.1.beta2)
|
6
|
+
opal (~> 0.11.0.rc1)
|
7
|
+
sprockets (~> 3.1)
|
8
|
+
tilt (>= 1.4)
|
9
|
+
|
10
|
+
GIT
|
11
|
+
remote: git://github.com/youchan/opal.git
|
12
|
+
revision: 79998074a820fd1e651bce1e8661245949648285
|
13
|
+
branch: marshal-dump-bignum
|
14
|
+
specs:
|
15
|
+
opal (0.11.0.rc1)
|
16
|
+
ast (>= 2.3.0)
|
17
|
+
hike (~> 1.2)
|
18
|
+
parser (= 2.3.3.1)
|
19
|
+
sourcemap (~> 0.1.0)
|
20
|
+
|
21
|
+
GEM
|
22
|
+
remote: https://rubygems.org/
|
23
|
+
specs:
|
24
|
+
ast (2.3.0)
|
25
|
+
backports (3.8.0)
|
26
|
+
concurrent-ruby (1.0.5)
|
27
|
+
daemons (1.2.4)
|
28
|
+
eventmachine (1.2.3)
|
29
|
+
hike (1.2.3)
|
30
|
+
multi_json (1.12.1)
|
31
|
+
mustermann (1.0.0)
|
32
|
+
parser (2.3.3.1)
|
33
|
+
ast (~> 2.2)
|
34
|
+
rack (2.0.3)
|
35
|
+
rack-protection (2.0.0)
|
36
|
+
rack
|
37
|
+
rake (12.0.0)
|
38
|
+
sass (3.4.24)
|
39
|
+
sinatra (2.0.0)
|
40
|
+
mustermann (~> 1.0)
|
41
|
+
rack (~> 2.0)
|
42
|
+
rack-protection (= 2.0.0)
|
43
|
+
tilt (~> 2.0)
|
44
|
+
sinatra-contrib (2.0.0)
|
45
|
+
backports (>= 2.0)
|
46
|
+
multi_json
|
47
|
+
mustermann (~> 1.0)
|
48
|
+
rack-protection (= 2.0.0)
|
49
|
+
sinatra (= 2.0.0)
|
50
|
+
tilt (>= 1.3, < 3)
|
51
|
+
sourcemap (0.1.1)
|
52
|
+
sprockets (3.7.1)
|
53
|
+
concurrent-ruby (~> 1.0)
|
54
|
+
rack (> 1, < 3)
|
55
|
+
thin (1.7.1)
|
56
|
+
daemons (~> 1.0, >= 1.0.9)
|
57
|
+
eventmachine (~> 1.0, >= 1.0.4)
|
58
|
+
rack (>= 1, < 3)
|
59
|
+
tilt (2.0.7)
|
60
|
+
|
61
|
+
PLATFORMS
|
62
|
+
ruby
|
63
|
+
|
64
|
+
DEPENDENCIES
|
65
|
+
opal!
|
66
|
+
opal-sprockets!
|
67
|
+
rake
|
68
|
+
sass
|
69
|
+
sinatra
|
70
|
+
sinatra-contrib
|
71
|
+
thin
|
72
|
+
|
73
|
+
BUNDLED WITH
|
74
|
+
1.14.6
|
File without changes
|
data/example/bin/console
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
|
5
|
+
require 'menilite'
|
6
|
+
require 'sinatra/activerecord'
|
7
|
+
|
8
|
+
Dir[File.expand_path('../../app/models/', __FILE__) + '/**/*.rb'].each {|file| require(file) }
|
9
|
+
Dir[File.expand_path('../../app/controllers/', __FILE__) + '/**/*.rb'].each {|file| require(file) }
|
10
|
+
|
11
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
12
|
+
# with your gem easier. You can also use a different console, if you like.
|
13
|
+
|
14
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
15
|
+
# require "pry"
|
16
|
+
# Pry.start
|
17
|
+
|
18
|
+
require "irb"
|
19
|
+
IRB.start
|
data/example/config.ru
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
Bundler.require(:default)
|
3
|
+
|
4
|
+
require_relative 'server'
|
5
|
+
|
6
|
+
app = Rack::Builder.app do
|
7
|
+
server = Server.new(host: 'localhost')
|
8
|
+
|
9
|
+
map '/' do
|
10
|
+
run server
|
11
|
+
end
|
12
|
+
|
13
|
+
map '/assets' do
|
14
|
+
run Server::OPAL.sprockets
|
15
|
+
end
|
16
|
+
|
17
|
+
map '/__OPAL_SOURCE_MAPS__' do
|
18
|
+
run Opal::SourceMapServer.new(Server::OPAL.sprockets, '/__OPAL_SOURCE_MAPS__')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Rack::Server.start({
|
23
|
+
app: app,
|
24
|
+
server: 'thin',
|
25
|
+
Host: '0.0.0.0',
|
26
|
+
Port: 9292,
|
27
|
+
signals: false,
|
28
|
+
})
|
data/example/server.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
require 'opal'
|
3
|
+
|
4
|
+
if development?
|
5
|
+
require 'sinatra/reloader'
|
6
|
+
end
|
7
|
+
|
8
|
+
class Server < Sinatra::Base
|
9
|
+
OPAL = Opal::Server.new do |server|
|
10
|
+
server.append_path 'app'
|
11
|
+
server.append_path 'assets'
|
12
|
+
server.append_path '../lib'
|
13
|
+
Opal.paths.each {|path| server.append_path path }
|
14
|
+
|
15
|
+
server.main = 'application'
|
16
|
+
end
|
17
|
+
|
18
|
+
configure do
|
19
|
+
set opal: OPAL
|
20
|
+
enable :sessions
|
21
|
+
end
|
22
|
+
|
23
|
+
get '/' do
|
24
|
+
erb :index
|
25
|
+
end
|
26
|
+
|
27
|
+
get "/favicon.ico" do
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<html lang="en">
|
2
|
+
<head>
|
3
|
+
<link rel="stylesheet" href="assets/css/application.css" />
|
4
|
+
</head>
|
5
|
+
<body>
|
6
|
+
<content/>
|
7
|
+
<%= ::Opal::Sprockets.javascript_include_tag('application', sprockets: settings.opal.sprockets, prefix: 'assets', debug: true) %>
|
8
|
+
</body>
|
9
|
+
</html>
|
data/lib/opal/drb.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module DRb
|
2
|
+
class DRbError < RuntimeError; end
|
3
|
+
class DRbConnError < DRbError; end
|
4
|
+
class DRbServerNotFound < DRbError; end
|
5
|
+
class DRbBadURI < DRbError; end
|
6
|
+
class DRbBadScheme < DRbError; end
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'opal/drb/version'
|
10
|
+
require 'opal/drb/websocket'
|
11
|
+
require 'opal/drb/drb_protocol'
|
12
|
+
require 'opal/drb/drb_conn'
|
13
|
+
require 'opal/drb/drb_object'
|
14
|
+
require 'opal/drb/drb_message'
|
15
|
+
require 'opal/drb/drb'
|
data/lib/opal/drb/drb.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'corelib/marshal'
|
2
|
+
require 'promise'
|
3
|
+
|
4
|
+
module DRb
|
5
|
+
class DRbUnknownError < DRbError
|
6
|
+
def initialize(unknown)
|
7
|
+
@unknown = unknown
|
8
|
+
super(unknown.name)
|
9
|
+
end
|
10
|
+
attr_reader :unknown
|
11
|
+
|
12
|
+
def self._load(s)
|
13
|
+
Marshal::load(s)
|
14
|
+
end
|
15
|
+
|
16
|
+
def _dump(lv)
|
17
|
+
Marshal::dump(@unknown)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class DRbRemoteError < DRbError
|
22
|
+
def initialize(error)
|
23
|
+
@reason = error.class.to_s
|
24
|
+
super("#{error.message} (#{error.class})")
|
25
|
+
set_backtrace(error.backtrace)
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :reason
|
29
|
+
end
|
30
|
+
|
31
|
+
class DRbIdConv
|
32
|
+
def to_obj(ref)
|
33
|
+
ObjectSpace._id2ref(ref)
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_id(obj)
|
37
|
+
obj.nil? ? nil : obj.__id__
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module DRbUndumped
|
42
|
+
def _dump(dummy)
|
43
|
+
raise TypeError, 'can\'t dump'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class DRbUnknown
|
48
|
+
def initialize(err, buf)
|
49
|
+
case err.to_s
|
50
|
+
when /uninitialized constant (\S+)/
|
51
|
+
@name = $1
|
52
|
+
when /undefined class\/module (\S+)/
|
53
|
+
@name = $1
|
54
|
+
else
|
55
|
+
@name = nil
|
56
|
+
end
|
57
|
+
@buf = buf
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_reader :name
|
61
|
+
attr_reader :buf
|
62
|
+
|
63
|
+
def self._load(s)
|
64
|
+
begin
|
65
|
+
Marshal::load(s)
|
66
|
+
rescue NameError, ArgumentError
|
67
|
+
DRbUnknown.new($!, s)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def _dump(lv)
|
72
|
+
@buf
|
73
|
+
end
|
74
|
+
|
75
|
+
def reload
|
76
|
+
self.class._load(@buf)
|
77
|
+
end
|
78
|
+
|
79
|
+
def exception
|
80
|
+
DRbUnknownError.new(self)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class DRbArray
|
85
|
+
def initialize(ary)
|
86
|
+
@ary = ary.collect { |obj|
|
87
|
+
if obj.kind_of? DRbUndumped
|
88
|
+
DRbObject.new(obj)
|
89
|
+
else
|
90
|
+
begin
|
91
|
+
Marshal.dump(obj)
|
92
|
+
obj
|
93
|
+
rescue
|
94
|
+
DRbObject.new(obj)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
def self._load(s)
|
101
|
+
Marshal::load(s)
|
102
|
+
end
|
103
|
+
|
104
|
+
def _dump(lv)
|
105
|
+
Marshal.dump(@ary)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module DRb
|
2
|
+
class DRbConn
|
3
|
+
POOL_SIZE = 16
|
4
|
+
@pool = []
|
5
|
+
|
6
|
+
def self.open(remote_uri)
|
7
|
+
begin
|
8
|
+
conn = nil
|
9
|
+
|
10
|
+
@pool = @pool.each_with_object([]) do |c, new_pool|
|
11
|
+
if conn.nil? and c.uri == remote_uri
|
12
|
+
conn = c if c.alive?
|
13
|
+
else
|
14
|
+
new_pool.push c
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
conn = self.new(remote_uri) unless conn
|
19
|
+
succ, result = yield(conn)
|
20
|
+
return succ, result
|
21
|
+
|
22
|
+
ensure
|
23
|
+
if conn
|
24
|
+
if succ
|
25
|
+
@pool.unshift(conn)
|
26
|
+
@pool.pop.close while @pool.size > POOL_SIZE
|
27
|
+
else
|
28
|
+
conn.close
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(remote_uri)
|
35
|
+
@uri = remote_uri
|
36
|
+
@protocol = DRbProtocol.open(remote_uri, DRb::default_config)
|
37
|
+
end
|
38
|
+
attr_reader :uri
|
39
|
+
|
40
|
+
def send_message(ref, msg_id, arg, b, &callback)
|
41
|
+
@protocol.send_request(ref, msg_id, arg, b).then do |stream|
|
42
|
+
yield @protocol.recv_reply stream
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def close
|
47
|
+
@protocol.close
|
48
|
+
@protocol = nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def alive?
|
52
|
+
return false unless @protocol
|
53
|
+
@protocol.alive?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.default_config
|
58
|
+
{
|
59
|
+
argc_limit: 256,
|
60
|
+
load_limit: 256 * 102400
|
61
|
+
}
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module DRb
|
2
|
+
class DRbMessage
|
3
|
+
def initialize(config)
|
4
|
+
@load_limit = config[:load_limit]
|
5
|
+
@argc_limit = config[:argc_limit]
|
6
|
+
end
|
7
|
+
|
8
|
+
def dump(obj, error=false)
|
9
|
+
obj = make_proxy(obj, error) if obj.kind_of? DRbUndumped
|
10
|
+
begin
|
11
|
+
str = Marshal::dump(obj)
|
12
|
+
rescue
|
13
|
+
str = Marshal::dump(make_proxy(obj, error))
|
14
|
+
end
|
15
|
+
pack_n(str.size) + str
|
16
|
+
end
|
17
|
+
|
18
|
+
def load(soc)
|
19
|
+
begin
|
20
|
+
sz = soc.read(4)
|
21
|
+
rescue
|
22
|
+
raise(DRbConnError, $!.message, $!.backtrace)
|
23
|
+
end
|
24
|
+
|
25
|
+
raise(DRbConnError, 'connection closed') if sz.nil?
|
26
|
+
raise(DRbConnError, 'premature header') if sz.size < 4
|
27
|
+
|
28
|
+
sz = unpack_n(sz)[0]
|
29
|
+
|
30
|
+
raise(DRbConnError, "too large packet #{sz}") if @load_limit < sz
|
31
|
+
begin
|
32
|
+
str = soc.read(sz)
|
33
|
+
rescue
|
34
|
+
raise(DRbConnError, $!.message, $!.backtrace)
|
35
|
+
end
|
36
|
+
|
37
|
+
raise(DRbConnError, 'connection closed') if str.nil?
|
38
|
+
raise(DRbConnError, 'premature marshal format(can\'t read)') if str.size < sz
|
39
|
+
|
40
|
+
Marshal::load(str)
|
41
|
+
end
|
42
|
+
|
43
|
+
def send_request(stream, ref, msg_id, arg, b)
|
44
|
+
ary = []
|
45
|
+
ary.push(dump(ref.__drbref))
|
46
|
+
ary.push(dump(msg_id))
|
47
|
+
ary.push(dump(arg.length))
|
48
|
+
arg.each do |e|
|
49
|
+
ary.push(dump(e))
|
50
|
+
end
|
51
|
+
ary.push(dump(b))
|
52
|
+
stream.write(ary.join(''))
|
53
|
+
rescue
|
54
|
+
raise(DRbConnError, $!.message, $!.backtrace)
|
55
|
+
end
|
56
|
+
|
57
|
+
def recv_request(stream)
|
58
|
+
ref = load(stream)
|
59
|
+
ro = DRb.to_obj(ref)
|
60
|
+
msg = load(stream)
|
61
|
+
argc = load(stream)
|
62
|
+
raise(DRbConnError, "too many arguments") if @argc_limit < argc
|
63
|
+
argv = Array.new(argc, nil)
|
64
|
+
argc.times do |n|
|
65
|
+
argv[n] = load(stream)
|
66
|
+
end
|
67
|
+
block = load(stream)
|
68
|
+
return ro, msg, argv, block
|
69
|
+
end
|
70
|
+
|
71
|
+
def send_reply(stream, succ, result)
|
72
|
+
stream.write(dump(succ) + dump(result, !succ))
|
73
|
+
rescue
|
74
|
+
raise(DRbConnError, $!.message, $!.backtrace)
|
75
|
+
end
|
76
|
+
|
77
|
+
def recv_reply(stream)
|
78
|
+
succ = load(stream)
|
79
|
+
result = load(stream)
|
80
|
+
[succ, result]
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
def make_proxy(obj, error=false)
|
85
|
+
if error
|
86
|
+
DRbRemoteError.new(obj)
|
87
|
+
else
|
88
|
+
DRbObject.new(obj)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def pack_n(n)
|
93
|
+
%x{
|
94
|
+
var s = "";
|
95
|
+
for (var i = 0; i < 4; i++) {
|
96
|
+
var b = n & 255;
|
97
|
+
s = String.fromCharCode(b) + s;
|
98
|
+
n >>= 8
|
99
|
+
}
|
100
|
+
|
101
|
+
return s;
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
def unpack_n(s)
|
106
|
+
s.bytes.each_slice(2).map(&:first).each_slice(4).map do |x|
|
107
|
+
x[0] << 24 | x[1] << 16 | x[2] << 8 | x[3]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module DRb
|
2
|
+
class DRbObject
|
3
|
+
def self._load(s)
|
4
|
+
uri, ref = Marshal.load(s)
|
5
|
+
self.new_with(uri, ref)
|
6
|
+
rescue Exception => e
|
7
|
+
`console.log(e)`
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.new_with(uri, ref)
|
11
|
+
it = self.allocate
|
12
|
+
it.instance_variable_set(:@uri, uri)
|
13
|
+
it.instance_variable_set(:@ref, ref)
|
14
|
+
it
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.new_with_uri(uri)
|
18
|
+
self.new(nil, uri)
|
19
|
+
end
|
20
|
+
|
21
|
+
def _dump(lv)
|
22
|
+
Marshal.dump([@uri, @ref])
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(obj, uri=nil)
|
26
|
+
@uri = nil
|
27
|
+
@ref = nil
|
28
|
+
if obj.nil?
|
29
|
+
return if uri.nil?
|
30
|
+
@uri, option = DRbProtocol.uri_option(uri, DRb::default_config)
|
31
|
+
@ref = DRbURIOption.new(option) unless option.nil?
|
32
|
+
else
|
33
|
+
@uri = uri ? uri : nil
|
34
|
+
@ref = obj ? DRb.to_id(obj) : nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def __drburi
|
39
|
+
@uri
|
40
|
+
end
|
41
|
+
|
42
|
+
def __drbref
|
43
|
+
@ref
|
44
|
+
end
|
45
|
+
|
46
|
+
undef :to_s
|
47
|
+
undef :to_a if respond_to?(:to_a)
|
48
|
+
|
49
|
+
def respond_to?(msg_id, priv=false)
|
50
|
+
case msg_id
|
51
|
+
when :_dump
|
52
|
+
true
|
53
|
+
when :marshal_dump
|
54
|
+
false
|
55
|
+
else
|
56
|
+
method_missing(:respond_to?, msg_id, priv)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def method_missing(msg_id, *a, &b)
|
61
|
+
promise = Promise.new
|
62
|
+
DRbConn.open(@uri) do |conn|
|
63
|
+
conn.send_message(self, msg_id, a, b) do |succ, result|
|
64
|
+
if succ
|
65
|
+
promise.resolve result
|
66
|
+
elsif DRbUnknown === result
|
67
|
+
promise.resolve result
|
68
|
+
else
|
69
|
+
bt = self.class.prepare_backtrace(@uri, result)
|
70
|
+
result.set_backtrace(bt + caller)
|
71
|
+
promise.resolve result
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
promise
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.prepare_backtrace(uri, result)
|
79
|
+
prefix = "(#{uri}) "
|
80
|
+
bt = []
|
81
|
+
result.backtrace.each do |x|
|
82
|
+
break if /`__send__'$/ =~ x
|
83
|
+
if /^\(druby:\/\// =~ x
|
84
|
+
bt.push(x)
|
85
|
+
else
|
86
|
+
bt.push(prefix + x)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
bt
|
90
|
+
end
|
91
|
+
|
92
|
+
def pretty_print(q)
|
93
|
+
q.pp_object(self)
|
94
|
+
end
|
95
|
+
|
96
|
+
def pretty_print_cycle(q)
|
97
|
+
q.object_address_group(self) {
|
98
|
+
q.breakable
|
99
|
+
q.text '...'
|
100
|
+
}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module DRb
|
2
|
+
module DRbProtocol
|
3
|
+
@protocol = [DRb::WebSocket] # default
|
4
|
+
end
|
5
|
+
|
6
|
+
module DRbProtocol
|
7
|
+
def add_protocol(prot)
|
8
|
+
@protocol.push(prot)
|
9
|
+
end
|
10
|
+
module_function :add_protocol
|
11
|
+
|
12
|
+
def open(uri, config, first=true)
|
13
|
+
@protocol.each do |prot|
|
14
|
+
begin
|
15
|
+
return prot.open(uri, config)
|
16
|
+
rescue DRbBadScheme
|
17
|
+
rescue DRbConnError
|
18
|
+
raise($!)
|
19
|
+
rescue
|
20
|
+
raise(DRbConnError, "#{uri} - #{$!.inspect}")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
raise DRbBadURI, 'can\'t parse uri:' + uri
|
24
|
+
end
|
25
|
+
module_function :open
|
26
|
+
|
27
|
+
def uri_option(uri, config, first=true)
|
28
|
+
@protocol.each do |prot|
|
29
|
+
begin
|
30
|
+
uri, opt = prot.uri_option(uri, config)
|
31
|
+
return uri, opt
|
32
|
+
rescue DRbBadScheme
|
33
|
+
end
|
34
|
+
end
|
35
|
+
if first && (config[:auto_load] != false)
|
36
|
+
auto_load(uri)
|
37
|
+
return uri_option(uri, config, false)
|
38
|
+
end
|
39
|
+
raise DRbBadURI, 'can\'t parse uri:' + uri
|
40
|
+
end
|
41
|
+
module_function :uri_option
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'native'
|
2
|
+
require 'promise'
|
3
|
+
|
4
|
+
class ArrayBuffer
|
5
|
+
include Native
|
6
|
+
|
7
|
+
native_reader :buffer
|
8
|
+
native_reader :length
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
result = ""
|
12
|
+
arr = []
|
13
|
+
%x(
|
14
|
+
for (var i = 0; i < self.native.length; i ++) {
|
15
|
+
arr.push(self.native[i]);
|
16
|
+
result += String.fromCharCode(self.native[i]);
|
17
|
+
}
|
18
|
+
)
|
19
|
+
result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class WebSocket
|
24
|
+
include Native
|
25
|
+
|
26
|
+
def initialize(url)
|
27
|
+
super `new WebSocket(url)`
|
28
|
+
`self.native.binaryType = 'arraybuffer'`
|
29
|
+
end
|
30
|
+
|
31
|
+
def onmessage
|
32
|
+
add_event_listener('message') {|event| yield MessageEvent.new(event) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def onopen
|
36
|
+
add_event_listener('open') {|event| yield MessageEvent.new(event) }
|
37
|
+
end
|
38
|
+
|
39
|
+
alias_native :close
|
40
|
+
alias_native :send
|
41
|
+
alias_native :add_event_listener, :addEventListener
|
42
|
+
|
43
|
+
class MessageEvent
|
44
|
+
include Native
|
45
|
+
|
46
|
+
def data
|
47
|
+
ArrayBuffer.new(`new Uint8Array(self.native.data)`)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module DRb
|
53
|
+
module WebSocket
|
54
|
+
class StrStream
|
55
|
+
def initialize(str='')
|
56
|
+
@buf = str
|
57
|
+
end
|
58
|
+
attr_reader :buf
|
59
|
+
|
60
|
+
def read(n)
|
61
|
+
begin
|
62
|
+
return @buf[0,n]
|
63
|
+
ensure
|
64
|
+
@buf = @buf[n, @buf.size - n]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def write(s)
|
69
|
+
@buf += s
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.uri_option(uri, config)
|
74
|
+
return uri, nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.open(uri, config)
|
78
|
+
unless uri =~ /^ws:\/\/(.*?):(\d+)(\?(.*))?$/
|
79
|
+
raise(DRbBadScheme, uri) unless uri =~ /^ws:/
|
80
|
+
raise(DRbBadURI, 'can\'t parse uri:' + uri)
|
81
|
+
end
|
82
|
+
ClientSide.new(uri, config)
|
83
|
+
end
|
84
|
+
|
85
|
+
class ClientSide
|
86
|
+
def initialize(uri, config)
|
87
|
+
@uri = uri
|
88
|
+
@res = nil
|
89
|
+
@config = config
|
90
|
+
@msg = DRbMessage.new(config)
|
91
|
+
@proxy = ENV['HTTP_PROXY']
|
92
|
+
end
|
93
|
+
|
94
|
+
def close
|
95
|
+
end
|
96
|
+
|
97
|
+
def alive?
|
98
|
+
false
|
99
|
+
end
|
100
|
+
|
101
|
+
def send_request(ref, msg_id, *arg, &b)
|
102
|
+
stream = StrStream.new
|
103
|
+
@msg.send_request(stream, ref, msg_id, *arg, &b)
|
104
|
+
post(@uri, stream.buf)
|
105
|
+
end
|
106
|
+
|
107
|
+
def recv_reply(reply_stream)
|
108
|
+
@ws.close
|
109
|
+
@msg.recv_reply(reply_stream)
|
110
|
+
end
|
111
|
+
|
112
|
+
def post(uri, data)
|
113
|
+
promise = Promise.new
|
114
|
+
@ws = ::WebSocket.new(uri)
|
115
|
+
@ws.onmessage do |event|
|
116
|
+
reply_stream = StrStream.new
|
117
|
+
reply_stream.write(event.data.to_s)
|
118
|
+
|
119
|
+
if @config[:load_limit] < reply_stream.buf.size
|
120
|
+
raise TypeError, 'too large packet'
|
121
|
+
end
|
122
|
+
|
123
|
+
promise.resolve reply_stream
|
124
|
+
end
|
125
|
+
|
126
|
+
@ws.onopen do
|
127
|
+
@ws.send(`new Uint8Array(#{data.bytes.each_slice(2).map(&:first)}).buffer`)
|
128
|
+
end
|
129
|
+
promise
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
data/opal-drb.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'opal/drb/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "opal-drb"
|
8
|
+
spec.version = Opal::DRb::VERSION
|
9
|
+
spec.authors = ["youchan"]
|
10
|
+
spec.email = ["youchan01@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{A dRuby implementation for Opal}
|
13
|
+
spec.description = %q{A dRuby implementation for Opal which is using WebSocket as Protocol.}
|
14
|
+
spec.homepage = "https://github.com/youchan/opal-drb"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
26
|
+
end
|
data/proc.rb
ADDED
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: opal-drb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- youchan
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-07-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: A dRuby implementation for Opal which is using WebSocket as Protocol.
|
56
|
+
email:
|
57
|
+
- youchan01@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".travis.yml"
|
65
|
+
- Gemfile
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- bin/console
|
69
|
+
- bin/setup
|
70
|
+
- example/Gemfile
|
71
|
+
- example/Gemfile.lock
|
72
|
+
- example/app/application.rb
|
73
|
+
- example/assets/css/application.scss
|
74
|
+
- example/bin/console
|
75
|
+
- example/config.ru
|
76
|
+
- example/server.rb
|
77
|
+
- example/views/index.erb
|
78
|
+
- lib/opal/drb.rb
|
79
|
+
- lib/opal/drb/drb.rb
|
80
|
+
- lib/opal/drb/drb_conn.rb
|
81
|
+
- lib/opal/drb/drb_message.rb
|
82
|
+
- lib/opal/drb/drb_object.rb
|
83
|
+
- lib/opal/drb/drb_protocol.rb
|
84
|
+
- lib/opal/drb/version.rb
|
85
|
+
- lib/opal/drb/websocket.rb
|
86
|
+
- opal-drb.gemspec
|
87
|
+
- proc.rb
|
88
|
+
homepage: https://github.com/youchan/opal-drb
|
89
|
+
licenses: []
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.6.11
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: A dRuby implementation for Opal
|
111
|
+
test_files: []
|