0mq 0.2.1 → 0.3.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,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5255703edba3faced3f3cc4cf411691e9a32657d
4
- data.tar.gz: 70d06c893160bc3b09176cdec4626ec565e5637a
3
+ metadata.gz: 620201ac4bf75176a5ab224bd0bf0f0c3598e028
4
+ data.tar.gz: c360991d9cf9aa84873672945bd84252cb191263
5
5
  SHA512:
6
- metadata.gz: 4114dc03d01056936a3bef1d4918e0f192616ee3283b4621d4249d4a4d8bb1dc05cc048ee7bf56a6c1167efc1636050839e59d83a762127d35c85e4df3558c62
7
- data.tar.gz: 9f5f9c14f49b2f34e2018406d173f02627973cdea41f0a09873f99370d226bd8fc8b4ca454f789d50c804d81e6a50b0c73c8602ba3e83107d4c75f820ef71c1c
6
+ metadata.gz: 32f96897d84651bcc51e2e9037401ceb4839963a2523b534cbd9a46ffa6c4bad2f58a7c35e641505bc8a8b924a6153f5342bdd57c73a3cd9dc99f2e94f2572a2
7
+ data.tar.gz: 448432e63a64c0fe205e277c0040cb41fa13e90772b57c9f0b03c7eae8e100f16ae0afe011dd301df7c7f3d34e126e3647b03d2efda86a215ac7fdba736ec034
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # 0mq
2
+ _Works like ZeroMQ. Feels like Ruby._
2
3
 
