zmachine 0.1.3 → 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.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ODFlZWJhODg3YmM5NWMxYmJmZmRmNmM5ZGI0N2NkMzIzNWU3YjEwZg==
5
- data.tar.gz: !binary |-
6
- NGMyYTk4ZmIwODI5OWZlMjY1ZDQxYjRkYTBlZGJiZjAyZGY0MDY4Mw==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- YTVjMmVhODBmZjU3NTA4MmQ4MDBkOTRlZmE4OTMzNjA4ZWM4NjgwZmM2ZWVm
10
- YWRlYTM0Mzg0NTlhYzYwYzgyOWIwZmMzMzcyZTEzNDU2MjFjNGQyYjliMmFh
11
- YzJmMWYwZWU5MTdjYmJmZjk0ZDgwZmQ2YzZhOGQxZjdmNTNmZTA=
12
- data.tar.gz: !binary |-
13
- OGRmZjQ3YWI2NTllOWI2MzQzODVhOGVjYzAzMjI5ZDgwNTQ3NTU4MjM4NjVk
14
- Yjk5MzU0MmJmM2QwNjUxYzllZTZlMWIyMTVlMGM5OTE1YWZmOTA1OTIzZGRm
15
- Y2VjYjI4N2JkNzRjOTcxNDgzMTA0NTU1YmM0ZWYwOWFmMzQ1M2I=
2
+ SHA1:
3
+ metadata.gz: 47d9ec01f1c2e637dd7b8bd49e8df5ab2f6c9ec2
4
+ data.tar.gz: 9fea025ea55da57597fc31ecb8fc17055afcca9b
5
+ SHA512:
6
+ metadata.gz: 3c2709abad08e6337fd8d930e71d7b1d970cd7add92ab40eee2574500de96cdad5bc8c09acb375dd4cd16cb67aa8f992f64db7b05a88eff0f8d92e6ced62c115
7
+ data.tar.gz: b0ad9bfe37a314ec281d61c1ff9eb1221153d1f199740ebde8acc9a9a755bbd5e7d25bdf66d3e18410ea2677f74e671093cdd177b0871ac346b42547a1378a44
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ .rspec
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ jruby-1.7.6
data/Gemfile CHANGED
@@ -3,7 +3,10 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in zmachine.gemspec
4
4
  gemspec
5
5
 
6
+ gem 'awesome_print'
7
+ gem 'brice'
8
+ gem 'fuubar'
6
9
  gem 'ruby-debug'
7
10
  gem 'ruby-debug-ide'
8
- gem 'brice'
9
- gem 'awesome_print'
11
+ gem 'madvertise-ext'
12
+ gem 'simplecov'
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Zmachine
2
2
 
3
- TODO: Write a gem description
3
+ ZMachine is a JRuby Event Reactor based on java.nio.Selector and a HashedWheel
4
+ timer implementation. ZMachine supports TCP and ZeroMQ sockets natively and
5
+ exposes an EventMachine compatible API where possible.
4
6
 
5
7
  ## Installation
6
8
 
data/Rakefile CHANGED
@@ -1 +1,2 @@
1
1
  require "bundler/gem_tasks"
2
+ require "madvertise/tasks"
@@ -0,0 +1,12 @@
1
+ #!/bin/bash
2
+
3
+ bundle exec jruby \
4
+ --server \
5
+ -J-Djruby.compile.fastest=true \
6
+ -J-Djruby.compile.frameless=true \
7
+ -J-Djruby.compile.positionless=true \
8
+ -J-Djruby.compile.threadless=true \
9
+ -J-Djruby.compile.fastops=true \
10
+ -J-Djruby.compile.fastcase=true \
11
+ -J-Djruby.compile.invokedynamic=true \
12
+ "$@" | pv -l >/dev/null
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'zmachine/tcp_channel'
4
+
5
+ include ZMachine
6
+
7
+ server = TCPChannel.new
8
+ server.bind("0.0.0.0", 12345)
9
+
10
+ client = TCPChannel.new
11
+ client.connect("0.0.0.0", 12345)
12
+
13
+ channel = server.accept
14
+ client.finish_connecting
15
+
16
+ data = ("x" * 2048).freeze
17
+
18
+ loop do
19
+ client.send_data(data)
20
+ client.write_outbound_data
21
+ received = channel.read_inbound_data
22
+ puts received
23
+ channel.send_data(received)
24
+ channel.write_outbound_data
25
+ client.read_inbound_data
26
+ end
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'zmachine/zmq_channel'
4
+
5
+ include ZMachine
6
+
7
+ server = ZMQChannel.new(ZMQ::REP)
8
+ #server.bind("tcp://0.0.0.0:12345")
9
+ server.bind("inproc://x")
10
+
11
+ client = ZMQChannel.new(ZMQ::REQ)
12
+ #client.connect("tcp://0.0.0.0:12345")
13
+ client.connect("inproc://x")
14
+
15
+ data = ("x" * 2048).to_java_bytes
16
+
17
+ loop do
18
+ client.send_data([data])
19
+ received = server.read_inbound_data.first
20
+ puts received
21
+ server.send_data([data])
22
+ client.read_inbound_data
23
+ end
data/echo_client.rb CHANGED
@@ -2,11 +2,12 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'bundler/setup'
5
+ require 'madvertise/boot'
5
6
  require 'zmachine'
