omf_common 6.0.0.pre.10 → 6.0.0.pre.11

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.
Files changed (41) hide show
  1. data/bin/monitor_topic.rb +80 -0
  2. data/bin/send_create.rb +94 -0
  3. data/bin/send_request.rb +58 -0
  4. data/example/engine_alt.rb +136 -0
  5. data/example/vm_alt.rb +65 -0
  6. data/lib/omf_common.rb +224 -3
  7. data/lib/omf_common/comm.rb +113 -46
  8. data/lib/omf_common/comm/amqp/amqp_communicator.rb +76 -0
  9. data/lib/omf_common/comm/amqp/amqp_topic.rb +91 -0
  10. data/lib/omf_common/comm/local/local_communicator.rb +64 -0
  11. data/lib/omf_common/comm/local/local_topic.rb +42 -0
  12. data/lib/omf_common/comm/topic.rb +190 -0
  13. data/lib/omf_common/{dsl/xmpp.rb → comm/xmpp/communicator.rb} +93 -53
  14. data/lib/omf_common/comm/xmpp/topic.rb +147 -0
  15. data/lib/omf_common/{dsl → comm/xmpp}/xmpp_mp.rb +2 -0
  16. data/lib/omf_common/eventloop.rb +94 -0
  17. data/lib/omf_common/eventloop/em.rb +57 -0
  18. data/lib/omf_common/eventloop/local_evl.rb +78 -0
  19. data/lib/omf_common/message.rb +112 -229
  20. data/lib/omf_common/message/json/json_message.rb +129 -0
  21. data/lib/omf_common/message/xml/message.rb +410 -0
  22. data/lib/omf_common/message/xml/relaxng_schema.rb +17 -0
  23. data/lib/omf_common/message/xml/topic_message.rb +20 -0
  24. data/lib/omf_common/protocol/6.0.rnc +11 -21
  25. data/lib/omf_common/protocol/6.0.rng +52 -119
  26. data/lib/omf_common/version.rb +1 -1
  27. data/omf_common.gemspec +4 -2
  28. data/test/fixture/pubsub.rb +19 -19
  29. data/test/omf_common/{dsl/xmpp_spec.rb → comm/xmpp/communicator_spec.rb} +47 -111
  30. data/test/omf_common/comm/xmpp/topic_spec.rb +113 -0
  31. data/test/omf_common/comm_spec.rb +1 -0
  32. data/test/omf_common/message/xml/message_spec.rb +136 -0
  33. data/test/omf_common/message_spec.rb +37 -131
  34. data/test/test_helper.rb +4 -1
  35. metadata +38 -28
  36. data/lib/omf_common/core_ext/object.rb +0 -21
  37. data/lib/omf_common/relaxng_schema.rb +0 -17
  38. data/lib/omf_common/topic.rb +0 -34
  39. data/lib/omf_common/topic_message.rb +0 -20
  40. data/test/omf_common/topic_message_spec.rb +0 -114
  41. data/test/omf_common/topic_spec.rb +0 -75
@@ -1,65 +1,132 @@
1
- require 'omf_common/dsl/xmpp'
2
- require 'omf_common/dsl/xmpp_mp'
3
-
1
+ require 'omf_common/comm/topic'
4
2
 
5
3
  module OmfCommon
6
4
  # PubSub communication class, can be extended with different implementations
7
5
  class Comm
8
- attr_accessor :published_messages
9
6
 
10
- def initialize(pubsub_implementation)
11
- @published_messages = []
12
- self.extend("OmfCommon::DSL::#{pubsub_implementation.to_s.camelize}".constantize)
13
- end
7
+ @@providers = {
8
+ xmpp: {
9
+ require: 'omf_common/comm/xmpp/communicator',
10
+ constructor: 'OmfCommon::Comm::XMPP::Communicator',
11
+ message_provider: {
12
+ type: :xml
13
+ }
14
+ },
15
+ amqp: {
16
+ require: 'omf_common/comm/amqp/amqp_communicator',
17
+ constructor: 'OmfCommon::Comm::AMQP::Communicator',
18
+ message_provider: {
19
+ type: :json
20
+ }
21
+ },
22
+ local: {
23
+ require: 'omf_common/comm/local/local_communicator',
24
+ constructor: 'OmfCommon::Comm::Local::Communicator',
25
+ message_provider: {
26
+ type: :json
27
+ }
28
+ }
29
+ }
30
+ @@instance = nil
14
31
 
