ipc_transit 0.0.1 → 0.0.2

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/bin/transitd ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+ require 'net/http'
3
+ require 'uri'
4
+ require 'ipc_transit'
5
+
6
+ $url = 'http://127.0.0.1:8726/transit_data'
7
+
8
+
9
+ def one_message
10
+ message = IPCTransit.receive('qname' => 'transitd', 'raw' => 1)
11
+ if not (serialized_message = message['serialized_wire_data'])
12
+ raise 'Message did not contain serialized_wire_data'
13
+ end
14
+ if not (wire_headers = message['wire_headers'])
15
+ raise 'Message did not contain wire_headers'
16
+ end
17
+ if not (d = wire_headers['d'])
18
+ raise 'Message did not contain required wire attribite "d"'
19
+ end
20
+ postData = Net::HTTP.post_form(URI.parse($url),
21
+ {'data'=>serialized_message})
22
+ puts postData.body
23
+ end
24
+ while 1
25
+ begin
26
+ one_message()
27
+ rescue Exception => e
28
+ puts "Exception: #{e}"
29
+ end
30
+ end
31
+
data/bin/trsend CHANGED
@@ -2,9 +2,14 @@
2
2
  require 'ipc_transit'
3
3
  require 'json'
4
4
 
5
+
5
6
  qname = ARGV[0]
6
7
  message = JSON.parse(ARGV[1])
8
+ dest = ARGV[2]
7
9
 
8
-
9
- ret = IPCTransit.send('message' => message, 'qname' => qname)
10
+ if dest.nil?
11
+ ret = IPCTransit.send('message' => message, 'qname' => qname)
12
+ else
13
+ ret = IPCTransit.send('message' => message, 'qname' => qname, 'd' => dest)
14
+ end
10
15
  puts ret
data/bin/trserver ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+ require 'webrick'
3
+ require 'ipc_transit'
4
+
5
+
6
+ class PersistAnswers < WEBrick::HTTPServlet::AbstractServlet
7
+ def do_POST(request, response)
8
+ status, content_type, body = handle_data(request)
9
+
10
+ response.status = status
11
+ response['Content-Type'] = content_type
12
+ response.body = body
13
+ end
14
+
15
+ def handle_data(request)
16
+ if (data = request.query['data'])
17
+ qname = handle_message({ 'serialized_wire_data' => data })
18
+ end
19
+ return 200, 'text/plain', "Forwarding message to queue '#{qname}'"
20
+ end
21
+ def handle_message(args)
22
+ IPCTransit.unpack_data(args)
23
+ if not (wire_headers = args['wire_headers'])
24
+ raise 'Message did not contain wire_headers'
25
+ end
26
+ if not (args['qname'] = wire_headers['q'])
27
+ raise 'Message did not contain required wire attribite "q"'
28
+ end
29
+ #at this point we should make sure the message we received
30
+ #is truly destined for this box
31
+ #we should also decrement the TTL
32
+ puts "Forwarding message to queue '#{args['qname']}'"
33
+ IPCTransit.send(args)
34
+ return args['qname']
35
+ end
36
+ end
37
+
38
+ server = WEBrick::HTTPServer.new(:Port => 8726)
39
+ server.mount '/transit_data', PersistAnswers
40
+ trap "INT" do server.shutdown end
41
+ server.start
data/lib/ipc_transit.rb CHANGED
@@ -3,7 +3,7 @@ require 'SysVIPC'
3
3
  include SysVIPC
4
4
 
5
5
  ##
6
- # Fast, serverless message queueing
6
+ # Fast, brokerless message queueing
7
7
  #
8
8
  # Author:: Dana M. Diederich (diederich@gmail.com)
9
9
  # Copyright:: Copyright (c) 2012 Dana M. Diederich
@@ -13,15 +13,18 @@ class IPCTransit
13
13
  @@queues = {}
14
14
 