6
7
 
7
- java_import org.zeromq.ZMQ
8
- java_import org.zeromq.ZMsg
9
- java_import org.zeromq.ZFrame
8
+ $log.level = :debug
9
+ ZMachine.logger = $log
10
+ ZMachine.debug = true
10
11
 
11
12
  #set_trace_func proc { |event, file, line, id, binding, classname|
12
13
  # printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
@@ -44,28 +45,9 @@ class TCPEcho < ZMachine::Connection
44
45
  end
45
46
  end
46
47
 
47
- ZMachine.run {
48
- ZMachine.connect("tcp://127.0.0.1:10000", ZMQ::ROUTER, ZMQEcho) do |handler|
49
- handler.channel.identity = "client"
50
- end
51
- #ZMachine.connect("127.0.0.1", 10000, TCPEcho)
52
- }
53
-
54
- #ctx = ZContext.new
55
- #socket = ctx.create_socket(ZMQ::ROUTER)
56
- #socket.connect("tcp://127.0.0.1:10000")
57
- #socket.identity = "client".to_java_bytes
58
-
59
- #sleep(1)
60
-
61
- #loop do
62
- # msg = ZMsg.new_string_msg($i.to_s)
63
- # msg.wrap(ZFrame.new("server"))
64
- # msg.java_send(:send, [org.zeromq.ZMQ::Socket], socket)
65
- # $i += 1
66
- # break if $i > 100
67
- # #puts ZMsg.recvMsg(socket).inspect
68
- #end
69
-
70
- #socket.close
71
- #ctx.destroy
48
+ ZMachine.run do
49
+ #ZMachine.connect("tcp://127.0.0.1:10000", ZMQ::ROUTER, ZMQEcho) do |handler|
50
+ # handler.channel.identity = "client"
51
+ #end
52
+ ZMachine.connect("127.0.0.1", 10000, TCPEcho)
53
+ end
data/echo_server.rb CHANGED
@@ -2,40 +2,33 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'bundler/setup'
5
+ require 'madvertise/boot'
5
6
  require 'zmachine'
6
7
 
7
- java_import org.zeromq.ZMQ
8
- java_import org.zeromq.ZFrame
8
+ $log.level = :debug
9
+ ZMachine.logger = $log
10
+ ZMachine.debug = true
9
11
 
10
12
  #set_trace_func proc { |event, file, line, id, binding, classname|
11
13
  # printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
12
14
  #}
13
15
 
14
- class EchoServer < ZMachine::Connection
15
- def receive_data(msg)
16
- origin = msg.unwrap
17
- puts "recv(#{msg.to_a.map {|f| String.from_java_bytes(f.data) }.inspect})"
18
- msg = ZMsg.new_string_msg("ok")
19
- msg.wrap(origin)
20
- send_data(msg)
16
+ class ZMQEchoServer < ZMachine::Connection
17
+ def receive_data(buffer)
18
+ send_data(buffer)
19
+ end
20
+ end
21
+
22
+ class TCPEchoServer < ZMachine::Connection
23
+ def receive_data(buffer)
24
+ send_data(buffer)
21
25
  end
22
26
  end
23
27
 
24
28
  ZMachine.run do
25
- ZMachine.start_server("tcp://*:10000", ZMQ::ROUTER, EchoServer) do |handler|
29
+ ZMachine.start_server("tcp://*:10000", ZMQ::ROUTER, ZMQEchoServer) do |handler|
26
30
  handler.channel.identity = "server"
27
31
  end
