zmachine 0.1.3 → 0.2.0

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