rservicebus2 0.2.10 → 0.2.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.
- checksums.yaml +4 -4
- data/lib/rservicebus2.rb +6 -4
- data/lib/rservicebus2/appresource/awss3.rb +3 -3
- data/lib/rservicebus2/appresource/awssqs.rb +2 -0
- data/lib/rservicebus2/appresource/dir.rb +3 -0
- data/lib/rservicebus2/appresource/file.rb +2 -0
- data/lib/rservicebus2/appresource/fluiddb.rb +3 -0
- data/lib/rservicebus2/appresource/fluiddb2.rb +3 -1
- data/lib/rservicebus2/config.rb +38 -29
- data/lib/rservicebus2/endpointmapping.rb +2 -4
- data/lib/rservicebus2/handler_manager.rb +1 -1
- data/lib/rservicebus2/helper_functions.rb +14 -13
- data/lib/rservicebus2/host.rb +1 -1
- data/lib/rservicebus2/message.rb +2 -0
- data/lib/rservicebus2/message/statisticoutput.rb +2 -0
- data/lib/rservicebus2/message/subscription.rb +2 -0
- data/lib/rservicebus2/message/verboseoutput.rb +2 -0
- data/lib/rservicebus2/monitor.rb +7 -7
- data/lib/rservicebus2/monitor/awss3.rb +3 -1
- data/lib/rservicebus2/monitor/awssqs.rb +9 -7
- data/lib/rservicebus2/monitor/dir.rb +24 -22
- data/lib/rservicebus2/monitor/dirnotifier.rb +3 -0
- data/lib/rservicebus2/monitor/message.rb +2 -0
- data/lib/rservicebus2/monitor/xmldir.rb +2 -0
- data/lib/rservicebus2/monitor_configure.rb +46 -36
- data/lib/rservicebus2/mq.rb +27 -30
- data/lib/rservicebus2/saga_loader.rb +27 -24
- data/lib/rservicebus2/saga_storage.rb +5 -4
- data/lib/rservicebus2/sendat_storage/file.rb +0 -1
- data/lib/rservicebus2/state_manager.rb +3 -3
- data/lib/rservicebus2/state_storage.rb +7 -6
- data/lib/rservicebus2/statistic_manager.rb +7 -3
- data/lib/rservicebus2/subscription_manager.rb +7 -5
- data/lib/rservicebus2/subscription_storage.rb +6 -5
- data/lib/rservicebus2/subscription_storage/file.rb +5 -18
- data/lib/rservicebus2/subscription_storage_configure.rb +2 -0
- data/lib/rservicebus2/transporter.rb +63 -52
- metadata +2 -3
- data/lib/rservicebus2/stats.rb +0 -68
@@ -17,15 +17,15 @@ module RServiceBus2
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def begin
|
20
|
-
@state_storage
|
20
|
+
@state_storage&.begin
|
21
21
|
end
|
22
22
|
|
23
23
|
def get(handler)
|
24
|
-
@state_storage
|
24
|
+
@state_storage&.get(handler)
|
25
25
|
end
|
26
26
|
|
27
27
|
def commit
|
28
|
-
@state_storage
|
28
|
+
@state_storage&.commit
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -1,17 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RServiceBus2
|
2
4
|
# State Storage
|
3
5
|
class StateStorage
|
4
6
|
def self.get(uri)
|
5
7
|
case uri.scheme
|
6
8
|
when 'dir'
|
7
|
-
require 'rservicebus2/state_storage/dir
|
8
|
-
|
9
|
+
require 'rservicebus2/state_storage/dir'
|
10
|
+
StateStorageDir.new(uri)
|
9
11
|
when 'inmem'
|
10
|
-
require 'rservicebus2/state_storage/inmemory
|
11
|
-
|
12
|
+
require 'rservicebus2/state_storage/inmemory'
|
13
|
+
StateStorageInMemory.new(uri)
|
12
14
|
else
|
13
|
-
abort("Scheme, #{uri.scheme}, not recognised when configuring
|
14
|
-
StateStorage, #{uri}")
|
15
|
+
abort("Scheme, #{uri.scheme}, not recognised when configuring StateStorage, #{uri}")
|
15
16
|
end
|
16
17
|
end
|
17
18
|
end
|
@@ -1,8 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RServiceBus2
|
2
4
|
# Used to collect various run time stats for runtime reporting
|
3
5
|
class StatisticManager
|
4
6
|
attr_accessor :output
|
5
7
|
|
8
|
+
# rubocop:disable Metrics/MethodLength
|
6
9
|
def initialize(host)
|
7
10
|
@host = host
|
8
11
|
@hash = {}
|
@@ -20,6 +23,7 @@ module RServiceBus2
|
|
20
23
|
RServiceBus2.get_value('STAT_OUTPUT_COUNTDOWN', '1').to_i
|
21
24
|
@stat_output_countdown = 0
|
22
25
|
end
|
26
|
+
# rubocop:enable Metrics/MethodLength
|
23
27
|
|
24
28
|
def inc_total_processed
|
25
29
|
@total_processed += 1
|
@@ -51,7 +55,7 @@ module RServiceBus2
|
|
51
55
|
@total_by_message_type[class_name] += 1
|
52
56
|
end
|
53
57
|
|
54
|
-
def
|
58
|
+
def internal_formatted_reporting
|
55
59
|
return unless @written == false
|
56
60
|
|
57
61
|
@written = true
|
@@ -63,7 +67,7 @@ module RServiceBus2
|
|
63
67
|
types
|
64
68
|
end
|
65
69
|
|
66
|
-
def
|
70
|
+
def formatted_reporting
|
67
71
|
"T:#{@total_processed};" \
|
68
72
|
"E:#{@total_errored};" \
|
69
73
|
"S:#{@total_sent};" \
|
@@ -72,7 +76,7 @@ module RServiceBus2
|
|
72
76
|
end
|
73
77
|
|
74
78
|
def report
|
75
|
-
@host.log(
|
79
|
+
@host.log(formatted_reporting) if @output
|
76
80
|
end
|
77
81
|
|
78
82
|
def tick
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RServiceBus2
|
2
4
|
# Subscription Manager
|
3
5
|
class SubscriptionManager
|
4
6
|
def initialize(subscription_storage)
|
5
7
|
@subscription_storage = subscription_storage
|
6
|
-
@subscriptions = @subscription_storage.
|
8
|
+
@subscriptions = @subscription_storage.all
|
7
9
|
end
|
8
10
|
|
9
11
|
# Get subscriptions for given eventName
|
@@ -11,7 +13,8 @@ module RServiceBus2
|
|
11
13
|
subscriptions = @subscriptions[event_name]
|
12
14
|
if subscriptions.nil?
|
13
15
|
RServiceBus2.log "No subscribers for event, #{event_name}"
|
14
|
-
RServiceBus2.log
|
16
|
+
RServiceBus2.log 'If there should be, ensure you have the appropriate evironment variable set, ' \
|
17
|
+
"eg MESSAGE_ENDPOINT_MAPPINGS=#{event_name}:<Queue Name>"
|
15
18
|
return []
|
16
19
|
end
|
17
20
|
|
@@ -19,13 +22,12 @@ module RServiceBus2
|
|
19
22
|
end
|
20
23
|
|
21
24
|
def add(event_name, queue_name)
|
22
|
-
RServiceBus2.log
|
23
|
-
event_name + ', to, ' + queue_name
|
25
|
+
RServiceBus2.log "Adding subscription for, #{event_name}, to, #{queue_name}"
|
24
26
|
@subscriptions = @subscription_storage.add(event_name, queue_name)
|
25
27
|
end
|
26
28
|
|
27
29
|
def remove(_event_name, _queue_name)
|
28
|
-
|
30
|
+
raise 'Method, remove, needs to be implemented for this subscription storage'
|
29
31
|
end
|
30
32
|
end
|
31
33
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
|
3
5
|
module RServiceBus2
|
@@ -14,8 +16,8 @@ module RServiceBus2
|
|
14
16
|
end
|
15
17
|
|
16
18
|
# Get a list of all subscription, as an Array
|
17
|
-
def
|
18
|
-
|
19
|
+
def all
|
20
|
+
raise 'Method, all, needs to be implemented for SubscriptionStorage'
|
19
21
|
end
|
20
22
|
|
21
23
|
# Add a new subscription
|
@@ -23,7 +25,7 @@ module RServiceBus2
|
|
23
25
|
# has asked for notification
|
24
26
|
# @param [String] queue_name the queue to which the event should be sent
|
25
27
|
def add(_event_name, _queue_name)
|
26
|
-
|
28
|
+
raise 'Method, add, needs to be implemented for this subscription storage'
|
27
29
|
end
|
28
30
|
|
29
31
|
# Remove an existing subscription
|
@@ -32,8 +34,7 @@ module RServiceBus2
|
|
32
34
|
# has asked for notification
|
33
35
|
# @param [String] queue_name the queue to which the event should be sent
|
34
36
|
def remove(_event_name, _queue_name)
|
35
|
-
|
36
|
-
storage'
|
37
|
+
raise 'Method, remove, needs to be implemented for this subscription storage'
|
37
38
|
end
|
38
39
|
end
|
39
40
|
end
|
@@ -1,15 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RServiceBus2
|
2
4
|
# Implementation of Subscription Storage to Redis
|
3
5
|
class SubscriptionStorageFile < SubscriptionStorage
|
4
|
-
|
5
|
-
#
|
6
|
-
# @param [String] app_ame Name of the application, used as a Namespace
|
7
|
-
# @param [String] uri resource location to attach, eg redis://127.0.0.1/foo
|
8
|
-
def initialize(app_name, uri)
|
9
|
-
super(app_name, uri)
|
10
|
-
end
|
11
|
-
|
12
|
-
def get_all
|
6
|
+
def all
|
13
7
|
RServiceBus2.log 'Load subscriptions'
|
14
8
|
return {} unless File.exist?(@uri.path)
|
15
9
|
|
@@ -17,13 +11,7 @@ module RServiceBus2
|
|
17
11
|
end
|
18
12
|
|
19
13
|
def add(event_name, queue_name)
|
20
|
-
|
21
|
-
if File.exist?(@uri.path)
|
22
|
-
s = YAML.load(File.open(@uri.path))
|
23
|
-
else
|
24
|
-
s = {}
|
25
|
-
end
|
26
|
-
|
14
|
+
s = File.exist?(@uri.path) ? YAML.load(File.open(@uri.path)) : {}
|
27
15
|
s[event_name] = [] if s[event_name].nil?
|
28
16
|
|
29
17
|
s[event_name] << queue_name
|
@@ -35,8 +23,7 @@ module RServiceBus2
|
|
35
23
|
end
|
36
24
|
|
37
25
|
def remove(_event_name, _queue_name)
|
38
|
-
|
39
|
-
subscription storage'
|
26
|
+
raise 'Method, remove, needs to be implemented for this subscription storage'
|
40
27
|
end
|
41
28
|
end
|
42
29
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'beanstalk-client'
|
2
4
|
require 'rservicebus2'
|
3
5
|
require 'net/ssh/gateway'
|
@@ -8,13 +10,15 @@ module RServiceBus2
|
|
8
10
|
|
9
11
|
# TODO: Poison Message? Can I bury with timeout in beanstalk ?
|
10
12
|
# Needs to end up on an error queue, destination queue may be down.
|
13
|
+
# rubocop:disable Metrics/ClassLength
|
11
14
|
class Transporter
|
12
15
|
def get_value(name, default = nil)
|
13
|
-
value =
|
16
|
+
value = ENV[name].nil? || ENV[name] == '' ? default : ENV[name]
|
14
17
|
RServiceBus2.log "Env value: #{name}: #{value}"
|
15
18
|
value
|
16
19
|
end
|
17
20
|
|
21
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
18
22
|
def connect_to_source_beanstalk
|
19
23
|
source_queue_name = get_value('SOURCE_QUEUE_NAME', 'transport-out')
|
20
24
|
source_url = get_value('SOURCE_URL', '127.0.0.1:11300')
|
@@ -22,7 +26,6 @@ module RServiceBus2
|
|
22
26
|
@source.watch source_queue_name
|
23
27
|
|
24
28
|
RServiceBus2.log "Connected to, #{source_queue_name}@#{source_url}"
|
25
|
-
|
26
29
|
rescue StandardError => e
|
27
30
|
puts 'Error connecting to Beanstalk'
|
28
31
|
puts "Host string, #{sourceUrl}"
|
@@ -35,71 +38,79 @@ module RServiceBus2
|
|
35
38
|
end
|
36
39
|
abort
|
37
40
|
end
|
41
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
38
42
|
|
39
43
|
def disconnect
|
40
44
|
RServiceBus2.log "Disconnect from,
|
41
45
|
#{@remote_user_name}@#{@remote_host_name}/#{@remote_queue_name}"
|
42
|
-
@gateway
|
46
|
+
@gateway&.shutdown!
|
43
47
|
@gateway = nil
|
44
48
|
@remote_host_name = nil
|
45
49
|
|
46
|
-
@destination
|
50
|
+
@destination&.close
|
47
51
|
@destination = nil
|
48
52
|
|
49
53
|
@remote_user_name = nil
|
50
54
|
@remote_queue_name = nil
|
51
55
|
end
|
52
56
|
|
57
|
+
# rubocop:disable Metrics/MethodLength
|
58
|
+
def connect_local
|
59
|
+
@local_port = get_value('LOCAL_PORT', 27_018).to_i
|
60
|
+
RServiceBus2.rlog "Local Port: #{@local_port}"
|
61
|
+
|
62
|
+
RServiceBus2.log "Connect SSH, #{@remote_user_name}@#{@remoteHostName}"
|
63
|
+
# Open port 27018 to forward to 127.0.0.11300 on the remote host
|
64
|
+
@gateway = Net::SSH::Gateway.new(@remote_host_name, @remote_user_name)
|
65
|
+
@gateway.open('127.0.0.1', 11_300, @local_port)
|
66
|
+
RServiceBus2.log "Connected to SSH, #{@remote_user_name}@#{@remote_host_name}"
|
67
|
+
rescue Errno::EADDRINUSE
|
68
|
+
puts "*** Local transport port in use, #{@local_port}"
|
69
|
+
puts "*** Change local transport port, #{@localPort}, using format, LOCAL_PORT=#{@localPort + 1}"
|
70
|
+
abort
|
71
|
+
rescue Errno::EACCES
|
72
|
+
puts "*** Local transport port specified, #{@local_port}, needs sudo access"
|
73
|
+
puts '*** Change local transport port using format, LOCAL_PORT=27018'
|
74
|
+
abort
|
75
|
+
end
|
76
|
+
# rubocop:enable Metrics/MethodLength
|
77
|
+
|
78
|
+
def connect_destination
|
79
|
+
destination_url = "127.0.0.1:#{@local_port}"
|
80
|
+
RServiceBus2.rlog "Connect to Remote Beanstalk, #{destination_url}"
|
81
|
+
@destination = Beanstalk::Pool.new([destinationUrl])
|
82
|
+
RServiceBus2.rlog "Connected to Remote Beanstalk, #{destination_url}"
|
83
|
+
rescue StandardError => e
|
84
|
+
if e.message == 'Beanstalk::NotConnected'
|
85
|
+
puts "***Could not connect to destination, check beanstalk is running at, #{destination_url}"
|
86
|
+
raise CouldNotConnectToDestination
|
87
|
+
end
|
88
|
+
raise
|
89
|
+
end
|
90
|
+
|
91
|
+
def pull_config(remote_host_name)
|
92
|
+
@remote_host_name = remote_host_name
|
93
|
+
@remote_user_name = get_value("REMOTE_USER_#{remote_host_name.upcase}")
|
94
|
+
return unless @remote_user_name.nil?
|
95
|
+
|
96
|
+
RServiceBus2.log "**** Username not specified for Host, #{remoteHostName}"
|
97
|
+
RServiceBus2.log "**** Add an environment variable of the form, REMOTE_USER_#{remoteHostName.upcase}=[USERNAME]"
|
98
|
+
abort
|
99
|
+
end
|
100
|
+
|
53
101
|
def connect(remote_host_name)
|
54
102
|
RServiceBus2.rlog "connect called, #{remote_host_name}"
|
55
|
-
if @gateway.nil? || remoteHostName != @remote_host_name || @destination.nil?
|
56
|
-
disconnect
|
57
|
-
end
|
103
|
+
disconnect if @gateway.nil? || remoteHostName != @remote_host_name || @destination.nil?
|
58
104
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
RServiceBus2.log "**** Add an environment variable of the form, REMOTE_USER_#{remoteHostName.upcase}=[USERNAME]"
|
66
|
-
abort
|
67
|
-
end
|
68
|
-
|
69
|
-
@local_port = get_value('LOCAL_PORT', 27018).to_i
|
70
|
-
RServiceBus2.rlog "Local Port: #{@local_port}"
|
71
|
-
begin
|
72
|
-
RServiceBus2.log "Connect SSH, #{@remote_user_name}@#{@remoteHostName}"
|
73
|
-
# Open port 27018 to forward to 127.0.0.11300 on the remote host
|
74
|
-
@gateway = Net::SSH::Gateway.new(@remote_host_name, @remote_user_name)
|
75
|
-
@gateway.open('127.0.0.1', 11300, @local_port)
|
76
|
-
RServiceBus2.log "Connected to SSH, #{@remote_user_name}@#{@remote_host_name}"
|
77
|
-
|
78
|
-
rescue Errno::EADDRINUSE
|
79
|
-
puts "*** Local transport port in use, #{@local_port}"
|
80
|
-
puts "*** Change local transport port, #{@localPort}, using format, LOCAL_PORT=#{@localPort+1}"
|
81
|
-
abort
|
82
|
-
rescue Errno::EACCES
|
83
|
-
puts "*** Local transport port specified, #{@local_port}, needs sudo access"
|
84
|
-
puts '*** Change local transport port using format, LOCAL_PORT=27018'
|
85
|
-
abort
|
86
|
-
end
|
87
|
-
|
88
|
-
begin
|
89
|
-
destination_url = "127.0.0.1:#{@local_port}"
|
90
|
-
RServiceBus2.rlog "Connect to Remote Beanstalk, #{destination_url}"
|
91
|
-
@destination = Beanstalk::Pool.new([destinationUrl])
|
92
|
-
RServiceBus2.rlog "Connected to Remote Beanstalk, #{destination_url}"
|
93
|
-
rescue StandardError => e
|
94
|
-
if e.message == 'Beanstalk::NotConnected'
|
95
|
-
puts "***Could not connect to destination, check beanstalk is running at, #{destination_url}"
|
96
|
-
raise CouldNotConnectToDestination
|
97
|
-
end
|
98
|
-
raise
|
99
|
-
end
|
100
|
-
end
|
105
|
+
return unless @gateway.nil?
|
106
|
+
|
107
|
+
# Get destination url from job
|
108
|
+
pull_config(remote_host_name)
|
109
|
+
connect_local
|
110
|
+
connect_destination
|
101
111
|
end
|
102
112
|
|
113
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
103
114
|
def process
|
104
115
|
# Get the next job from the source queue
|
105
116
|
job = @source.reserve @timeout
|
@@ -129,14 +140,14 @@ module RServiceBus2
|
|
129
140
|
end
|
130
141
|
raise e
|
131
142
|
end
|
143
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
132
144
|
|
133
145
|
def run
|
134
146
|
@timeout = get_value('TIMEOUT', 5)
|
135
147
|
connectToSourceBeanstalk
|
136
|
-
|
137
|
-
process
|
138
|
-
end
|
148
|
+
loop { process }
|
139
149
|
disconnect_from_remote_ssh
|
140
150
|
end
|
141
151
|
end
|
152
|
+
# rubocop:enable Metrics/ClassLength
|
142
153
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rservicebus2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Guy Irvine
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-05-
|
11
|
+
date: 2021-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: beanstalk-client
|
@@ -156,7 +156,6 @@ files:
|
|
156
156
|
- lib/rservicebus2/state_storage/dir.rb
|
157
157
|
- lib/rservicebus2/state_storage/inmemory.rb
|
158
158
|
- lib/rservicebus2/statistic_manager.rb
|
159
|
-
- lib/rservicebus2/stats.rb
|
160
159
|
- lib/rservicebus2/subscription_manager.rb
|
161
160
|
- lib/rservicebus2/subscription_storage.rb
|
162
161
|
- lib/rservicebus2/subscription_storage/file.rb
|
data/lib/rservicebus2/stats.rb
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
module RServiceBus2
|
2
|
-
# Used to collect various run time stats for runtime reporting
|
3
|
-
class Stats
|
4
|
-
def initialize
|
5
|
-
@hash = {}
|
6
|
-
|
7
|
-
@total_processed = 0
|
8
|
-
@total_errored = 0
|
9
|
-
@total_sent = 0
|
10
|
-
@total_published = 0
|
11
|
-
@total_reply = 0
|
12
|
-
|
13
|
-
@total_by_message_type = {}
|
14
|
-
|
15
|
-
@written = false
|
16
|
-
end
|
17
|
-
|
18
|
-
def inc_total_processed
|
19
|
-
@total_processed += 1
|
20
|
-
end
|
21
|
-
|
22
|
-
def inc_total_errored
|
23
|
-
@total_errored += 1
|
24
|
-
end
|
25
|
-
|
26
|
-
def inc_total_sent
|
27
|
-
@total_sent += 1
|
28
|
-
end
|
29
|
-
|
30
|
-
def inc_total_published
|
31
|
-
@total_published += 1
|
32
|
-
end
|
33
|
-
|
34
|
-
def inc_total_reply
|
35
|
-
@total_reply += 1
|
36
|
-
end
|
37
|
-
|
38
|
-
def inc(key)
|
39
|
-
@hash[key] = 0 if @hash[key].nil?
|
40
|
-
@hash[key] += 1
|
41
|
-
end
|
42
|
-
|
43
|
-
def inc_message_type(class_name)
|
44
|
-
@total_by_message_type[class_name] = 0 if @total_by_message_type[class_name].nil?
|
45
|
-
@total_by_message_type[class_name] += 1
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def get_for_reporting_2
|
50
|
-
return unless @written == false
|
51
|
-
|
52
|
-
@written = true
|
53
|
-
types = Hash.new(0)
|
54
|
-
ObjectSpace.each_object do |obj|
|
55
|
-
types[obj.class] += 1
|
56
|
-
end
|
57
|
-
|
58
|
-
types
|
59
|
-
end
|
60
|
-
|
61
|
-
def get_for_reporting
|
62
|
-
"T:#{@total_processed};
|
63
|
-
E:#{@total_errored};
|
64
|
-
S:#{@total_sent};
|
65
|
-
P:#{@total_published};
|
66
|
-
R:#{@total_reply}"
|
67
|
-
end
|
68
|
-
end
|