15
15
  @@ipc_transit_wire_header_args = {
16
- 'e' => {
16
+ 'e' => { #encoding
17
17
  'json' => 1,
18
18
  'yaml' => 1,
19
19
  },
20
- 'c' => {
20
+ 'c' => { #compression
21
21
  'zlib' => 1,
22
22
  'snappy' => 1,
23
23
  'none' => 1,
24
24
  },
25
+ 'd' => 1, #destination address
26
+ 't' => 1, #hop TTL
27
+ 'q' => 1, #destination qname
25
28
  }
26
29
  @@ipc_transit_std_args = {
27
30
  'message' => 1,
@@ -42,14 +45,25 @@ class IPCTransit
42
45
  ret = nil
43
46
  flags = IPC_NOWAIT
44
47
  begin
48
+ if args['d']
49
+ args['q'] = args['qname']
50
+ args['qname'] = 'transitd'
51
+ if not args['t']
52
+ args['t'] = 9
53
+ end
54
+ end
45
55
  key = self.get_queue_id(args)
46
56
  mq = MessageQueue.new(key, IPC_CREAT | 0666)
47
- ret = mq.snd(1, pack_message(args), flags)
57
+ if args['serialized_wire_data'].nil?
58
+ pack_message(args)
59
+ end
60
+ ret = mq.snd(1, args['serialized_wire_data'], flags)
48
61
  rescue Exception => msg
49
62
  puts "Exception: #{msg}"
50
63
  end
51
64
  return ret
52
65
  end
66
+
53
67
  ##
54
68
  # Receive a message from a queue
55
69
  #
@@ -73,8 +87,12 @@ class IPCTransit
73
87
  mq = MessageQueue.new(key, IPC_CREAT | 0666)
74
88
  args['serialized_wire_data'] = mq.receive(0, 10000, flags)
75
89
  self.unpack_data(args)
90
+ #at this point I need to see if this is a remote transit
91
+ #if it is, then do not thaw the message proper
92
+ args['message'] = self.transit_thaw(args)
76
93
  rescue Exception => msg
77
94
  # puts "Exception: #{msg}"
95
+ # need to do something smarter with this
78
96
  end
79
97
  if args['raw']
80
98
  ret = args;
@@ -83,11 +101,21 @@ class IPCTransit
83
101
  end
84
102
  return ret
85
103
  end
104
+
86
105
  def self.all_queue_info()
87
106
  self.gather_queue_info()
88
107
  return @@queues
89
108
  end
90
109
 
110
+ ##
111
+ # Return info about all of the queues on the system
112
+ #
113
+ # Arguments: none
114
+ #
115
+ # Returns: hash. key is qname, value contains:
116
+ # qid - integer queue ID
117
+ # count - number of messages in this queue
118
+
91
119
  def self.all_queues()
92
120
  ret = {}
93
121
  self.all_queue_info().each_pair do |qname,v|
@@ -103,7 +131,38 @@ class IPCTransit
103
131
  return ret
104
132
  end
105
133
 
134
+ ##
135
+ # Unpack the wire meta data from a message
136
+ #
137
+ # Arguments:
138
+ # serialized_wire_data - the serialized message
139
+ #
140
+ # Returns: (in the passed args)
141
+ # wire_headers - all of the wire headers
142
+ # serialized_message - the message itself, still serialized
143
+
144
+ def self.unpack_data(args)
145
+ stuff = args['serialized_wire_data'].split(':')
146
+ offset = Integer(stuff.shift)
147
+ header_and_message = stuff.join(':')
148
+ if offset == 0
149
+ args['serialized_header'] = ''
150
+ else
151
+ args['serialized_header'] = header_and_message[0..offset-1]
152
+ self.thaw_wire_headers(args)
153
+ end
154
+ args['serialized_message'] = header_and_message[offset..header_and_message.length]
155
+ return true
156
+ end
157
+ #NB: I know this is all hideously inefficient. I'm still learning Ruby,
158
+ #and I'm focusing on getting this correct first.
159
+ #
160
+ #returns a serialized_message and wire_meta_data
161
+ #takes serialized_wire_data
162
+
163
+
106
164
  private
165
+
107
166
  def self.get_next_id
108
167
  new_id = 1
109
168
  @@queues.each_pair do |k,v|
@@ -197,8 +256,8 @@ class IPCTransit
197
256
  args['serialized_message'] = self.transit_freeze(args)
198
257
  self.serialize_wire_meta(args)
199
258
  l = args['serialized_wire_meta_data'].length
200
- ret = "#{l}:#{args['serialized_wire_meta_data']}#{args['serialized_message']}"
201
- return ret
259
+ args['serialized_wire_data'] = "#{l}:#{args['serialized_wire_meta_data']}#{args['serialized_message']}"
260
+ return args['serialized_wire_data']
202
261
  end
203
262
 
204
263
  def self.serialize_wire_meta(args)
@@ -221,25 +280,6 @@ class IPCTransit
221
280
  args['serialized_wire_meta_data'] = s
222
281
  end
223
282
 
224
- #NB: I know this is all hideously inefficient. I'm still learning Ruby,
225
- #and I'm focusing on getting this correct first.
226
- #
227
- #returns a serialized_message and wire_meta_data
228
- #takes serialized_wire_data
229
- def self.unpack_data(args)
230
- stuff = args['serialized_wire_data'].split(':')
231
- offset = Integer(stuff.shift)
232
- header_and_message = stuff.join(':')
233
- if offset == 0
234
- args['serialized_header'] = ''
235
- else
236
- args['serialized_header'] = header_and_message[0..offset-1]
237
- self.thaw_wire_headers(args)
238
- end
239
- args['serialized_message'] = header_and_message[offset..header_and_message.length]
240
- args['message'] = self.transit_thaw(args)
241
- return true
242
- end
243
283
 
244
284
  def self.thaw_wire_headers(args)
245
285
  h = args['serialized_header']
@@ -0,0 +1,51 @@
1
+ require 'test/unit'
2
+ require 'ipc_transit'
3
+
4
+ #kind of ghetto, but I don't have a better way right now
5
+ def drain_test_queue
6
+ begin
7
+ while ret = IPCTransit.receive('qname' => 'test_qname', 'nowait' => 1)
8
+ end
9
+ rescue Exception => msg
10
+ end
11
+ end
12
+
13
+ def run_daemon(prog)
14
+ pid = fork
15
+ if pid.nil? #child
16
+ exec "bin/#{prog}"
17
+ exit
18
+ end
19
+ return pid
20
+ end
21
+ def kill_daemon(pid)
22
+ Process.kill(9, pid)
23
+ end
24
+
25
+ class TestIPCTransit < Test::Unit::TestCase
26
+ def test_basic_remote
27
+ drain_test_queue()
28
+ IPCTransit.send('message' => { 'foo' => 'bar' }, 'qname' => 'test_qname', 'd' => '127.0.0.1')
29
+ ret = IPCTransit.receive('qname' => 'transitd', 'nowait' => 1)
30
+ assert(ret, 'IPCTransit.receive returned true')
31
+ assert_equal(ret['foo'], 'bar')
32
+ end
33
+
34
+ def test_full_remote
35
+ drain_test_queue()
36
+ begin
37
+ trserver_pid = run_daemon('trserver')
38
+ transitd_pid = run_daemon('transitd')
39
+ sleep 1
40
+ IPCTransit.send('message' => { 'foo' => 'bar' }, 'qname' => 'test_qname', 'd' => '127.0.0.1')
41
+ ret = IPCTransit.receive('qname' => 'test_qname', 'nowait' => 1)
42
+ assert(ret, 'IPCTransit.receive returned true')
43
+ assert_equal(ret['foo'], 'bar')
44
+ rescue Exception => msg
45
+ puts "Exception: #{msg}"
46
+ end
47
+ kill_daemon(transitd_pid)
48
+ kill_daemon(trserver_pid)
49
+ end
50
+ end
51
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ipc_transit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-11 00:00:00.000000000 Z
12
+ date: 2012-11-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
@@ -43,12 +43,14 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
- description: Serverless Message Queue
46
+ description: Brokerless Message Queue
47
47
  email: diederich@gmail.com
48
48
  executables:
49
49
  - trrecv
50
50
  - trsend
51
51
  - trlist
52
+ - transitd
53
+ - trserver
52
54
  extensions: []
53
55
  extra_rdoc_files: []
54
56
  files:
@@ -57,7 +59,10 @@ files:
57
59
  - bin/trrecv
58
60
  - bin/trsend
59
61
  - bin/trlist
62
+ - bin/transitd
63
+ - bin/trserver
60
64
  - test/tc_transit_simple.rb
65
+ - test/tc_transit_remote.rb
61
66
  homepage: http://rubygems.org/gems/ipc_transit
62
67
  licenses: []
63
68
  post_install_message:
@@ -81,6 +86,7 @@ rubyforge_project:
81
86
  rubygems_version: 1.8.24
82
87
  signing_key:
83
88
  specification_version: 3
84
- summary: Serverless, cross-language, fast message queue library
89
+ summary: Brokerless, cross-language, fast message queue library
85
90
  test_files:
86
91
  - test/tc_transit_simple.rb
92
+ - test/tc_transit_remote.rb