zmachine 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.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in zmachine.gemspec
4
+ gemspec
5
+
6
+ gem 'ruby-debug'
7
+ gem 'ruby-debug-ide'
8
+ gem 'brice'
9
+ gem 'awesome_print'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Benedikt Böhm
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Zmachine
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'zmachine'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install zmachine
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/echo_client.rb ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'zmachine'
6
+
7
+ java_import org.zeromq.ZMQ
8
+ java_import org.zeromq.ZMsg
9
+ java_import org.zeromq.ZFrame
10
+
11
+ #set_trace_func proc { |event, file, line, id, binding, classname|
12
+ # printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
13
+ #}
14
+
15
+ $i = 0
16
+
17
+ class ZMQEcho < ZMachine::Connection
18
+ def connection_completed
19
+ send_msg
20
+ end
21
+
22
+ def receive_data(data)
23
+ puts "recv(#{data.to_a.map {|f| String.from_java_bytes(f.data) }.inspect})"
24
+ send_msg
25
+ end
26
+
27
+ def send_msg
28
+ msg = ZMsg.new_string_msg($i.to_s)
29
+ msg.wrap(ZFrame.new("server"))
30
+ send_data(msg)
31
+ $i += 1
32
+ end
33
+ end
34
+
35
+ class TCPEcho < ZMachine::Connection
36
+ def connection_completed
37
+ send_data(Time.now.to_s)
38
+ sleep(0.5)
39
+ end
40
+
41
+ def receive_data(data)
42
+ puts "receive_data(#{data.inspect})"
43
+ send_data(Time.now.to_s)
44
+ end
45
+ end
46
+
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
data/echo_server.rb ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'zmachine'
6
+
7
+ java_import org.zeromq.ZMQ
8
+ java_import org.zeromq.ZFrame
9
+
10
+ #set_trace_func proc { |event, file, line, id, binding, classname|
11
+ # printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname
12
+ #}
13
+
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)
21
+ end
22
+ end
23
+
24
+ ZMachine.run do
25
+ ZMachine.start_server("tcp://*:10000", ZMQ::ROUTER, EchoServer) do |handler|
26
+ handler.channel.identity = "server"
27
+ end
28
+ #ZMachine.start_server("0.0.0.0", 10000, EchoServer)
29
+ puts "machine running"
30
+ 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
@@ -0,0 +1,12 @@
1
+ module ZMachine
2
+ class Acceptor
3
+ attr_reader :klass
4
+ attr_reader :args
5
+ attr_reader :callback
6
+
7
+ def initialize(channel, klass, *args, &block)
8
+ @klass, @args, @callback = klass, args, block
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module ZMachine
2
+ class Channel
3
+
4
+ attr_reader :socket
5
+ attr_reader :selector
6
+ attr_accessor :handler
7
+
8
+ def initialize(selector)
9
+ @selector = selector
10
+ @outbound_queue = []
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,186 @@
1
+ module ZMachine
2
+ class Connection
3
+
4
+ attr_accessor :channel
5
+
6
+ extend Forwardable
7
+
8
+ alias original_method method
9
+
10
+ def self.new(channel, *args, &block)
11
+ allocate.instance_eval do
12
+ @channel = channel
13
+ initialize(*args, &block)
14
+ post_init
15
+ self
16
+ end
17
+ end
18
+
19
+ def initialize(*args, &block)
20
+ end
21
+
22
+ # callbacks
23
+
24
+ def post_init
25
+ end
26
+
27
+ def connection_completed
28
+ end
29
+
30
+ def receive_data(data)
31
+ end
32
+
33
+ def unbind
34
+ end
35
+
36
+ # public API
37
+
38
+ def_delegator :@channel, :close_connection
39
+
40
+ def close_connection_after_writing
41
+ close_connection(true)
42
+ end
43
+
44
+ def comm_inactivity_timeout
45
+ end
46
+
47
+ def comm_inactivity_timeout=(value)
48
+ end
49
+
50
+ alias :set_comm_inactivity_timeout :comm_inactivity_timeout=
51
+
52
+ def detach
53
+ _not_implemented
54
+ end
55
+
56
+ def error?
57
+ errno = ZMachine::report_connection_error_status(@signature)
58
+ case errno
59
+ when 0
60
+ false
61
+ when -1
62
+ true
63
+ else
64
+ Errno::constants.select do |name|
65
+ Errno.__send__(:const_get, name)::Errno == errno
66
+ end.first
67
+ end
68
+ end
69
+
70
+ def get_idle_time
71
+ _not_implemented
72
+ end
73
+
74
+ def get_peer_cert
75
+ _not_implemented
76
+ end
77
+
78
+ def get_peername
79
+ if peer = @channel.peer_name
80
+ ::Socket.pack_sockaddr_in(*peer)
81
+ end
82
+ end
83
+
84
+ def get_pid
85
+ _not_implemented
86
+ end
87
+
88
+ def get_proxied_bytes
89
+ _not_implemented
90
+ end
91
+
92
+ def_delegator :@channel, :get_sock_opt
93
+
94
+ def get_sockname
95
+ if sock_name = @channel.sock_name
96
+ ::Socket.pack_sockaddr_in(*sock_name)
97
+ end
98
+ end
99
+
100
+ def get_status
101
+ end
102
+
103
+ def notify_readable=(mode)
104
+ _not_implemented
105
+ end
106
+
107
+ def notify_readable?
108
+ _not_implemented
109
+ end
110
+
111
+ def notify_writable=(mode)
112
+ _not_implemented
113
+ end
114
+
115
+ def notify_writable?
116
+ _not_implemented
117
+ end
118
+
119
+ def pause
120
+ _not_implemented
121
+ end
122
+
123
+ def paused?
124
+ _not_implemented
125
+ end
126
+
127
+ def pending_connect_timeout=(value)
128
+ end
129
+
130
+ alias :set_pending_connect_timeout :pending_connect_timeout=
131
+
132
+ def proxy_completed
133
+ _not_implemented
134
+ end
135
+
136
+ def proxy_incoming_to(conn, bufsize = 0)
137
+ _not_implemented
138
+ end
139
+
140
+ def proxy_target_unbound
141
+ _not_implemented
142
+ end
143
+
144
+ def resume
145
+ _not_implemented
146
+ end
147
+
148
+ def_delegator :@channel, :send_data
149
+
150
+ def send_datagram(data, recipient_address, recipient_port)
151
+ _not_implemented
152
+ end
153
+
154
+ def send_file_data(filename)
155
+ _not_implemented
156
+ end
157
+
158
+ def_delegator :@channel, :set_sock_opt
159
+
160
+ def ssl_handshake_completed
161
+ _not_implemented
162
+ end
163
+
164
+ def ssl_verify_peer(cert)
165
+ _not_implemented
166
+ end
167
+
168
+ def start_tls(args = {})
169
+ _not_implemented
170
+ end
171
+
172
+ def stop_proxying
173
+ _not_implemented
174
+ end
175
+
176
+ def stream_file_data(filename, args = {})
177
+ _not_implemented
178
+ end
179
+
180
+ private
181
+
182
+ def _not_implemented
183
+ raise RuntimeError.new("API call not implemented!")
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,207 @@
1
+ #--
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 16 Jul 2006
6
+ #
7
+ # See ZMachine and ZMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+
26
+ module ZMachine
27
+ module Deferrable
28
+ autoload :Pool, 'em/deferrable/pool'
29
+
30
+ # Specify a block to be executed if and when the Deferrable object receives
31
+ # a status of :succeeded. See #set_deferred_status for more information.
32
+ #
33
+ # Calling this method on a Deferrable object whose status is not yet known
34
+ # will cause the callback block to be stored on an internal list.
35
+ # If you call this method on a Deferrable whose status is :succeeded, the
36
+ # block will be executed immediately, receiving the parameters given to the
37
+ # prior #set_deferred_status call.
38
+ #
39
+ #--
40
+ # If there is no status, add a callback to an internal list.
41
+ # If status is succeeded, execute the callback immediately.
42
+ # If status is failed, do nothing.
43
+ #
44
+ def callback(&block)
45
+ return unless block
46
+ @deferred_status ||= :unknown
47
+ if @deferred_status == :succeeded
48
+ block.call(*@deferred_args)
49
+ elsif @deferred_status != :failed
50
+ @callbacks ||= []
51
+ @callbacks.unshift(block) # << block
52
+ end
53
+ self
54
+ end
55
+
56
+ # Cancels an outstanding callback to &block if any. Undoes the action of #callback.
57
+ #
58
+ def cancel_callback(block)
59
+ @callbacks ||= []
60
+ @callbacks.delete(block)
61
+ end
62
+
63
+ # Specify a block to be executed if and when the Deferrable object receives
64
+ # a status of :failed. See #set_deferred_status for more information.
65
+ #--
66
+ # If there is no status, add an errback to an internal list.
67
+ # If status is failed, execute the errback immediately.
68
+ # If status is succeeded, do nothing.
69
+ #
70
+ def errback(&block)
71
+ return unless block
72
+ @deferred_status ||= :unknown
73
+ if @deferred_status == :failed
74
+ block.call(*@deferred_args)
75
+ elsif @deferred_status != :succeeded
76
+ @errbacks ||= []
77
+ @errbacks.unshift(block) # << block
78
+ end
79
+ self
80
+ end
81
+
82
+ # Cancels an outstanding errback to &block if any. Undoes the action of #errback.
83
+ #
84
+ def cancel_errback(block)
85
+ @errbacks ||= []
86
+ @errbacks.delete(block)
87
+ end
88
+
89
+ # Sets the "disposition" (status) of the Deferrable object. See also the large set of
90
+ # sugarings for this method.
91
+ # Note that if you call this method without arguments,
92
+ # no arguments will be passed to the callback/errback.
93
+ # If the user has coded these with arguments, then the
94
+ # user code will throw an argument exception.
95
+ # Implementors of deferrable classes <b>must</b>
96
+ # document the arguments they will supply to user callbacks.
97
+ #
98
+ # OBSERVE SOMETHING VERY SPECIAL here: you may call this method even
99
+ # on the INSIDE of a callback. This is very useful when a previously-registered
100
+ # callback wants to change the parameters that will be passed to subsequently-registered
101
+ # ones.
102
+ #
103
+ # You may give either :succeeded or :failed as the status argument.
104
+ #
105
+ # If you pass :succeeded, then all of the blocks passed to the object using the #callback
106
+ # method (if any) will be executed BEFORE the #set_deferred_status method returns. All of the blocks
107
+ # passed to the object using #errback will be discarded.
108
+ #
109
+ # If you pass :failed, then all of the blocks passed to the object using the #errback
110
+ # method (if any) will be executed BEFORE the #set_deferred_status method returns. All of the blocks
111
+ # passed to the object using # callback will be discarded.
112
+ #
113
+ # If you pass any arguments to #set_deferred_status in addition to the status argument,
114
+ # they will be passed as arguments to any callbacks or errbacks that are executed.
115
+ # It's your responsibility to ensure that the argument lists specified in your callbacks and
116
+ # errbacks match the arguments given in calls to #set_deferred_status, otherwise Ruby will raise
117
+ # an ArgumentError.
118
+ #
119
+ #--
120
+ # We're shifting callbacks off and discarding them as we execute them.
121
+ # This is valid because by definition callbacks are executed no more than
122
+ # once. It also has the magic effect of permitting recursive calls, which
123
+ # means that a callback can call #set_deferred_status and change the parameters
124
+ # that will be sent to subsequent callbacks down the chain.
125
+ #
126
+ # Changed @callbacks and @errbacks from push/shift to unshift/pop, per suggestion
127
+ # by Kirk Haines, to work around the memory leak bug that still exists in many Ruby
128
+ # versions.
129
+ #
130
+ # Changed 15Sep07: after processing callbacks or errbacks, CLEAR the other set of
131
+ # handlers. This gets us a little closer to the behavior of Twisted's "deferred,"
132
+ # which only allows status to be set once. Prior to making this change, it was possible
133
+ # to "succeed" a Deferrable (triggering its callbacks), and then immediately "fail" it,
134
+ # triggering its errbacks! That is clearly undesirable, but it's just as undesirable
135
+ # to raise an exception is status is set more than once on a Deferrable. The latter
136
+ # behavior would invalidate the idiom of resetting arguments by setting status from
137
+ # within a callback or errback, but more seriously it would cause spurious errors
138
+ # if a Deferrable was timed out and then an attempt was made to succeed it. See the
139
+ # comments under the new method #timeout.
140
+ #
141
+ def set_deferred_status(status, *args)
142
+ cancel_timeout
143
+ @errbacks ||= nil
144
+ @callbacks ||= nil
145
+ @deferred_status = status
146
+ @deferred_args = args
147
+ case @deferred_status
148
+ when :succeeded
149
+ if @callbacks
150
+ while cb = @callbacks.pop
151
+ cb.call(*@deferred_args)
152
+ end
153
+ end
154
+ @errbacks.clear if @errbacks
155
+ when :failed
156
+ if @errbacks
157
+ while eb = @errbacks.pop
158
+ eb.call(*@deferred_args)
159
+ end
160
+ end
161
+ @callbacks.clear if @callbacks
162
+ end
163
+ end
164
+
165
+ # Setting a timeout on a Deferrable causes it to go into the failed state after
166
+ # the Timeout expires (passing no arguments to the object's errbacks).
167
+ # Setting the status at any time prior to a call to the expiration of the timeout
168
+ # will cause the timer to be cancelled.
169
+ def timeout(seconds, *args)
170
+ cancel_timeout
171
+ me = self
172
+ @deferred_timeout = ZMachine::Timer.new(seconds) { me.fail(*args) }
173
+ self
174
+ end
175
+
176
+ # Cancels an outstanding timeout if any. Undoes the action of #timeout.
177
+ #
178
+ def cancel_timeout
179
+ @deferred_timeout ||= nil
180
+ if @deferred_timeout
181
+ @deferred_timeout.cancel
182
+ @deferred_timeout = nil
183
+ end
184
+ end
185
+
186
+ # Sugar for set_deferred_status(:succeeded, ...)
187
+ #
188
+ def succeed(*args)
189
+ set_deferred_status(:succeeded, *args)
190
+ end
191
+ alias set_deferred_success succeed
192
+
193
+ # Sugar for set_deferred_status(:failed, ...)
194
+ #
195
+ def fail(*args)
196
+ set_deferred_status(:failed, *args)
197
+ end
198
+ alias set_deferred_failure fail
199
+ end
200
+
201
+ # DefaultDeferrable is an otherwise empty class that includes Deferrable.
202
+ # This is very useful when you just need to return a Deferrable object
203
+ # as a way of communicating deferred status to some other part of a program.
204
+ class DefaultDeferrable
205
+ include Deferrable
206
+ end
207
+ end