15
- # Generate OMF related message
16
- %w(create configure request inform release).each do |m_name|
17
- define_method("#{m_name}_message") do |*args, &block|
18
- message =
19
- if block
20
- Message.send(m_name, *args, &block)
21
- elsif args[0].kind_of? Array
22
- Message.send(m_name) do |v|
23
- args[0].each do |opt|
24
- if opt.kind_of? Hash
25
- opt.each_pair do |key, value|
26
- v.property(key, value)
27
- end
28
- else
29
- v.property(opt)
30
- end
31
- end
32
- end
33
- else
34
- Message.send(m_name)
32
+ #
33
+ # opts:
34
+ # :type - pre installed comms provider
35
+ # :provider - custom provider (opts)
36
+ # :require - gem to load first (opts)
37
+ # :constructor - Class implementing provider
38
+ #
39
+ def self.init(opts)
40
+ if @@instance
41
+ raise "Comms layer already initialised"
42
+ end
43
+ unless provider = opts[:provider]
44
+ unless type = opts[:type]
45
+ if url = opts[:url]
46
+ type = url.split(':')[0].to_sym
35
47
  end
48
+ end
49
+ provider = @@providers[type]
50
+ end
51
+ unless provider
52
+ raise "Missing Comm provider declaration. Either define 'type', 'provider', or 'url'"
53
+ end
36
54
 
37
- OmfCommon::TopicMessage.new(message, self)
55
+ require provider[:require] if provider[:require]
56
+
57
+ if class_name = provider[:constructor]
58
+ provider_class = class_name.split('::').inject(Object) {|c,n| c.const_get(n) }
59
+ inst = provider_class.new(opts)
60
+ else
61
+ raise "Missing communicator creation info - :constructor"
38
62
  end
63
+ @@instance = inst
64
+ Message.init(provider[:message_provider])
65
+ inst.init(opts)
39
66
  end
40
67
 
41
- %w(created status released failed).each do |inform_type|
42
- define_method("on_#{inform_type}_message") do |*args, &message_block|
43
- msg_id = args[0].msg_id if args[0]
44
- event_block = proc do |event|
45
- message_block.call(Message.parse(event.items.first.payload))
46
- end
47
- guard_block = proc do |event|
48
- (event.items?) && (!event.delayed?) &&
49
- event.items.first.payload &&
50
- (omf_message = Message.parse(event.items.first.payload)) &&
51
- omf_message.operation == :inform &&
52
- omf_message.read_content(:inform_type) == inform_type.upcase &&
53
- (msg_id ? (omf_message.context_id == msg_id) : true)
68
+ def self.instance
69
+ @@instance
70
+ end
71
+
72
+ # Initialize comms layer
73
+ #
74
+ def init(opts = {})
75
+ raise "Not implemented"
76
+ end
77
+
78
+ # Shut down comms layer
79
+ def disconnect(opts = {})
80
+ raise "Not implemented"
81
+ end
82
+
83
+ def on_connected(&block)
84
+ raise "Not implemented"
85
+ end
86
+
87
+ # Create a new pubsub topic with additional configuration
88
+ #
89
+ # @param [String] topic Pubsub topic name
90
+ def create_topic(topic, opts = {})
91
+ raise "Not implemented"
92
+ end
93
+
94
+ # Delete a pubsub topic
95
+ #
96
+ # @param [String] topic Pubsub topic name
97
+ def delete_topic(topic, &block)
98
+ raise "Not implemented"
99
+ end
100
+
101
+ # Subscribe to a pubsub topic
102
+ #
103
+ # @param [String, Array] topic_name Pubsub topic name
104
+ # @param [Hash] opts
105
+ # @option opts [Boolean] :create_if_non_existent create the topic if non-existent, use this option with caution
106
+ #
107
+ def subscribe(topic_name, opts = {}, &block)
108
+ tna = (topic_name.is_a? Array) ? topic_name : [topic_name]
109
+ ta = tna.collect do |tn|
110
+ t = create_topic(tn)
111
+ if block
112
+ block.call(t)
54
113
  end
55
- topic_event(guard_block, &callback_logging(__method__, &event_block))
114
+ t
56
115
  end