28
- #ZMachine.start_server("0.0.0.0", 10000, EchoServer)
32
+ #ZMachine.start_server("0.0.0.0", 10000, TCPEchoServer)
29
33
  puts "machine running"
30
34
  end
31
-
32
- #ctx = ZContext.new
33
- #socket = ctx.create_socket(ZMQ::ROUTER)
34
- #socket.bind("tcp://127.0.0.1:10000")
35
- #socket.identity = "server".to_java_bytes
36
-
37
- #loop do
38
- # puts socket.events.inspect
39
- # msg = ZMsg.recvMsg(socket)
40
- # puts "recv(#{msg.to_a.map {|f| String.from_java_bytes(f.data) }.inspect})"
41
- #end
data/lib/zmachine.rb CHANGED
@@ -1,11 +1,13 @@
1
- require 'forwardable'
1
+ require 'zmachine/jeromq-0.3.0-SNAPSHOT.jar'
2
+ java_import org.zeromq.ZContext
3
+
4
+ require 'madvertise/boot'
2
5
 
3
6
  require 'zmachine/connection'
4
7
  require 'zmachine/deferrable'
5
8
  require 'zmachine/reactor'
6
9
  require 'zmachine/timers'
7
10
 
8
-
9
11
  module ZMachine
10
12
  class ConnectionError < RuntimeError; end
11
13
  class ConnectionNotBound < RuntimeError; end
@@ -25,27 +27,11 @@ module ZMachine
25
27
  Thread.current[:reactor] ||= Reactor.new
26
28
  end
27
29
 
30
+ # TODO: move to ZMQChannel
28
31
  def self.context
29
32
  Thread.current[:context] ||= ZContext.new
30
33
  end
31
34
 
32
- class << self
33
- extend Forwardable
34
- def_delegator :reactor, :add_shutdown_hook
35
- def_delegator :reactor, :add_timer
36
- def_delegator :reactor, :cancel_timer
37
- def_delegator :reactor, :connect
38
- def_delegator :reactor, :connection_count
39
- def_delegator :reactor, :error_handler
40
- def_delegator :reactor, :next_tick
41
- def_delegator :reactor, :run
42
- def_delegator :reactor, :reactor_running?
43
- def_delegator :reactor, :reconnect
44
- def_delegator :reactor, :start_server
45
- def_delegator :reactor, :stop_event_loop
46
- def_delegator :reactor, :stop_server
47
- end
48
-
49
35
  def self._not_implemented
50
36
  raise RuntimeError.new("API call not implemented! #{caller[0]}")
51
37
  end
@@ -56,6 +42,14 @@ module ZMachine
56
42
  PeriodicTimer.new(interval, callback)
57
43
  end
58
44
 
45
+ def self.add_shutdown_hook(&block)
46
+ reactor.add_shutdown_hook(&block)
47
+ end
48
+
49
+ def self.add_timer(*args, &block)
50
+ reactor.add_timer(*args, &block)
51
+ end
52
+
59
53
  def self.attach(io, handler = nil, *args, &blk)
60
54
  _not_implemented
61
55
  end
@@ -68,10 +62,26 @@ module ZMachine
68
62
  _not_implemented
69
63
  end
70
64
 
65
+ def self.cancel_timer(timer_or_sig)
66
+ timer_or_sig.cancel # we do not support signatures
67
+ end
68
+
69
+ def self.close_connection(connection)
70
+ reactor.close_connection(connection)
71
+ end
72
+
73
+ def self.connect(server, port_or_type=nil, handler=nil, *args, &block)
74
+ reactor.connect(server, port_or_type, handler, *args, &block)
75
+ end
76
+
71
77
  def self.connect_unix_domain(socketname, *args, &blk)
72
78
  _not_implemented
73
79
  end
74
80
 
81
+ def self.connection_count
82
+ reactor.connections.size
83
+ end
84
+
75
85
  def self.defer(op = nil, callback = nil, &blk)
76
86
  _not_implemented
77
87
  end
@@ -88,6 +98,10 @@ module ZMachine
88
98
  _not_implemented
89
99
  end
90
100
 
101
+ def self.error_handler(callback = nil, &block)
102
+ _not_implemented
103
+ end
104
+
91
105
  def self.fork_reactor(&block)
92
106
  _not_implemented
93
107
  end
@@ -97,11 +111,15 @@ module ZMachine
97
111
  end
98
112
 
99
113
  def self.heartbeat_interval
100
- _not_implemented
114
+ reactor.heartbeat_interval
101
115
  end
102
116
 