3
4
  [![Build Status](https://travis-ci.org/jemc/0mq.png)](https://travis-ci.org/jemc/0mq)
4
5
  [![Gem Version](https://badge.fury.io/rb/0mq.png)](http://badge.fury.io/rb/0mq)
@@ -21,10 +22,112 @@ Supported Ruby versions:
21
22
 
22
23
  ## Feature Requests / Bug Reports
23
24
 
24
- File them as issues or pull requests on [the github repository](https://github.com/jemc/0mq).
25
+ File them as issues or pull requests on the [0mq github repository](https://github.com/jemc/0mq).
25
26
 
26
27
  ## Authors
27
28
 
28
29
  - Joe McIlvain
29
30
 
30
31
  - Alex McLain
32
+
33
+ ## Installation / Prerequisites
34
+
35
+ - Requires the [libzmq library](http://zeromq.org/intro:get-the-software).
36
+
37
+ - PGM (multicast) requires compiling libzmq with ./configure --with-pgm
38
+
39
+ - Curve cryptography requires compiling libzmq with [libsodium](https://github.com/jedisct1/libsodium).
40
+
41
+ ## ZeroMQ Documentation
42
+
43
+ - Manual: http://zeromq.org/intro:read-the-manual
44
+
45
+ - API: http://api.zeromq.org/
46
+
47
+ ## Code Examples
48
+
49
+ ### Using The 0mq Gem
50
+
51
+ ``` ruby
52
+ require '0mq'
53
+ ```
54
+
55
+ ### Create A Socket
56
+
57
+ Sockets can be created by specifying the [ZMQ socket type](http://api.zeromq.org/4-0:zmq-socket). Any errors will be raised as exceptions.
58
+
59
+ ``` ruby
60
+ socket = ZMQ::Socket.new ZMQ::PULL
61
+ socket.connect 'tcp://127.0.0.1:10000'
62
+ ```
63
+
64
+ ### Send And Receive Data
65
+
66
+ ``` ruby
67
+ address = 'tcp://127.0.0.1:10000'
68
+
69
+ push = ZMQ::Socket.new ZMQ::PUSH
70
+ push.bind address
71
+
72
+ pull = ZMQ::Socket.new ZMQ::PULL
73
+ pull.connect address
74
+
75
+ push.send_string 'test'
76
+
77
+ string = pull.recv_string
78
+
79
+ puts string
80
+ ```
81
+
82
+ ### Poll A Socket For Data
83
+
84
+ ``` ruby
85
+ address = 'inproc://poll_example'
86
+
87
+ pull = ZMQ::Socket.new ZMQ::PULL
88
+ pull.bind address
89
+
90
+ # Push a message after a delay.
91
+ Thread.new do
92
+ push = ZMQ::Socket.new ZMQ::PUSH
93
+ push.connect address
94
+ sleep 3
95
+
96
+ push.send_string 'test'
97
+ end
98
+
99
+ # Check if pull has any data (it doesn't yet).
100
+ # (Non-blocking demonstration.)
101
+ result = ZMQ::Poll.poll_nonblock pull
102
+ puts "No data available yet." if result.empty?
103
+
104
+ # Do a blocking poll until the pull socket has data.
105
+ ZMQ::Poll.poll pull do |socket, event|
106
+ puts socket.recv_string
107
+ end
108
+ ```
109
+
110
+ ### Proxy Sockets
111
+
112
+ A proxy can be used to funnel multiple endpoints into a single connection.
113
+ See: [Pub-Sub Network with a Proxy](http://zguide.zeromq.org/page:all#The-Dynamic-Discovery-Problem)
114
+
115
+ ```ruby
116
+ # ---------------- ---------------- ---------------- ----------------
117
+ # | Endpoint REQ | --> | Proxy ROUTER | --> | Proxy DEALER | --> | Endpoint REP |
118
+ # ---------------- ---------------- ---------------- ----------------
119
+
120
+ # Create sockets.
121
+ endpoint_req = ZMQ::Socket.new(ZMQ::REQ).tap { |s| s.bind 'inproc://proxy_in' }
122
+ proxy_router = ZMQ::Socket.new(ZMQ::ROUTER).tap { |s| s.connect 'inproc://proxy_in' }
123
+ proxy_dealer = ZMQ::Socket.new(ZMQ::DEALER).tap { |s| s.bind 'inproc://proxy_out' }
124
+ endpoint_rep = ZMQ::Socket.new(ZMQ::REP).tap { |s| s.connect 'inproc://proxy_out' }
125
+
126
+ # Create the proxy.
127
+ Thread.new { ZMQ::Proxy.proxy proxy_router, proxy_dealer }
128
+
129
+ # Send a message.
130
+ endpoint_req.send_string 'test'
131
+
132
+ puts endpoint_rep.recv_string
133
+ ```
data/lib/0mq.rb CHANGED
@@ -6,3 +6,8 @@ require_relative '0mq/context'
6
6
  require_relative '0mq/socket'
7
7
  require_relative '0mq/proxy'
8
8
  require_relative '0mq/poll'
9
+ require_relative '0mq/curve'
10
+ require_relative '0mq/version'
11
+
12
+ # :nodoc:
13
+ module ZMQ; end
@@ -1,22 +1,26 @@
1
1
 
2
2
  module ZMQ
3
3
 
4
+ # The context object encapsulates all the global state associated
5
+ # with the library.
4
6
  class Context
5
- attr_reader :ptr
7
+
8
+ # The FFI pointer to the context.
9
+ attr_reader :pointer
6
10
 
7
11
  def initialize
8
- @ptr = LibZMQ.zmq_ctx_new
12
+ @pointer = LibZMQ.zmq_ctx_new
9
13
  end
10
14
 
11
15
  # Destroy the ØMQ context.
12
16
  def terminate
13
- if @ptr
17
+ if @pointer
14
18
  rc = LibZMQ.version4? ?
15
- LibZMQ.zmq_ctx_term(@ptr) :
16
- LibZMQ.zmq_term(@ptr)
19
+ LibZMQ.zmq_ctx_term(@pointer) :
20
+ LibZMQ.zmq_term(@pointer)
17
21
  ZMQ.error_check true if rc == -1
18
22
 
19
- @ptr = nil
23
+ @pointer = nil
20
24
  end
21
25
  end
22
26
 
@@ -26,8 +30,14 @@ module ZMQ
26
30
  ZMQ::Socket.new type, opts
27
31
  end
28
32
 
33
+ # Returns the context's FFI pointer.
34
+ def to_ptr
35
+ @pointer
36
+ end
37
+
29
38
  end
30
39
 
40
+ # The default context to be used if another context is not provided.
31
41
  DefaultContext = Context.new
32
42
 
33
43
  end
@@ -0,0 +1,26 @@
1
+
2
+ module ZMQ
3
+
4
+ # Secure authentication and confidentiality.
5
+ class Curve
6
+
7
+ # Generate a keypair.
8
+ # Returns a hash with the :public and :private keys.
9
+ def self.keypair
10
+ public_key = FFI::MemoryPointer.new :char, 41, true
11
+ private_key = FFI::MemoryPointer.new :char, 41, true
12
+
13
+ rc = LibZMQ::zmq_curve_keypair public_key, private_key
14
+
15
+ begin
16
+ ZMQ.error_check true if rc==-1
17
+ rescue Errno::EOPNOTSUPP
18
+ raise Errno::EOPNOTSUPP, "Curve requires libzmq to be compiled with libsodium."
19
+ end
20
+
21
+ { public: public_key.read_string, private: private_key.read_string }
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -1,18 +1,24 @@
1
1
 
2
2
  module ZMQ
3
3
 
4
+ # A hash of error number => exception class.
5
+ # Example: 1 => Errno::EPERM
4
6
  ErrorMap = Hash.new
5
7
 
6
8
  Errno.constants
7
- .map { |x| Errno.const_get x }
8
- .select { |x| x.is_a?(Class) && x < SystemCallError }
9
- .each { |x| ErrorMap[x.const_get(:Errno)] = x }
9
+ .map { |x| Errno.const_get x }
10
+ .select { |x| x.is_a?(Class) && x < SystemCallError }
11
+ .each { |x| ErrorMap[x.const_get(:Errno)] = x }
10
12
 
13
+
14
+ # Checks the libzmq global error number and raises it as an exception.
15
+ # Should be used after calling a libzmq resource that returns -1 on error.
16
+ # Example: ZMQ.error_check if rc == -1
11
17
  def self.error_check(adjust_backtrace=false)
12
18
  errno = LibZMQ.zmq_errno
13
19
  return true if errno == 25
14
20
 
15
- # str = LibZMQ.zmq_strerror(errno).read_string
21
+ # TODO: Use adjust_backtrace
16
22
  str = ''
17
23
  raise ErrorMap[errno], str, caller[0...-2]
18
24
  end
@@ -15,7 +15,8 @@ module ZMQ
15
15
  # See #initialize for parameters.
16
16
  # See #run for block and return value.
17
17
  def self.poll(*sockets, &block)
18
- new(*sockets).tap { |poll| poll.run(&block) }
18
+ poller = new *sockets
19
+ poller.run &block
19
20
  end
20
21
 
21
22
  # Non-blocking version of poll.
@@ -58,7 +59,7 @@ module ZMQ
58
59
  # This is an easy way to reconnect PollItem to ZMQ::Socket without
59
60
  # having to store multiple dimensions in the socks hash.
60
61
  @socket_lookup = {}
61
- @socks.each { |socket, event| @socket_lookup[socket.ptr.address] = socket }
62
+ @socks.each { |socket, event| @socket_lookup[socket.to_ptr.address] = socket }
62
63
 
63
64
  # Allocate space for C PollItem (zmq_pollitem_t) structs.
64
65
  @poll_structs = FFI::MemoryPointer.new LibZMQ::PollItem, @socks.count, true
@@ -90,7 +91,7 @@ module ZMQ
90
91
 
91
92
  # Poll
92
93
  rc = LibZMQ::zmq_poll @poll_structs, @poll_items.count, timeout
93
- ZMQ.error_check true if rc==-1
94
+ ZMQ.error_check true if rc == -1
94
95
 
95
96
  # Create a hash of the items with triggered events.
96
97
  # (ZMQ::Socket => revents)
@@ -115,7 +116,10 @@ module ZMQ
115
116
  end
116
117
 
117
118
 
119
+ # :nodoc:
118
120
  module LibZMQ
121
+
122
+ # :nodoc:
119
123
  class PollItem
120
124
 
121
125
  # Get the event flags:
@@ -142,7 +146,7 @@ module LibZMQ
142
146
  # Set the socket to poll for events on.
143
147
  # Accepts a ZMQ::Socket or a pointer.
144
148
  def socket=(sock)
145
- self[:socket] = sock.is_a?(FFI::Pointer) ? sock : sock.ptr
149
+ self[:socket] = sock.is_a?(FFI::Pointer) ? sock : sock.to_ptr
146
150
  end
147
151
 
148
152
  end
@@ -1,12 +1,24 @@
1
1
 
2
2
  module ZMQ
3
3
 
4
+ # The proxy connects a frontend socket to a backend socket. Conceptually,
5
+ # data flows from frontend to backend. Depending on the socket types,
6
+ # replies may flow in the opposite direction. The direction is conceptual
7
+ # only; the proxy is fully symmetric and there is no technical difference
8
+ # between frontend and backend.
4
9
  class Proxy
5
10
 
11
+ # Create a running proxy object.
12
+ def self.proxy(frontend, backend, capture = nil)
13
+ new(frontend, backend, capture).tap { |p| p.run }
14
+ end
15
+
16
+ # Accepts a frontend, backend, and optional capture socket.
17
+ # See http://api.zeromq.org/4-0:zmq-proxy
6
18
  def initialize(frontend, backend, capture = nil)
7
- @frontend = frontend.nil? ? nil : frontend.ptr
8
- @backend = backend.nil? ? nil : backend.ptr
9
- @capture = capture.nil? ? nil : capture.ptr
19
+ @frontend = frontend.nil? ? nil : frontend.to_ptr
20
+ @backend = backend.nil? ? nil : backend.to_ptr
21
+ @capture = capture.nil? ? nil : capture.to_ptr
10
22
  end
11
23
 
12
24
  # Block the current thread with the event loop of the proxy
@@ -3,16 +3,22 @@ require_relative 'socket/options'
3
3
 
4
4
  module ZMQ
5
5
 
6
+ # See http://api.zeromq.org/4-0:zmq-socket
7
+ # Not thread safe.
6
8
  class Socket
7
- attr_reader :ptr
9
+
10
+ # The FFI pointer to the socket.
11
+ attr_reader :pointer
12
+ # The socket's ZMQ::Context.
8
13
  attr_reader :context
14
+ # The socket's ZeroMQ socket type (e.g. ZMQ::ROUTER).
9
15
  attr_reader :type
10
16
 
11
17
  def initialize(type, opts={})
12
18
  @context = opts.fetch :context, ZMQ::DefaultContext
13
19
  @type = type
14
- @ptr = LibZMQ.zmq_socket @context.ptr, @type
15
- ZMQ.error_check true if @ptr.null?
20
+ @pointer = LibZMQ.zmq_socket @context.pointer, @type
21
+ ZMQ.error_check true if @pointer.null?
16
22
 
17
23
  @msgptr = FFI::MemoryPointer.new LibZMQ::Message.size, 1, false
18
24
 
@@ -22,20 +28,20 @@ module ZMQ
22
28
 
23
29
  # Close the socket
24
30
  def close
25
- if @ptr
31
+ if @pointer
26
32
  ObjectSpace.undefine_finalizer self
27
33
  @temp_buffers.clear if @temp_buffers
28
34
 
29
- rc = LibZMQ.zmq_close @ptr
35
+ rc = LibZMQ.zmq_close @pointer
30
36
  ZMQ.error_check true if rc==-1
31
37
 
32
- @ptr = nil
38
+ @pointer = nil
33
39
  end
34
40
  end
35
41
 
36
- # Create a safe finalizer for the socket ptr to close on GC of the object
37
- def self.finalizer(ptr, pid)
38
- Proc.new { LibZMQ.zmq_close ptr if Process.pid == pid }
42
+ # Create a safe finalizer for the socket pointer to close on GC of the object
43
+ def self.finalizer(pointer, pid)
44
+ Proc.new { LibZMQ.zmq_close pointer if Process.pid == pid }
39
45
  end
40
46
 
41
47
  # Get the socket type name as a symbol
@@ -45,25 +51,25 @@ module ZMQ
45
51
 
46
52
  # Bind to an endpoint
47
53
  def bind(endpoint)
48
- rc = LibZMQ.zmq_bind @ptr, endpoint
54
+ rc = LibZMQ.zmq_bind @pointer, endpoint
49
55
  ZMQ.error_check true if rc==-1
50
56
  end
51
57
 
52
58
  # Connect to an endpoint
53
59
  def connect(endpoint)
54
- rc = LibZMQ.zmq_connect @ptr, endpoint
60
+ rc = LibZMQ.zmq_connect @pointer, endpoint
55
61
  ZMQ.error_check true if rc==-1
56
62
  end
57
63
 
58
64
  # Unbind from an endpoint
59
65
  def unbind(endpoint)
60
- rc = LibZMQ.zmq_unbind @ptr, endpoint
66
+ rc = LibZMQ.zmq_unbind @pointer, endpoint
61
67
  ZMQ.error_check true if rc==-1
62
68
  end
63
69
 
64
- # Disconnect to an endpoint
70
+ # Disconnect from an endpoint
65
71
  def disconnect(endpoint)
66
- rc = LibZMQ.zmq_disconnect @ptr, endpoint
72
+ rc = LibZMQ.zmq_disconnect @pointer, endpoint
67
73
  ZMQ.error_check true if rc==-1
68
74
  end
69
75
 
@@ -77,7 +83,7 @@ module ZMQ
77
83
  rc = LibZMQ.zmq_msg_init_data @msgptr, @msgbuf, size, LibC::Free, nil
78
84
  ZMQ.error_check true if rc==-1
79
85
 
80
- rc = LibZMQ.zmq_sendmsg @ptr, @msgptr, flags
86
+ rc = LibZMQ.zmq_sendmsg @pointer, @msgptr, flags
81
87
  ZMQ.error_check true if rc==-1
82
88
 
83
89
  rc = LibZMQ.zmq_msg_close @msgptr
@@ -89,7 +95,7 @@ module ZMQ
89
95
  rc = LibZMQ.zmq_msg_init @msgptr
90
96
  ZMQ.error_check true if rc==-1
91
97
 
92
- rc = LibZMQ.zmq_recvmsg @ptr, @msgptr, flags
98
+ rc = LibZMQ.zmq_recvmsg @pointer, @msgptr, flags
93
99
  ZMQ.error_check true if rc==-1
94
100
 
95
101
  str = LibZMQ.zmq_msg_data(@msgptr)
@@ -163,7 +169,7 @@ module ZMQ
163
169
  value = valptr
164
170
  end
165
171
 
166
- rc = LibZMQ.zmq_setsockopt @ptr, option, value, value.size
172
+ rc = LibZMQ.zmq_setsockopt @pointer, option, value, value.size
167
173
  ZMQ.error_check true if rc==-1
168
174
 
169
175
  value
@@ -176,7 +182,7 @@ module ZMQ
176
182
 
177
183
  value, size = get_opt_pointers type
178
184
 
179
- rc = LibZMQ.zmq_getsockopt @ptr, option, value, size
185
+ rc = LibZMQ.zmq_getsockopt @pointer, option, value, size
180
186
  ZMQ.error_check true if rc==-1
181
187
 
182
188
  if type == :string
@@ -188,6 +194,11 @@ module ZMQ
188
194
  end
189
195
  end
190
196
 
197
+ # Returns the socket's FFI pointer.
198
+ def to_ptr
199
+ @pointer
200
+ end
201
+
191
202
  private
192
203
 
193
204
  def get_opt_pointers(type)
@@ -0,0 +1,102 @@
1
+
2
+ module ZMQ
3
+
4
+ # Returns a ZMQ::Version object containing the libzmq library version.
5
+ def self.version
6
+ ZMQ::Version
7
+ end
8
+
9
+
10
+ # libzmq library version.
11
+ class Version
12
+
13
+ @version = LibZMQ.version
14
+
15
+ private_class_method :new
16
+
17
+ class << self
18
+
19
+ # :nodoc:
20
+ def major
21
+ @version[:major]
22
+ end
23
+
24
+ # :nodoc:
25
+ def minor
26
+ @version[:minor]
27
+ end
28
+
29
+ # :nodoc:
30
+ def patch
31
+ @version[:patch]
32
+ end
33
+
34
+ # :nodoc:
35
+ def to_s
36
+ "#{major}.#{minor}.#{patch}"
37
+ end
38
+
39
+ # :nodoc:
40
+ def inspect
41
+ "#{super} \"#{to_s}\""
42
+ end
43
+
44
+ # Compare this version to another version.
45
+ # Examples: "3.2.0", "3.2", "3", 3
46
+ def <=>(value)
47
+ expression = /(?<major>\d+)(\.(?<minor>\d+))?(\.(?<patch>\d+))?/
48
+
49
+ # Convert both versions into an array of [major, minor, patch].
50
+ this_version = self.to_s
51
+ other_version = value.to_s
52
+
53
+ this_version =~ expression
54
+ this_set = $~.captures.map { |item| item.to_i if item }.select { |item| item }
55
+
56
+ other_version =~ expression
57
+ other_set = $~.captures.map { |item| item.to_i if item }.select { |item| item }
58
+
59
+ # Compare each section (major/minor/patch) of the version number.
60
+ other_set.count.times do |i|
61
+ return 1 if this_set[i] > other_set[i]
62
+ return -1 if this_set[i] < other_set[i]
63
+ end
64
+
65
+ 0 # If the iterator didn't return, the versions are equal.
66
+ end
67
+
68
+ # :nodoc:
69
+ def ==(value)
70
+ (self <=> value) == 0 ? true : false
71
+ end
72
+
73
+ # :nodoc:
74
+ def !=(value)
75
+ (self <=> value) != 0 ? true : false
76
+ end
77
+
78
+ # :nodoc:
79
+ def >(value)
80
+ (self <=> value) == 1 ? true : false
81
+ end
82
+
83
+ # :nodoc:
84
+ def >=(value)
85
+ (self <=> value) != -1 ? true : false
86
+ end
87
+
88
+ # :nodoc:
89
+ def <(value)
90
+ (self <=> value) == -1 ? true : false
91
+ end
92
+
93
+ # :nodoc:
94
+ def <=(value)
95
+ (self <=> value) != 1 ? true : false
96
+ end
97
+
98
+ end
99
+
100
+ end
101
+
102
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: 0mq
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe McIlvain
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-03-04 00:00:00.000000000 Z
12
+ date: 2014-03-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ffi-rzmq-core
@@ -119,11 +119,13 @@ files:
119
119
  - README.md
120
120
  - lib/0mq.rb
121
121
  - lib/0mq/context.rb
122
+ - lib/0mq/curve.rb
122
123
  - lib/0mq/error_map.rb
123
124
  - lib/0mq/poll.rb
124
125
  - lib/0mq/proxy.rb
125
126
  - lib/0mq/socket.rb
126
127
  - lib/0mq/socket/options.rb
128
+ - lib/0mq/version.rb
127
129
  homepage: https://github.com/jemc/0mq/
128
130
  licenses:
129
131
  - MIT