rservicebus2 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +64 -0
  3. data/bin/return_messages_to_source_queue +114 -0
  4. data/bin/rsb_ctl +38 -0
  5. data/bin/rservicebus2 +14 -0
  6. data/bin/rservicebus2-create +107 -0
  7. data/bin/rservicebus2-init +104 -0
  8. data/bin/rservicebus2-transport +16 -0
  9. data/bin/send_empty_message +15 -0
  10. data/lib/rservicebus.rb +59 -0
  11. data/lib/rservicebus/agent.rb +54 -0
  12. data/lib/rservicebus/appresource.rb +65 -0
  13. data/lib/rservicebus/appresource/dir.rb +29 -0
  14. data/lib/rservicebus/appresource/file.rb +8 -0
  15. data/lib/rservicebus/appresource/fluiddb.rb +24 -0
  16. data/lib/rservicebus/appresource_configure.rb +33 -0
  17. data/lib/rservicebus/audit.rb +28 -0
  18. data/lib/rservicebus/circuitbreaker.rb +79 -0
  19. data/lib/rservicebus/config.rb +168 -0
  20. data/lib/rservicebus/cron_manager.rb +76 -0
  21. data/lib/rservicebus/endpointmapping.rb +72 -0
  22. data/lib/rservicebus/errormessage.rb +14 -0
  23. data/lib/rservicebus/handler_loader.rb +162 -0
  24. data/lib/rservicebus/handler_manager.rb +131 -0
  25. data/lib/rservicebus/helper_functions.rb +85 -0
  26. data/lib/rservicebus/host.rb +487 -0
  27. data/lib/rservicebus/message.rb +78 -0
  28. data/lib/rservicebus/message/statisticoutput.rb +7 -0
  29. data/lib/rservicebus/message/subscription.rb +10 -0
  30. data/lib/rservicebus/message/verboseoutput.rb +7 -0
  31. data/lib/rservicebus/monitor.rb +61 -0
  32. data/lib/rservicebus/monitor/csvdir.rb +52 -0
  33. data/lib/rservicebus/monitor/dir.rb +139 -0
  34. data/lib/rservicebus/monitor/dirnotifier.rb +101 -0
  35. data/lib/rservicebus/monitor/message.rb +11 -0
  36. data/lib/rservicebus/monitor/xmldir.rb +11 -0
  37. data/lib/rservicebus/monitor_configure.rb +71 -0
  38. data/lib/rservicebus/mq.rb +98 -0
  39. data/lib/rservicebus/mq/beanstalk.rb +72 -0
  40. data/lib/rservicebus/resource_manager.rb +69 -0
  41. data/lib/rservicebus/saga/base.rb +17 -0
  42. data/lib/rservicebus/saga/data.rb +20 -0
  43. data/lib/rservicebus/saga/manager.rb +128 -0
  44. data/lib/rservicebus/saga_loader.rb +118 -0
  45. data/lib/rservicebus/saga_storage.rb +18 -0
  46. data/lib/rservicebus/saga_storage/dir.rb +87 -0
  47. data/lib/rservicebus/saga_storage/inmemory.rb +37 -0
  48. data/lib/rservicebus/sendat_manager.rb +33 -0
  49. data/lib/rservicebus/sendat_storage.rb +20 -0
  50. data/lib/rservicebus/sendat_storage/file.rb +37 -0
  51. data/lib/rservicebus/sendat_storage/inmemory.rb +20 -0
  52. data/lib/rservicebus/state_manager.rb +30 -0
  53. data/lib/rservicebus/state_storage.rb +18 -0
  54. data/lib/rservicebus/state_storage/dir.rb +66 -0
  55. data/lib/rservicebus/state_storage/inmemory.rb +25 -0
  56. data/lib/rservicebus/statistic_manager.rb +86 -0
  57. data/lib/rservicebus/stats.rb +68 -0
  58. data/lib/rservicebus/subscription_manager.rb +31 -0
  59. data/lib/rservicebus/subscription_storage.rb +39 -0
  60. data/lib/rservicebus/subscription_storage/file.rb +42 -0
  61. data/lib/rservicebus/subscription_storage/redis.rb +69 -0
  62. data/lib/rservicebus/subscription_storage_configure.rb +19 -0
  63. data/lib/rservicebus/test.rb +2 -0
  64. data/lib/rservicebus/test/bus.rb +32 -0
  65. data/lib/rservicebus/transporter.rb +142 -0
  66. data/lib/rservicebus/usermessage/withpayload.rb +10 -0
  67. metadata +184 -0