103
117
  def self.heartbeat_interval=(time)
104
- _not_implemented
118
+ reactor.heartbeat_interval = time
119
+ end
120
+
121
+ def self.next_tick(callback=nil, &block)
122
+ reactor.next_tick(callback, &block)
105
123
  end
106
124
 
107
125
  def self.open_datagram_socket(address, port, handler = nil, *args)
@@ -112,12 +130,20 @@ module ZMachine
112
130
  _not_implemented
113
131
  end
114
132
 
133
+ def self.reactor_running?
134
+ reactor.running?
135
+ end
136
+
115
137
  def self.reactor_thread?
116
138
  _not_implemented
117
139
  end
118
140
 
119
- def self.stop
120
- Reactor.terminate_all_reactors
141
+ def self.reconnect(server, port, handler)
142
+ reactor.reconnect(server, port, handler)
143
+ end
144
+
145
+ def self.run(callback=nil, shutdown_hook=nil, &block)
146
+ reactor.run(callback, shutdown_hook, &block)
121
147
  end
122
148
 
123
149
  def self.run_block(&block)
@@ -152,10 +178,26 @@ module ZMachine
152
178
  _not_implemented
153
179
  end
154
180
 
181
+ def self.start_server(server, port_or_type=nil, handler=nil, *args, &block)
182
+ reactor.bind(server, port_or_type, handler, *args, &block)
183
+ end
184
+
155
185
  def self.start_unix_domain_server(filename, *args, &block)
156
186
  _not_implemented
157
187
  end
158
188
 
189
+ def self.stop_event_loop
190
+ reactor.stop_event_loop
191
+ end
192
+
193
+ def self.stop_server(signature)
194
+ reactor.stop_server(signature)
195
+ end
196
+
197
+ def self.stop
198
+ Reactor.terminate_all_reactors
199
+ end
200
+
159
201
  def self.system(cmd, *args, &cb)
160
202
  _not_implemented
161
203
  end
@@ -177,3 +219,9 @@ module ZMachine
177
219
  end
178
220
 
179
221
  end
222
+
223
+ if ENV['DEBUG']
224
+ $log.level = :debug
225
+ ZMachine.logger = $log
226
+ ZMachine.debug = true
227
+ end
@@ -1,42 +1,44 @@
1
+ java_import java.nio.ByteBuffer
2
+
1
3
  module ZMachine
2
4
  class Channel
3
5
 
4
6
  attr_accessor :socket
5
- attr_reader :selector
6
- attr_accessor :handler
7
- attr_accessor :reactor
8
-
9
- attr_reader :comm_inactivity_timeout
10
- attr_reader :last_comm_activity
11
7
 
12
- def initialize(selector)
13
- @selector = selector
8
+ def initialize
9
+ @inbound_buffer = ByteBuffer.allocate(1024 * 1024)
14
10
  @outbound_queue = []
15
- @comm_inactivity_timeout = 0
16
- @timedout = false
17
- mark_active!
18
- end
19
-
20
- # assigned in seconds!!
21
- def comm_inactivity_timeout=(value)
22
- # we are in nanos
23
- @comm_inactivity_timeout = value * 1000_000_000
24
- end
25
-
26
- def mark_active!
27
- @last_comm_activity = System.nano_time
11
+ @close_scheduled = false
28
12
  end
29
13
 
30
- def timedout?
31
- @timedout
14
+ # methods that need to be implemented in sub classes:
15
+ #
16
+ # selectable_fd
17
+ # bind(address, port = nil)
18
+ # bound?
19
+ # accept
20
+ # connect(address, port = nil)
21
+ # connection_pending?
22
+ # finish_connecting
23
+ # connected?
24
+ # read_inbound_data
25
+ # send_data(data)
26
+ # closed?
27
+ # peer
28
+ # write_outbound_data
29
+
30
+ def can_send?
31
+ !@outbound_queue.empty?
32
32
  end
33
33
 
34
- def timedout!
35
- @timedout = true
34
+ def close(after_writing = false)
35
+ ZMachine.logger.debug("zmachine:channel:#{__method__}", channel: self, after_writing: after_writing) if ZMachine.debug
36
+ @close_scheduled = true
37
+ @outbound_queue.clear unless after_writing
36
38
  end
37
39
 
38
- def was_active?(now)
39
- @last_comm_activity + @comm_inactivity_timeout >= now
40
+ def close_after_writing
41
+ close(true)
40
42
  end
41
43
 
42
44
  end