116
+ ta[0]
57
117
  end
58
118
 
59
- # Return a topic object represents pubsub topic
119
+ # Return the options used to initiate this
120
+ # communicator.
60
121
  #
61
- def get_topic(topic_id)
62
- OmfCommon::Topic.new(topic_id, self)
122
+ def options()
123
+ @opts
63
124
  end
125
+
126
+ private
127
+ def initialize(opts = {})
128
+ @opts = opts
129
+ end
130
+
64
131
  end
65
132
  end
@@ -0,0 +1,76 @@
1
+ require 'amqp'
2
+ require 'omf_common/comm/amqp/amqp_topic'
3
+ #require 'omf_common/comm/monkey_patches'
4
+
5
+ module OmfCommon
6
+ class Comm
7
+ class AMQP
8
+ class Communicator < OmfCommon::Comm
9
+
10
+ # def initialize(opts = {})
11
+ # # ignore arguments
12
+ # end
13
+
14
+ # Initialize comms layer
15
+ #
16
+ def init(opts = {})
17
+ unless (@url = opts[:url])
18
+ raise "Missing 'url' option for AQMP layer"
19
+ end
20
+ @address_prefix = @url + '/'
21
+ ::AMQP.connect(@url) do |connection|
22
+ @channel = ::AMQP::Channel.new(connection)
23
+
24
+ if @on_connected_proc
25
+ @on_connected_proc.arity == 1 ? @on_connected_proc.call(self) : @on_connected_proc.call
26
+ end
27
+
28
+ OmfCommon.eventloop.on_stop do
29
+ connection.close
30
+ end
31
+ end
32
+ end
33
+
34
+ # Shut down comms layer
35
+ def disconnect(opts = {})
36
+ end
37
+
38
+ def on_connected(&block)
39
+ @on_connected_proc = block
40
+ end
41
+
42
+ # Create a new pubsub topic with additional configuration
43
+ #
44
+ # @param [String] topic Pubsub topic name
45
+ def create_topic(topic, opts = {})
46
+ raise "Topic can't be nil or empty" if topic.nil? || topic.empty?
47
+ opts = opts.dup
48
+ opts[:channel] = @channel
49
+ if topic.start_with? 'amqp:'
50
+ # absolute address
51
+ unless topic.start_with? @address_prefix
52
+ raise "Cannot subscribe to a topic from different domain (#{topic})"
53
+ end
54
+ opts[:address] = topic
55
+ topic = topic.split(@address_prefix).last
56
+ else
57
+ opts[:address] = @address_prefix + topic
58
+ end
59
+ OmfCommon::Comm::AMQP::Topic.create(topic, opts)
60
+ end
61
+
62
+ # Delete a pubsub topic
63
+ #
64
+ # @param [String] topic Pubsub topic name
65
+ def delete_topic(topic, &block)
66
+ if t = OmfCommon::CommProvider::AMQP::Topic.find(topic)
67
+ t.release
68
+ else
69
+ warn "Attempt to delete unknown topic '#{topic}"
70
+ end
71
+ end
72
+
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,91 @@
1
+
2
+
3
+ module OmfCommon
4
+ class Comm
5
+ class AMQP
6
+ class Topic < OmfCommon::Comm::Topic
7
+
8
+ # def self.address_for(name)
9
+ # "#{name}@local"
10
+ # end
11
+
12
+ def to_s
13
+ "AMQP::Topic<#{id}>"
14
+ end
15
+
16
+ def address
17
+ @address
18
+ end
19
+
20
+ # Call 'block' when topic is subscribed to underlying messaging
21
+ # infrastructure.
22
+ #
23
+ def on_subscribed(&block)
24
+ return unless block
25
+
26
+ call_now = false
27
+ @lock.synchronize do
28
+ if @subscribed
29
+ call_now = true
30
+ else
31
+ @on_subscrided_handlers << block
32
+ end
33
+ end
34
+ if call_now
35
+ after(0, &block)
36
+ end
37
+ end
38
+
39
+
40
+ private
41
+
42
+ def initialize(id, opts = {})
43
+ unless channel = opts.delete(:channel)
44
+ raise "Missing :channel option"
45
+ end
46
+ super
47
+ @address = opts[:address]
48
+ @exchange = channel.topic(id, :auto_delete => true)
49
+ @lock = Monitor.new
50
+ @subscribed = false
51
+ @on_subscrided_handlers = []
52
+
53
+ # Subscribe as well
54
+ #puts "QQ0(#{id})"
55
+ channel.queue("", :exclusive => true) do |queue|
56
+ #puts "QQ1(#{id}): #{queue}"
57
+ queue.bind(@exchange)
58
+ queue.subscribe do |headers, payload|
59
+ #puts "===(#{id}) Incoming message '#{payload}'"
60
+ msg = Message.parse(payload)
61
+ #puts "---(#{id}) Parsed message '#{msg}'"
62
+ on_incoming_message(msg)
63
+ end
64
+ # Call all accumulated on_subscribed handlers
65
+ @lock.synchronize do
66
+ @subscribed = true
67
+ @on_subscrided_handlers.each do |block|
68
+ after(0, &block)
69
+ end
70
+ @on_subscrided_handlers = nil
71
+ end
72
+ end
73
+ end
74
+
75
+
76
+ def _send_message(msg, block = nil)
77
+ super
78
+ debug "(#{id}) Send message #{msg.inspect}"
79
+ content = msg.marshall
80
+ @exchange.publish(content)
81
+ # OmfCommon.eventloop.after(0) do
82
+ # on_incoming_message(msg)
83
+ # end
84
+ end
85
+
86
+
87
+
88
+ end # class
89
+ end # module
90
+ end # module
91
+ end # module
@@ -0,0 +1,64 @@
1
+ require 'omf_common/comm/local/local_topic'
2
+ require 'omf_common/comm/monkey_patches'
3
+
4
+ module OmfCommon
5
+ class Comm
6
+ class Local
7
+ class Communicator < OmfCommon::Comm
8
+
9
+ # def initialize(opts = {})
10
+ # # ignore arguments
11
+ # end
12
+
13
+ # Initialize comms layer
14
+ #
15
+ def init(opts = {})
16
+ end
17
+
18
+ # Shut down comms layer
19
+ def disconnect(opts = {})
20
+ end
21
+
22
+ # Create a new pubsub topic with additional configuration
23
+ #
24
+ # @param [String] topic Pubsub topic name
25
+ def create_topic(topic, &block)
26
+ t = OmfCommon::Comm::Local::Topic.create(topic)
27
+ if block
28
+ block.call(t)
29
+ end
30
+ t
31
+ end
32
+
33
+ # Delete a pubsub topic
34
+ #
35
+ # @param [String] topic Pubsub topic name
36
+ def delete_topic(topic, &block)
37
+ if t = OmfCommon::CommProvider::Local::Topic.find(topic)
38
+ t.release
39
+ else
40
+ warn "Attempt to delete unknown topic '#{topic}"
41
+ end
42
+ end
43
+
44
+ def on_connected(&block)
45
+ return unless block
46
+
47
+ OmfCommon.eventloop.after(0) do
48
+ block.arity == 1 ? block.call(self) : block.call
49
+ end
50
+ end
51
+
52
+ # Publish to a pubsub topic
53
+ #
54
+ # @param [String] topic Pubsub topic name
55
+ # @param [String] message Any XML fragment to be sent as payload
56
+ # def publish(topic, message, &block)
57
+ # raise StandardError, "Invalid message" unless message.valid?
58
+ #
59
+ # end
60
+
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,42 @@
1
+
2
+
3
+ module OmfCommon
4
+ class Comm
5
+ class Local
6
+ class Topic < OmfCommon::Comm::Topic
7
+
8
+ # def self.address_for(name)
9
+ # "#{name}@local"
10
+ # end
11
+
12
+ def to_s
13
+ "Mock::Topic<#{id}>"
14
+ end
15
+
16
+ def address
17
+ "local:/#{id}"
18
+ end
19
+
20
+ def on_subscribed(&block)
21
+ return unless block
22
+
23
+ OmfCommon.eventloop.after(0) do
24
+ block.arity == 1 ? block.call(self) : block.call
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def _send_message(msg, block = nil)
31
+ super
32
+ debug "(#{id}) Send message #{msg.inspect}"
33
+ OmfCommon.eventloop.after(0) do
34
+ on_incoming_message(msg)
35
+ end
36
+ end
37
+
38
+
39
+ end # class
40
+ end # module
41
+ end # module
42
+ end # module