masstransit 0.2 → 0.2.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/lib/masstransit.rb +13 -0
- data/lib/masstransit/bus.rb +84 -0
- data/lib/masstransit/config.rb +55 -0
- data/lib/masstransit/envelope.rb +15 -0
- data/lib/masstransit/exceptions.rb +0 -0
- data/lib/masstransit/message.rb +26 -0
- data/lib/masstransit/serializer.rb +25 -0
- data/lib/masstransit/transports/amqp.rb +84 -0
- data/lib/masstransit/urn.rb +14 -0
- metadata +16 -7
data/lib/masstransit.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_support' unless defined?(ActiveSupport)
|
3
|
+
|
4
|
+
here = File.expand_path(File.dirname(__FILE__))
|
5
|
+
|
6
|
+
$LOAD_PATH << "#{here}/masstransit"
|
7
|
+
require 'bus'
|
8
|
+
require 'config'
|
9
|
+
require 'message'
|
10
|
+
require 'serializer'
|
11
|
+
require 'envelope'
|
12
|
+
require 'transports/amqp'
|
13
|
+
require 'urn'
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module MassTransit
|
2
|
+
#The bus abstracts the desired transportation, and manages the callbacks
|
3
|
+
#orchestrates the threading
|
4
|
+
#
|
5
|
+
#three main queues (data, control, poison)
|
6
|
+
class Bus
|
7
|
+
def initialize(conf)
|
8
|
+
@subscriptions = {}
|
9
|
+
@serializer = conf.serializer
|
10
|
+
@transport = conf.transport
|
11
|
+
@queue = conf.queue
|
12
|
+
|
13
|
+
@transport.open(conf)
|
14
|
+
end
|
15
|
+
|
16
|
+
#this will register an exchange in rabbit for the 'message_name'
|
17
|
+
#and then bind the queue to that exchange. it then sets
|
18
|
+
# the subscriptions[message_name] to the callback provided
|
19
|
+
def subscribe(message_name, &block)
|
20
|
+
@subscriptions = {} if @subscriptions.nil?
|
21
|
+
consumers = @subscriptions[message_name]
|
22
|
+
consumers = [] if consumers.nil?
|
23
|
+
consumers << block
|
24
|
+
@subscriptions[message_name] = consumers
|
25
|
+
@transport.bind message_name
|
26
|
+
end
|
27
|
+
|
28
|
+
#this will unregister the queue with the exchange in rabbitmq
|
29
|
+
#for the message_name. It then removes the callbacks in the
|
30
|
+
#subscriptions
|
31
|
+
def unsubscribe(message_name)
|
32
|
+
@transport.unbind(message_name, @queue)
|
33
|
+
|
34
|
+
#has key check
|
35
|
+
@subscriptions.delete(message_name)
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
#tells the bus to start listening for messages
|
40
|
+
#this method blocks forver. Need to implement
|
41
|
+
#better ctrl-c support
|
42
|
+
def start()
|
43
|
+
#start listening
|
44
|
+
@transport.monitor do |rmsg|
|
45
|
+
consume(rmsg)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def close()
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
#this will publish the message object to an exchange in rabbitmq
|
54
|
+
#that is equal to the message class name. this is a direct concept
|
55
|
+
#from .net and should be adopted into a more ruby manner
|
56
|
+
def publish(message)
|
57
|
+
envelope = @transport.create_message(message, @serializer)
|
58
|
+
data = @serializer.serialize(envelope)
|
59
|
+
|
60
|
+
@transport.publish(envelope.MessageType, data) #exchange?
|
61
|
+
end
|
62
|
+
|
63
|
+
#takes a rabbitmq message, strips off the noise and gets back to an
|
64
|
+
#envelope
|
65
|
+
def consume(rmsg)
|
66
|
+
data = @transport.get_message(rmsg)
|
67
|
+
#payload is a string
|
68
|
+
env = @serializer.deserialize data
|
69
|
+
puts 'oeuaoeusatoehuntsaoheuntsahoeusnth'
|
70
|
+
puts env
|
71
|
+
deliver(env)
|
72
|
+
end
|
73
|
+
|
74
|
+
#for local distribution
|
75
|
+
def deliver(env)
|
76
|
+
consumers = @subscriptions[env.MessageType]
|
77
|
+
consumers = [] if consumers.nil?
|
78
|
+
consumers.each do |c|
|
79
|
+
obj = @serializer.deserialize(env.Message)
|
80
|
+
c.call obj
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'transports/amqp'
|
3
|
+
require 'serializer'
|
4
|
+
|
5
|
+
module MassTransit
|
6
|
+
#A class that groups all of the configuration options and provides defaults
|
7
|
+
#Currently AMQP is the only transport option
|
8
|
+
class Config
|
9
|
+
attr_accessor :server
|
10
|
+
attr_accessor :port
|
11
|
+
attr_accessor :vdir
|
12
|
+
attr_accessor :user
|
13
|
+
attr_accessor :password
|
14
|
+
attr_accessor :insist
|
15
|
+
attr_accessor :transport
|
16
|
+
attr_accessor :serializer
|
17
|
+
attr_accessor :queue
|
18
|
+
|
19
|
+
def initialize()
|
20
|
+
@server = 'localhost'
|
21
|
+
@port = 5672
|
22
|
+
@vdir = '/'
|
23
|
+
@user = 'guest'
|
24
|
+
@password = 'guest'
|
25
|
+
@insist = true
|
26
|
+
@transport = Amqp.new()
|
27
|
+
@serializer = Serializer.new
|
28
|
+
@queue = 'default_queue'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Sample Config File
|
33
|
+
# ---
|
34
|
+
# server : localhost
|
35
|
+
# port : 5672
|
36
|
+
# vdir : /
|
37
|
+
# user : guest
|
38
|
+
# password : guest
|
39
|
+
# insist: true def load_config(file_name)
|
40
|
+
def MassTransit.load_config(file_name)
|
41
|
+
o = YAML::load_file(file_name)
|
42
|
+
cfg = Config.new
|
43
|
+
|
44
|
+
cfg.server = o['server']
|
45
|
+
cfg.port = o['port']
|
46
|
+
cfg.vdir = o['vdir']
|
47
|
+
cfg.user = o['user']
|
48
|
+
cfg.password = o['password']
|
49
|
+
cfg.insist = o['insist']
|
50
|
+
cfg.queue = o['queue']
|
51
|
+
|
52
|
+
return cfg
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module MassTransit
|
2
|
+
#a simple class to wrap the message and name
|
3
|
+
class Envelope
|
4
|
+
attr_accessor :MessageType
|
5
|
+
attr_accessor :Message
|
6
|
+
|
7
|
+
def initialize()
|
8
|
+
end
|
9
|
+
|
10
|
+
# def initialize(message_name, body)
|
11
|
+
# @message_name = message_name
|
12
|
+
# @body = body
|
13
|
+
# end
|
14
|
+
end
|
15
|
+
end
|
File without changes
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module MassTransit
|
4
|
+
|
5
|
+
#creates a method missing style dictionary for when
|
6
|
+
#i don't have the actual type availible
|
7
|
+
class Message
|
8
|
+
attr_accessor :hash
|
9
|
+
|
10
|
+
def initialize(hash)
|
11
|
+
@hash = hash
|
12
|
+
@o = OpenStruct.new hash
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(name, *args)
|
16
|
+
value = @o.send name, args
|
17
|
+
if value.class == Hash
|
18
|
+
value = Message.new value
|
19
|
+
end
|
20
|
+
return value unless value.nil?
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'ostruct'
|
3
|
+
# may want to write my own to change the json_class bit
|
4
|
+
#http://flori.github.com/json/doc/classes/Object.html#method-i-to_json
|
5
|
+
#look at the source and hack! whoot whoot
|
6
|
+
|
7
|
+
module MassTransit
|
8
|
+
|
9
|
+
class Serializer
|
10
|
+
def serialize(env)
|
11
|
+
#enforce that env is an Envelope
|
12
|
+
return ActiveSupport::JSON.encode env
|
13
|
+
end
|
14
|
+
|
15
|
+
#returns an Envelope
|
16
|
+
def deserialize(data)
|
17
|
+
result = ActiveSupport::JSON.decode(data)
|
18
|
+
|
19
|
+
result = MassTransit::Message.new(result)
|
20
|
+
|
21
|
+
result
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'bunny'
|
2
|
+
|
3
|
+
module MassTransit
|
4
|
+
#The wrapper class on top of AMQP, that provides the standard
|
5
|
+
#masstransit 'transport' api
|
6
|
+
class Amqp
|
7
|
+
|
8
|
+
#opens a connection to the Amqp server
|
9
|
+
def open(config)
|
10
|
+
@client = Bunny.new(
|
11
|
+
:logging=>true,
|
12
|
+
:host => config.server,
|
13
|
+
:port => config.port,
|
14
|
+
:user => config.user,
|
15
|
+
:pass => config.password,
|
16
|
+
:vhost => config.vdir,
|
17
|
+
:insist => config.insist
|
18
|
+
)
|
19
|
+
@queue = config.queue
|
20
|
+
@client.start
|
21
|
+
end
|
22
|
+
|
23
|
+
#closes the connection to the Amqp server
|
24
|
+
def close()
|
25
|
+
@client.close()
|
26
|
+
end
|
27
|
+
|
28
|
+
#declares a queue on the server
|
29
|
+
def queue_declare(name)
|
30
|
+
@client.queue(name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def queue_delete(name)
|
34
|
+
#how to?
|
35
|
+
end
|
36
|
+
|
37
|
+
#binds the queue to the exchange
|
38
|
+
def bind(exchange)
|
39
|
+
ex = @client.exchange(exchange, :type=>:fanout, :durable=>true)
|
40
|
+
q = @client.queue(@queue)
|
41
|
+
q.bind(ex)
|
42
|
+
end
|
43
|
+
|
44
|
+
#unbnids the queue from the exchange
|
45
|
+
def unbind(queue, exchange)
|
46
|
+
end
|
47
|
+
|
48
|
+
#creates a transport ready message object
|
49
|
+
def create_message(data, serializer)
|
50
|
+
msg_name = data.class.name.gsub("::",".")
|
51
|
+
msg = data
|
52
|
+
|
53
|
+
env = Envelope.new
|
54
|
+
env.MessageType = msg_name
|
55
|
+
#this needs to be a string for .net
|
56
|
+
env.Message = serializer.serialize(msg)
|
57
|
+
|
58
|
+
return env
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_message(rmsg)
|
62
|
+
return rmsg[:payload]
|
63
|
+
end
|
64
|
+
|
65
|
+
def monitor(&block)
|
66
|
+
#basic consume / pop loop here
|
67
|
+
q = @client.queue(@queue)
|
68
|
+
q.subscribe(:consumer_tag => 'testtag1', :timeout => 30) do |msg|
|
69
|
+
block.call msg
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
#pushes the message onto the exchange
|
75
|
+
def send(queue, data)
|
76
|
+
@client.queue(queue).publish(data)
|
77
|
+
end
|
78
|
+
|
79
|
+
def publish(exchange, data)
|
80
|
+
ex = @client.exchange(exchange, :type=>:fanout, :durable=>true)
|
81
|
+
ex.publish(data)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: masstransit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
|
9
|
+
- 2
|
10
|
+
version: 0.2.2
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- ACM,PBG,LEGO
|
@@ -14,7 +15,7 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2011-01-
|
18
|
+
date: 2011-01-12 00:00:00 -06:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
@@ -39,8 +40,16 @@ extensions: []
|
|
39
40
|
|
40
41
|
extra_rdoc_files: []
|
41
42
|
|
42
|
-
files:
|
43
|
-
|
43
|
+
files:
|
44
|
+
- ./lib/masstransit/bus.rb
|
45
|
+
- ./lib/masstransit/config.rb
|
46
|
+
- ./lib/masstransit/envelope.rb
|
47
|
+
- ./lib/masstransit/exceptions.rb
|
48
|
+
- ./lib/masstransit/message.rb
|
49
|
+
- ./lib/masstransit/serializer.rb
|
50
|
+
- ./lib/masstransit/transports/amqp.rb
|
51
|
+
- ./lib/masstransit/urn.rb
|
52
|
+
- ./lib/masstransit.rb
|
44
53
|
has_rdoc: true
|
45
54
|
homepage: http://www.masstransit.com
|
46
55
|
licenses: []
|
@@ -71,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
80
|
requirements: []
|
72
81
|
|
73
82
|
rubyforge_project: masstransit
|
74
|
-
rubygems_version: 1.
|
83
|
+
rubygems_version: 1.4.2
|
75
84
|
signing_key:
|
76
85
|
specification_version: 3
|
77
86
|
summary: a simple message framework
|