@@ -0,0 +1,78 @@
1
+ require 'zlib'
2
+ require 'yaml'
3
+ require 'uuidtools'
4
+
5
+ module RServiceBus
6
+ # This is the top level message that is passed around the bus
7
+ class Message
8
+ attr_reader :return_address, :msg_id, :remote_queue_name, :remote_host_name,
9
+ :last_error_source_queue, :last_error_string, :correlation_id,
10
+ :sendat
11
+
12
+ # Constructor
13
+ #
14
+ # @param [Object] msg The msg to be sent
15
+ # @param [Object] returnAddress A queue to which the destination message
16
+ # handler can send replies
17
+ def initialize(msg, return_address, correlation_id = nil)
18
+ if RServiceBus.check_environment_variable('RSBMSG_COMPRESS')
19
+ @compressed = true
20
+ @_msg = Zlib::Deflate.deflate(YAML.dump(msg))
21
+ else
22
+ @compressed = false
23
+ @_msg = YAML.dump(msg)
24
+ end
25
+
26
+ @correlation_id = correlation_id
27
+ @return_address = return_address
28
+
29
+ @createdat = DateTime.now
30
+
31
+ @msg_id = UUIDTools::UUID.random_create
32
+ @error_list = []
33
+ end
34
+
35
+ # If an error occurs while processing the message, this method allows details of the error to held
36
+ # next to the msg.
37
+ #
38
+ # Error(s) are held in an array, which allows current error information to be held, while still
39
+ # retaining historical error messages.
40
+ #
41
+ # @param [Object] source_queue The name of the queue to which the msg should be returned
42
+ # @param [Object] error_string A readible version of what occured
43
+ def add_error_msg(source_queue, error_string)
44
+ @last_error_source_queue = source_queue
45
+ @last_error_string = error_string
46
+
47
+ @error_list << RServiceBus::ErrorMessage.new(source_queue, error_string)
48
+ end
49
+
50
+ def set_remote_host_name(host_name)
51
+ @remote_host_name = host_name
52
+ end
53
+
54
+ def set_remote_queue_name(queue_name)
55
+ @remote_queue_name = queue_name
56
+ end
57
+
58
+ def send_at(timestamp)
59
+ @send_at = timestamp
60
+ end
61
+
62
+ # @return [Object] The msg to be sent
63
+ def msg
64
+ if @compressed == true
65
+ return YAML.load(Zlib::Inflate.inflate(@_msg))
66
+ else
67
+ return YAML.load( @_msg )
68
+ end
69
+ rescue ArgumentError => e
70
+ raise e if e.message.index('undefined class/module ').nil?
71
+
72
+ puts e.message
73
+ msg_name = e.message.sub('undefined class/module ', '')
74
+
75
+ raise ClassNotFoundForMsg, msg_name
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,7 @@
1
+ module RServiceBus
2
+ class MessageStatisticOutputOn
3
+ end
4
+
5
+ class MessageStatisticOutputOff
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ module RServiceBus
2
+ # Class to hold message subscriptions
3
+ class MessageSubscription
4
+ attr_reader :event_name
5
+
6
+ def initialize(event_name)
7
+ @event_name = event_name
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ module RServiceBus
2
+ class MessageVerboseOutputOn
3
+ end
4
+
5
+ class MessageVerboseOutputOff
6
+ end
7
+ end
@@ -0,0 +1,61 @@
1
+ module RServiceBus
2
+ # Monitor
3
+ class Monitor
4
+ attr_accessor :bus
5
+
6
+ # The method which actually connects to the resource.
7
+ def connect(_uri)
8
+ fail 'Method, connect, needs to be implemented for resource'
9
+ end
10
+
11
+ # The method which actually connects to the resource.
12
+ def look
13
+ fail 'Method, Look, needs to be implemented for the Monitor'
14
+ end
15
+
16
+ def _connect
17
+ @connection = connect(@uri)
18
+ @bus.log "#{self.class.name}. Connected to, #{@uri}" if
19
+ ENV['QUIET'].nil?
20
+ end
21
+
22
+ # Resources are attached resources, and can be specified using the URI
23
+ # syntax.
24
+ # @param [String] uri a location for the resource to which we will attach,
25
+ # eg redis://127.0.0.1/foo
26
+ def initialize(bus, name, uri)
27
+ @bus = bus
28
+ new_anonymous_class = Class.new(MonitorMessage)
29
+ Object.const_set(name, new_anonymous_class)
30
+ @msg_type = Object.const_get(name)
31
+
32
+ @uri = uri
33
+ _connect
34
+ end
35
+
36
+ # A notification that allows cleanup
37
+ def finished
38
+ end
39
+
40
+ # At least called in the Host rescue block, to ensure all network links
41
+ # are healthy
42
+ def reconnect
43
+ begin
44
+ finished
45
+ rescue StandardError => e
46
+ puts '** Monitor. An error was raised while closing connection to, ' +
47
+ @uri
48
+ puts 'Message: ' + e.message
49
+ puts e.backtrace
50
+ end
51
+
52
+ _connect
53
+ end
54
+
55
+ def send(payload, uri)
56
+ msg = @msg_type.new(payload, uri)
57
+
58
+ @bus.send(msg)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,52 @@
1
+ require 'rservicebus/Monitor/Dir'
2
+ require 'csv'
3
+
4
+ module RServiceBus
5
+ # Pull files and pre-parse as csv
6
+ class MonitorCsvDir < MonitorDir
7
+ def check_payload_for_number_of_columns(payload)
8
+ return if @QueryStringParts.nil?
9
+ return unless @QueryStringParts.key?('cols')
10
+
11
+ cols = @QueryStringParts['cols'][0].to_i
12
+ payload.each_with_index do |row, idx|
13
+ if row.length != cols
14
+ fail "Expected number of columns, #{cols}, Actual number of columns,
15
+ #{row.length}, on line, #{idx}"
16
+ end
17
+ end
18
+ end
19
+
20
+ def check_send_hash
21
+ if !@QueryStringParts.nil? && @QueryStringParts.key?('hash')
22
+ flag = @QueryStringParts['hash'][0]
23
+ return flag == 'Y'
24
+ end
25
+
26
+ false
27
+ end
28
+
29
+ def process_to_hash(p)
30
+ headline = payload.shift
31
+ payload = []
32
+ p.each do |csvline|
33
+ hash = {}
34
+ csvline.each_with_index do |v, idx|
35
+ hash[headline[idx]] = v
36
+ end
37
+ payload << hash
38
+ end
39
+
40
+ payload
41
+ end
42
+
43
+ def process_content(content)
44
+ payload = CSV.parse(content)
45
+ check_payload_for_number_of_columns(payload)
46
+
47
+ payload = process_to_hash(payload) if check_send_hash
48
+
49
+ payload
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,139 @@
1
+ require 'cgi'
2
+ require 'zip/zip'
3
+ require 'zlib'
4
+
5
+ module RServiceBus
6
+ # Monitor Directory for files
7
+ class MonitorDir < Monitor
8
+ def connect(uri)
9
+ # Pass the path through the Dir object to check syntax on startup
10
+ begin
11
+ input_dir = Dir.new(uri.path)
12
+ unless File.writable?(uri.path)
13
+ puts "***** Directory is not writable, #{uri.path}."
14
+ puts "***** Make the directory, #{uri.path}, writable and try again."
15
+ abort
16
+ end
17
+ rescue Errno::ENOENT
18
+ puts "***** Directory does not exist, #{uri.path}."
19
+ puts "***** Create the directory, #{uri.path}, and try again."
20
+ puts "***** eg, mkdir #{uri.path}"
21
+ abort
22
+ rescue Errno::ENOTDIR
23
+ puts "***** The specified path does not point to a directory,
24
+ #{uri.path}."
25
+ puts "***** Either repoint path to a directory, or remove, #{uri.path},
26
+ and create it as a directory."
27
+ puts "***** eg, rm #{uri.path} && mkdir #{uri.path}"
28
+ abort
29
+ end
30
+
31
+ @path = input_dir.path
32
+ @input_filter = []
33
+
34
+ return if uri.query.nil?
35
+ parts = CGI.parse(uri.query)
36
+ @querystringparts = parts
37
+ if parts.key?('archive')
38
+ archiveuri = URI.parse(parts['archive'][0])
39
+ unless File.directory?(archiveuri.path)
40
+ puts '***** Archive file name templating not yet supported.'
41
+ puts "***** Directory's only."
42
+ abort
43
+ end
44
+ @archivedir = archiveuri.path
45
+ end
46
+
47
+ return unless parts.key?('input_filter')
48
+
49
+ if parts['input_filter'].count > 1
50
+ puts 'Too many input_filters specified.'
51
+ puts '*** ZIP, or GZ are the only valid input_filters.'
52
+ abort
53
+ end
54
+
55
+ if parts['input_filter'][0] == 'ZIP'
56
+ elsif parts['input_filter'][0] == 'GZ'
57
+ elsif parts['input_filter'][0] == 'TAR'
58
+ else
59
+ puts 'Invalid input_filter specified.'
60
+ puts '*** ZIP, or GZ are the only valid input_filters.'
61
+ abort
62
+ end
63
+ @input_filter << parts['input_filter'][0]
64
+ end
65
+
66
+ def process_content(content)
67
+ content
68
+ end
69
+
70
+ def read_content_from_zip_file(file_path)
71
+ zip = Zip::ZipInputStream.open(file_path)
72
+ zip.get_next_entry
73
+ content = zip.read
74
+ zip.close
75
+
76
+ content
77
+ end
78
+
79
+ def read_content_from_gz_file(filepath)
80
+ gz = Zlib::GzipReader.open(filepath)
81
+ gz.read
82
+ end
83
+
84
+ def read_content_from_file(file_path)
85
+ content = ''
86
+ if @input_filter.length > 0
87
+ if @input_filter[0] == 'ZIP'
88
+ content = read_content_from_zip_file(file_path)
89
+ elsif @input_filter[0] == 'GZ'
90
+ content = read_content_from_gz_file(file_path)
91
+ elsif @input_filter[0] == 'TAR'
92
+ fail 'TAR reader not implemented'
93
+ end
94
+
95
+ else
96
+ content = IO.read(file_path)
97
+ end
98
+
99
+ content
100
+ end
101
+
102
+ def process_path(file_path)
103
+ content = read_content_from_file(file_path)
104
+ payload = process_content(content)
105
+
106
+ send(payload, URI.parse(URI.encode("file://#{file_path}")))
107
+ content
108
+ end
109
+
110
+ def look
111
+ file_processed = 0
112
+ max_files_processed = 10
113
+
114
+ file_list = Dir.glob("#{@path}/*")
115
+ file_list.each do |file_path|
116
+ RServiceBus.log "Ready to process, #{file_path}"
117
+ content = process_path(file_path)
118
+
119
+ unless @archivedir.nil?
120
+ basename = File.basename(file_path)
121
+ new_file_path = "#{@archivedir}/#{basename}.
122
+ #{DateTime.now.strftime('%Y%m%d%H%M%S%L')}.zip"
123
+ RServiceBus.log "Writing to archive, #{new_file_path}"
124
+
125
+ Zip::ZipOutputStream.open(new_file_path) do |zos|
126
+ zos.put_next_entry(basename)
127
+ zos.puts content
128
+ end
129
+ end
130
+ File.unlink(file_path)
131
+
132
+ file_processed += 1
133
+ RServiceBus.log "Processed #{file_processed} of #{file_list.length}."
134
+ RServiceBus.log "Allow system tick #{self.class.name}"
135
+ break if file_processed >= max_files_processed
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,101 @@
1
+ require 'cgi'
2
+ require 'fileutils'
3
+ require 'pathname'
4
+
5
+ module RServiceBus
6
+ # Monitor for Directory
7
+ class MonitorDirNotifier < Monitor
8
+ attr_reader :Path, :ProcessingFolder, :Filter
9
+ def connect(uri)
10
+ # Pass the path through the Dir object to check syntax on startup
11
+ begin
12
+ open_folder uri.path
13
+ unless File.writable?(uri.path)
14
+ puts "***** Directory is not writable, #{uri.path}."
15
+ puts "***** Make the directory, #{uri.path}, writable and try again."
16
+ abort
17
+ end
18
+ rescue Errno::ENOENT
19
+ puts "***** Directory does not exist, #{uri.path}."
20
+ puts "***** Create the directory, #{uri.path}, and try again."
21
+ puts "***** eg, mkdir #{uri.path}"
22
+ abort
23
+ rescue Errno::ENOTDIR
24
+ puts "***** The specified path does not point to a directory,
25
+ #{uri.path}."
26
+ puts "***** Either repoint path to a directory, or remove, #{uri.path},
27
+ and create it as a directory."
28
+ puts "***** eg, rm #{uri.path} && mkdir #{uri.path}"
29
+ abort
30
+ end
31
+
32
+ @path = uri.path
33
+
34
+ if uri.query.nil?
35
+ puts '***** Processing Directory is not specified.'
36
+ puts '***** Specify the Processing Directory as a query string in the
37
+ Path URI'
38
+ puts "***** eg, '/#{uri.path}?processing=*ProcessingDir*"
39
+ abort
40
+ else
41
+ parts = CGI.parse(uri.query)
42
+
43
+ if parts.key? 'processing'
44
+ processing_uri = URI.parse parts['processing'][0]
45
+ begin
46
+ open_folder processing_uri.path
47
+ unless File.writable?(processing_uri.path)
48
+ puts "***** Processing Directory is not writable,
49
+ #{processingUri.path}."
50
+ puts "***** Make the directory, #{processingUri.path},
51
+ writable and try again."
52
+ abort
53
+ end
54
+ rescue Errno::ENOENT
55
+ puts "***** Processing Directory does not exist,
56
+ #{processingUri.path}."
57
+ puts "***** Create the directory, #{processingUri.path}, and try
58
+ again."
59
+ puts "***** eg, mkdir #{processingUri.path}"
60
+ abort
61
+ rescue Errno::ENOTDIR
62
+ puts "***** Processing Directory does not point to a directory,
63
+ #{processingUri.path}."
64
+ puts "***** Either repoint path to a directory, or remove,
65
+ #{processingUri.path}, and create it as a directory."
66
+ puts "***** eg, rm #{processingUri.path} && mkdir
67
+ #{processingUri.path}"
68
+ abort
69
+ end
70
+
71
+ @processing_folder = processing_uri.path
72
+ end
73
+
74
+ @filter = '*'
75
+ @filter = parts['filter'][0] if parts.key? 'filter'
76
+ end
77
+ end
78
+
79
+ def look
80
+ file_list = get_files
81
+ file_list.each do |file_path|
82
+ new_path = move_file(file_path, @processing_folder)
83
+ send(nil, URI.parse("file://#{new_path}"))
84
+ end
85
+ end
86
+
87
+ def open_folder(path)
88
+ Dir.new path
89
+ end
90
+
91
+ def move_file(src, dest)
92
+ FileUtils.mv(src, dest)
93
+ filename = Pathname.new(src).basename
94
+ Pathname.new(dest).join(filename)
95
+ end
96
+
97
+ def get_files
98
+ Dir.glob(Pathname.new("#{@Path}").join(@Filter) ).select { |f| File.file?(f) }
99
+ end
100
+ end
101
+ end