gitlab-mail_room 0.0.8 → 0.0.9
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/.gitlab-ci.yml +9 -1
- data/README.md +15 -0
- data/lib/mail_room.rb +2 -0
- data/lib/mail_room/cli.rb +1 -1
- data/lib/mail_room/configuration.rb +11 -1
- data/lib/mail_room/connection.rb +7 -181
- data/lib/mail_room/coordinator.rb +8 -4
- data/lib/mail_room/crash_handler.rb +0 -1
- data/lib/mail_room/health_check.rb +60 -0
- data/lib/mail_room/imap.rb +8 -0
- data/lib/mail_room/imap/connection.rb +200 -0
- data/lib/mail_room/imap/message.rb +19 -0
- data/lib/mail_room/mailbox.rb +5 -4
- data/lib/mail_room/mailbox_watcher.rb +3 -1
- data/lib/mail_room/message.rb +16 -0
- data/lib/mail_room/version.rb +1 -1
- data/mail_room.gemspec +1 -0
- data/spec/fixtures/test_config.yml +3 -0
- data/spec/lib/cli_spec.rb +3 -3
- data/spec/lib/configuration_spec.rb +9 -1
- data/spec/lib/coordinator_spec.rb +16 -2
- data/spec/lib/health_check_spec.rb +57 -0
- data/spec/lib/{connection_spec.rb → imap/connection_spec.rb} +12 -8
- data/spec/lib/imap/message_spec.rb +36 -0
- data/spec/lib/mailbox_spec.rb +10 -10
- data/spec/lib/mailbox_watcher_spec.rb +4 -4
- data/spec/lib/message_spec.rb +35 -0
- metadata +29 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 046d032389d041dfea1d880c47ff567ad6ccd97439ba05db04f49fe8f6fd8596
|
4
|
+
data.tar.gz: c1eda45ae5d2cbab863eabb843adfb89694ea563f73101bbf268fba18c25d175
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58986de036f80e17d25440c25d4d6bbdb54a0340f865b455847f7a7bf4d2206ae4fefccb91edbb3b56990cf468505501ad1fa30f5223f589483a1e291a59c49a
|
7
|
+
data.tar.gz: a085cd90036662bf26516bd5574a64d921cfff6b0728ec3350cac8eba80f75faef08dc0a69bf4909adb6e31a1f62ff9e4f2d62560eff5226e493af777eaa5810
|
data/.gitlab-ci.yml
CHANGED
@@ -10,7 +10,7 @@ services:
|
|
10
10
|
variables:
|
11
11
|
REDIS_URL: redis://redis:6379
|
12
12
|
script:
|
13
|
-
|
13
|
+
- bundle exec rspec spec
|
14
14
|
before_script:
|
15
15
|
- apt update && apt install -y libicu-dev
|
16
16
|
- ruby -v # Print out ruby version for debugging
|
@@ -30,3 +30,11 @@ rspec-2.5:
|
|
30
30
|
rspec-2.6:
|
31
31
|
image: "ruby:2.6"
|
32
32
|
<<: *test
|
33
|
+
|
34
|
+
rspec-2.7:
|
35
|
+
image: "ruby:2.7"
|
36
|
+
<<: *test
|
37
|
+
|
38
|
+
rspec-3.0:
|
39
|
+
image: "ruby:3.0"
|
40
|
+
<<: *test
|
data/README.md
CHANGED
@@ -55,6 +55,9 @@ You will also need to install `faraday` or `letter_opener` if you use the `postb
|
|
55
55
|
|
56
56
|
```yaml
|
57
57
|
---
|
58
|
+
:health_check:
|
59
|
+
- :address: "127.0.0.1"
|
60
|
+
:port: 8080
|
58
61
|
:mailboxes:
|
59
62
|
-
|
60
63
|
:email: "user1@gmail.com"
|
@@ -119,6 +122,18 @@ You will also need to install `faraday` or `letter_opener` if you use the `postb
|
|
119
122
|
**Note:** If using `delete_after_delivery`, you also probably want to use
|
120
123
|
`expunge_deleted` unless you really know what you're doing.
|
121
124
|
|
125
|
+
## health_check ##
|
126
|
+
|
127
|
+
Requires `webrick` gem to be installed.
|
128
|
+
|
129
|
+
This option enables an HTTP server that listens to a bind address
|
130
|
+
defined by `address` and `port`. The following endpoints are supported:
|
131
|
+
|
132
|
+
* `/liveness`: This returns a 200 status code with `OK` as the body if
|
133
|
+
the server is running. Otherwise, it returns a 500 status code.
|
134
|
+
|
135
|
+
This feature is not included in upstream `mail_room` and is specific to GitLab.
|
136
|
+
|
122
137
|
## delivery_method ##
|
123
138
|
|
124
139
|
### postback ###
|
data/lib/mail_room.rb
CHANGED
@@ -7,8 +7,10 @@ end
|
|
7
7
|
|
8
8
|
require "mail_room/version"
|
9
9
|
require "mail_room/configuration"
|
10
|
+
require "mail_room/health_check"
|
10
11
|
require "mail_room/mailbox"
|
11
12
|
require "mail_room/mailbox_watcher"
|
13
|
+
require "mail_room/message"
|
12
14
|
require "mail_room/connection"
|
13
15
|
require "mail_room/coordinator"
|
14
16
|
require "mail_room/cli"
|
data/lib/mail_room/cli.rb
CHANGED
@@ -42,7 +42,7 @@ module MailRoom
|
|
42
42
|
end.parse!(args)
|
43
43
|
|
44
44
|
self.configuration = Configuration.new(options)
|
45
|
-
self.coordinator = Coordinator.new(configuration.mailboxes)
|
45
|
+
self.coordinator = Coordinator.new(configuration.mailboxes, configuration.health_check)
|
46
46
|
end
|
47
47
|
|
48
48
|
# Start the coordinator running, sets up signal traps
|
@@ -4,7 +4,7 @@ module MailRoom
|
|
4
4
|
# Wraps configuration for a set of individual mailboxes with global config
|
5
5
|
# @author Tony Pitale
|
6
6
|
class Configuration
|
7
|
-
attr_accessor :mailboxes, :log_path, :quiet
|
7
|
+
attr_accessor :mailboxes, :log_path, :quiet, :health_check
|
8
8
|
|
9
9
|
# Initialize a new configuration of mailboxes
|
10
10
|
def initialize(options={})
|
@@ -18,6 +18,7 @@ module MailRoom
|
|
18
18
|
config_file = YAML.load(erb.result)
|
19
19
|
|
20
20
|
set_mailboxes(config_file[:mailboxes])
|
21
|
+
set_health_check(config_file[:health_check])
|
21
22
|
rescue => e
|
22
23
|
raise e unless quiet
|
23
24
|
end
|
@@ -32,5 +33,14 @@ module MailRoom
|
|
32
33
|
self.mailboxes << Mailbox.new(attributes)
|
33
34
|
end
|
34
35
|
end
|
36
|
+
|
37
|
+
# Builds the health checker from YAML configuration
|
38
|
+
#
|
39
|
+
# @param health_check_config nil or a Hash containing :address and :port
|
40
|
+
def set_health_check(health_check_config)
|
41
|
+
return unless health_check_config
|
42
|
+
|
43
|
+
self.health_check = HealthCheck.new(health_check_config)
|
44
|
+
end
|
35
45
|
end
|
36
46
|
end
|
data/lib/mail_room/connection.rb
CHANGED
@@ -1,197 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MailRoom
|
2
4
|
class Connection
|
5
|
+
attr_reader :mailbox, :new_message_handler
|
6
|
+
|
3
7
|
def initialize(mailbox)
|
4
8
|
@mailbox = mailbox
|
5
|
-
|
6
|
-
# log in and set the mailbox
|
7
|
-
reset
|
8
|
-
setup
|
9
9
|
end
|
10
10
|
|
11
11
|
def on_new_message(&block)
|
12
12
|
@new_message_handler = block
|
13
13
|
end
|
14
14
|
|
15
|
-
# is the connection logged in?
|
16
|
-
# @return [Boolean]
|
17
|
-
def logged_in?
|
18
|
-
@logged_in
|
19
|
-
end
|
20
|
-
|
21
|
-
# is the connection blocked idling?
|
22
|
-
# @return [Boolean]
|
23
|
-
def idling?
|
24
|
-
@idling
|
25
|
-
end
|
26
|
-
|
27
|
-
# is the imap connection closed?
|
28
|
-
# @return [Boolean]
|
29
|
-
def disconnected?
|
30
|
-
imap.disconnected?
|
31
|
-
end
|
32
|
-
|
33
|
-
# is the connection ready to idle?
|
34
|
-
# @return [Boolean]
|
35
|
-
def ready_to_idle?
|
36
|
-
logged_in? && !idling?
|
37
|
-
end
|
38
|
-
|
39
|
-
def quit
|
40
|
-
stop_idling
|
41
|
-
reset
|
42
|
-
end
|
43
|
-
|
44
15
|
def wait
|
45
|
-
|
46
|
-
# in case we missed any between idles
|
47
|
-
process_mailbox
|
48
|
-
|
49
|
-
idle
|
50
|
-
|
51
|
-
process_mailbox
|
52
|
-
rescue Net::IMAP::Error, IOError => e
|
53
|
-
@mailbox.logger.warn({ context: @mailbox.context, action: "Disconnected. Resetting...", error: e.message })
|
54
|
-
reset
|
55
|
-
setup
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
def reset
|
62
|
-
@imap = nil
|
63
|
-
@logged_in = false
|
64
|
-
@idling = false
|
65
|
-
end
|
66
|
-
|
67
|
-
def setup
|
68
|
-
@mailbox.logger.info({ context: @mailbox.context, action: "Starting TLS session" })
|
69
|
-
start_tls
|
70
|
-
|
71
|
-
@mailbox.logger.info({ context: @mailbox.context, action: "Logging into mailbox" })
|
72
|
-
log_in
|
73
|
-
|
74
|
-
@mailbox.logger.info({ context: @mailbox.context, action: "Setting mailbox" })
|
75
|
-
set_mailbox
|
16
|
+
raise NotImplementedError
|
76
17
|
end
|
77
18
|
|
78
|
-
|
79
|
-
|
80
|
-
@imap ||= Net::IMAP.new(@mailbox.host, :port => @mailbox.port, :ssl => @mailbox.ssl_options)
|
81
|
-
end
|
82
|
-
|
83
|
-
# start a TLS session
|
84
|
-
def start_tls
|
85
|
-
imap.starttls if @mailbox.start_tls
|
86
|
-
end
|
87
|
-
|
88
|
-
# send the imap login command to google
|
89
|
-
def log_in
|
90
|
-
imap.login(@mailbox.email, @mailbox.password)
|
91
|
-
@logged_in = true
|
92
|
-
end
|
93
|
-
|
94
|
-
# select the mailbox name we want to use
|
95
|
-
def set_mailbox
|
96
|
-
imap.select(@mailbox.name) if logged_in?
|
97
|
-
end
|
98
|
-
|
99
|
-
# is the response for a new message?
|
100
|
-
# @param response [Net::IMAP::TaggedResponse] the imap response from idle
|
101
|
-
# @return [Boolean]
|
102
|
-
def message_exists?(response)
|
103
|
-
response.respond_to?(:name) && response.name == 'EXISTS'
|
104
|
-
end
|
105
|
-
|
106
|
-
# @private
|
107
|
-
def idle_handler
|
108
|
-
lambda {|response| imap.idle_done if message_exists?(response)}
|
109
|
-
end
|
110
|
-
|
111
|
-
# maintain an imap idle connection
|
112
|
-
def idle
|
113
|
-
return unless ready_to_idle?
|
114
|
-
|
115
|
-
@mailbox.logger.info({ context: @mailbox.context, action: "Idling" })
|
116
|
-
@idling = true
|
117
|
-
|
118
|
-
imap.idle(@mailbox.idle_timeout, &idle_handler)
|
119
|
-
ensure
|
120
|
-
@idling = false
|
121
|
-
end
|
122
|
-
|
123
|
-
# trigger the idle to finish and wait for the thread to finish
|
124
|
-
def stop_idling
|
125
|
-
return unless idling?
|
126
|
-
|
127
|
-
imap.idle_done
|
128
|
-
|
129
|
-
# idling_thread.join
|
130
|
-
# self.idling_thread = nil
|
131
|
-
end
|
132
|
-
|
133
|
-
def process_mailbox
|
134
|
-
return unless @new_message_handler
|
135
|
-
@mailbox.logger.info({ context: @mailbox.context, action: "Processing started" })
|
136
|
-
|
137
|
-
msgs = new_messages
|
138
|
-
|
139
|
-
any_deletions = msgs.
|
140
|
-
# deliver each new message, collect success
|
141
|
-
map(&@new_message_handler).
|
142
|
-
# include messages with success
|
143
|
-
zip(msgs).
|
144
|
-
# filter failed deliveries, collect message
|
145
|
-
select(&:first).map(&:last).
|
146
|
-
# scrub delivered messages
|
147
|
-
map { |message| scrub(message) }.
|
148
|
-
any?
|
149
|
-
|
150
|
-
imap.expunge if @mailbox.expunge_deleted && any_deletions
|
151
|
-
end
|
152
|
-
|
153
|
-
def scrub(message)
|
154
|
-
if @mailbox.delete_after_delivery
|
155
|
-
imap.store(message.seqno, "+FLAGS", [Net::IMAP::DELETED])
|
156
|
-
true
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
# @private
|
161
|
-
# fetch all messages for the new message ids
|
162
|
-
def new_messages
|
163
|
-
# Both of these calls may results in
|
164
|
-
# imap raising an EOFError, we handle
|
165
|
-
# this exception in the watcher
|
166
|
-
messages_for_ids(new_message_ids)
|
167
|
-
end
|
168
|
-
|
169
|
-
# TODO: label messages?
|
170
|
-
# @imap.store(id, "+X-GM-LABELS", [label])
|
171
|
-
|
172
|
-
# @private
|
173
|
-
# search for all new (unseen) message ids
|
174
|
-
# @return [Array<Integer>] message ids
|
175
|
-
def new_message_ids
|
176
|
-
# uid_search still leaves messages UNSEEN
|
177
|
-
all_unread = imap.uid_search(@mailbox.search_command)
|
178
|
-
|
179
|
-
all_unread = all_unread.slice(0, @mailbox.limit_max_unread) unless @mailbox.limit_max_unread.nil? || @mailbox.limit_max_unread == 0
|
180
|
-
|
181
|
-
to_deliver = all_unread.select { |uid| @mailbox.deliver?(uid) }
|
182
|
-
@mailbox.logger.info({ context: @mailbox.context, action: "Getting new messages", unread: {count: all_unread.count, ids: all_unread}, to_be_delivered: { count: to_deliver.count, ids: to_deliver } })
|
183
|
-
to_deliver
|
184
|
-
end
|
185
|
-
|
186
|
-
# @private
|
187
|
-
# fetch the email for all given ids in RFC822 format
|
188
|
-
# @param ids [Array<Integer>] list of message ids
|
189
|
-
# @return [Array<Net::IMAP::FetchData>] the net/imap messages for the given ids
|
190
|
-
def messages_for_ids(uids)
|
191
|
-
return [] if uids.empty?
|
192
|
-
|
193
|
-
# uid_fetch marks as SEEN, will not be re-fetched for UNSEEN
|
194
|
-
imap.uid_fetch(uids, "RFC822")
|
19
|
+
def quit
|
20
|
+
raise NotImplementedError
|
195
21
|
end
|
196
22
|
end
|
197
23
|
end
|
@@ -2,13 +2,15 @@ module MailRoom
|
|
2
2
|
# Coordinate the mailbox watchers
|
3
3
|
# @author Tony Pitale
|
4
4
|
class Coordinator
|
5
|
-
attr_accessor :watchers, :running
|
5
|
+
attr_accessor :watchers, :running, :health_check
|
6
6
|
|
7
7
|
# build watchers for a set of mailboxes
|
8
8
|
# @params mailboxes [Array<MailRoom::Mailbox>] mailboxes to be watched
|
9
|
-
|
9
|
+
# @params health_check <MailRoom::HealthCheck> health checker to run
|
10
|
+
def initialize(mailboxes, health_check = nil)
|
10
11
|
self.watchers = []
|
11
12
|
|
13
|
+
@health_check = health_check
|
12
14
|
mailboxes.each {|box| self.watchers << MailboxWatcher.new(box)}
|
13
15
|
end
|
14
16
|
|
@@ -16,10 +18,11 @@ module MailRoom
|
|
16
18
|
|
17
19
|
# start each of the watchers to running
|
18
20
|
def run
|
21
|
+
health_check&.run
|
19
22
|
watchers.each(&:run)
|
20
|
-
|
23
|
+
|
21
24
|
self.running = true
|
22
|
-
|
25
|
+
|
23
26
|
sleep_while_running
|
24
27
|
ensure
|
25
28
|
quit
|
@@ -27,6 +30,7 @@ module MailRoom
|
|
27
30
|
|
28
31
|
# quit each of the watchers when we're done running
|
29
32
|
def quit
|
33
|
+
health_check&.quit
|
30
34
|
watchers.each(&:quit)
|
31
35
|
end
|
32
36
|
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MailRoom
|
4
|
+
class HealthCheck
|
5
|
+
attr_reader :address, :port, :running
|
6
|
+
|
7
|
+
def initialize(attributes = {})
|
8
|
+
@address = attributes[:address]
|
9
|
+
@port = attributes[:port]
|
10
|
+
|
11
|
+
validate!
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
@server = create_server
|
16
|
+
|
17
|
+
@thread = Thread.new do
|
18
|
+
@server.start
|
19
|
+
end
|
20
|
+
|
21
|
+
@thread.abort_on_exception = true
|
22
|
+
@running = true
|
23
|
+
end
|
24
|
+
|
25
|
+
def quit
|
26
|
+
@running = false
|
27
|
+
@server&.shutdown
|
28
|
+
@thread&.join(60)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def validate!
|
34
|
+
raise 'No health check address specified' unless address
|
35
|
+
raise "Health check port #{@port.to_i} is invalid" unless port.to_i.positive?
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_server
|
39
|
+
require 'webrick'
|
40
|
+
|
41
|
+
server = ::WEBrick::HTTPServer.new(Port: port, BindAddress: address, AccessLog: [])
|
42
|
+
|
43
|
+
server.mount_proc '/liveness' do |_req, res|
|
44
|
+
handle_liveness(res)
|
45
|
+
end
|
46
|
+
|
47
|
+
server
|
48
|
+
end
|
49
|
+
|
50
|
+
def handle_liveness(res)
|
51
|
+
if @running
|
52
|
+
res.status = 200
|
53
|
+
res.body = "OK\n"
|
54
|
+
else
|
55
|
+
res.status = 500
|
56
|
+
res.body = "Not running\n"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MailRoom
|
4
|
+
module IMAP
|
5
|
+
class Connection < MailRoom::Connection
|
6
|
+
def initialize(mailbox)
|
7
|
+
super
|
8
|
+
|
9
|
+
# log in and set the mailbox
|
10
|
+
reset
|
11
|
+
setup
|
12
|
+
end
|
13
|
+
|
14
|
+
# is the connection logged in?
|
15
|
+
# @return [Boolean]
|
16
|
+
def logged_in?
|
17
|
+
@logged_in
|
18
|
+
end
|
19
|
+
|
20
|
+
# is the connection blocked idling?
|
21
|
+
# @return [Boolean]
|
22
|
+
def idling?
|
23
|
+
@idling
|
24
|
+
end
|
25
|
+
|
26
|
+
# is the imap connection closed?
|
27
|
+
# @return [Boolean]
|
28
|
+
def disconnected?
|
29
|
+
imap.disconnected?
|
30
|
+
end
|
31
|
+
|
32
|
+
# is the connection ready to idle?
|
33
|
+
# @return [Boolean]
|
34
|
+
def ready_to_idle?
|
35
|
+
logged_in? && !idling?
|
36
|
+
end
|
37
|
+
|
38
|
+
def quit
|
39
|
+
stop_idling
|
40
|
+
reset
|
41
|
+
end
|
42
|
+
|
43
|
+
def wait
|
44
|
+
# in case we missed any between idles
|
45
|
+
process_mailbox
|
46
|
+
|
47
|
+
idle
|
48
|
+
|
49
|
+
process_mailbox
|
50
|
+
rescue Net::IMAP::Error, IOError => e
|
51
|
+
@mailbox.logger.warn({ context: @mailbox.context, action: 'Disconnected. Resetting...', error: e.message })
|
52
|
+
reset
|
53
|
+
setup
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def reset
|
59
|
+
@imap = nil
|
60
|
+
@logged_in = false
|
61
|
+
@idling = false
|
62
|
+
end
|
63
|
+
|
64
|
+
def setup
|
65
|
+
@mailbox.logger.info({ context: @mailbox.context, action: 'Starting TLS session' })
|
66
|
+
start_tls
|
67
|
+
|
68
|
+
@mailbox.logger.info({ context: @mailbox.context, action: 'Logging into mailbox' })
|
69
|
+
log_in
|
70
|
+
|
71
|
+
@mailbox.logger.info({ context: @mailbox.context, action: 'Setting mailbox' })
|
72
|
+
set_mailbox
|
73
|
+
end
|
74
|
+
|
75
|
+
# build a net/imap connection to google imap
|
76
|
+
def imap
|
77
|
+
@imap ||= Net::IMAP.new(@mailbox.host, port: @mailbox.port, ssl: @mailbox.ssl_options)
|
78
|
+
end
|
79
|
+
|
80
|
+
# start a TLS session
|
81
|
+
def start_tls
|
82
|
+
imap.starttls if @mailbox.start_tls
|
83
|
+
end
|
84
|
+
|
85
|
+
# send the imap login command to google
|
86
|
+
def log_in
|
87
|
+
imap.login(@mailbox.email, @mailbox.password)
|
88
|
+
@logged_in = true
|
89
|
+
end
|
90
|
+
|
91
|
+
# select the mailbox name we want to use
|
92
|
+
def set_mailbox
|
93
|
+
imap.select(@mailbox.name) if logged_in?
|
94
|
+
end
|
95
|
+
|
96
|
+
# is the response for a new message?
|
97
|
+
# @param response [Net::IMAP::TaggedResponse] the imap response from idle
|
98
|
+
# @return [Boolean]
|
99
|
+
def message_exists?(response)
|
100
|
+
response.respond_to?(:name) && response.name == 'EXISTS'
|
101
|
+
end
|
102
|
+
|
103
|
+
# @private
|
104
|
+
def idle_handler
|
105
|
+
->(response) { imap.idle_done if message_exists?(response) }
|
106
|
+
end
|
107
|
+
|
108
|
+
# maintain an imap idle connection
|
109
|
+
def idle
|
110
|
+
return unless ready_to_idle?
|
111
|
+
|
112
|
+
@mailbox.logger.info({ context: @mailbox.context, action: 'Idling' })
|
113
|
+
@idling = true
|
114
|
+
|
115
|
+
imap.idle(@mailbox.idle_timeout, &idle_handler)
|
116
|
+
ensure
|
117
|
+
@idling = false
|
118
|
+
end
|
119
|
+
|
120
|
+
# trigger the idle to finish and wait for the thread to finish
|
121
|
+
def stop_idling
|
122
|
+
return unless idling?
|
123
|
+
|
124
|
+
imap.idle_done
|
125
|
+
|
126
|
+
# idling_thread.join
|
127
|
+
# self.idling_thread = nil
|
128
|
+
end
|
129
|
+
|
130
|
+
def process_mailbox
|
131
|
+
return unless @new_message_handler
|
132
|
+
|
133
|
+
@mailbox.logger.info({ context: @mailbox.context, action: 'Processing started' })
|
134
|
+
|
135
|
+
msgs = new_messages
|
136
|
+
any_deletions = msgs.
|
137
|
+
# deliver each new message, collect success
|
138
|
+
map(&@new_message_handler).
|
139
|
+
# include messages with success
|
140
|
+
zip(msgs).
|
141
|
+
# filter failed deliveries, collect message
|
142
|
+
select(&:first).map(&:last).
|
143
|
+
# scrub delivered messages
|
144
|
+
map { |message| scrub(message) }
|
145
|
+
.any?
|
146
|
+
|
147
|
+
imap.expunge if @mailbox.expunge_deleted && any_deletions
|
148
|
+
end
|
149
|
+
|
150
|
+
def scrub(message)
|
151
|
+
if @mailbox.delete_after_delivery
|
152
|
+
imap.store(message.seqno, '+FLAGS', [Net::IMAP::DELETED])
|
153
|
+
true
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# @private
|
158
|
+
# fetch all messages for the new message ids
|
159
|
+
def new_messages
|
160
|
+
# Both of these calls may results in
|
161
|
+
# imap raising an EOFError, we handle
|
162
|
+
# this exception in the watcher
|
163
|
+
messages_for_ids(new_message_ids)
|
164
|
+
end
|
165
|
+
|
166
|
+
# TODO: label messages?
|
167
|
+
# @imap.store(id, "+X-GM-LABELS", [label])
|
168
|
+
|
169
|
+
# @private
|
170
|
+
# search for all new (unseen) message ids
|
171
|
+
# @return [Array<Integer>] message ids
|
172
|
+
def new_message_ids
|
173
|
+
# uid_search still leaves messages UNSEEN
|
174
|
+
all_unread = imap.uid_search(@mailbox.search_command)
|
175
|
+
|
176
|
+
all_unread = all_unread.slice(0, @mailbox.limit_max_unread) if @mailbox.limit_max_unread.to_i > 0
|
177
|
+
|
178
|
+
to_deliver = all_unread.select { |uid| @mailbox.deliver?(uid) }
|
179
|
+
@mailbox.logger.info({ context: @mailbox.context, action: 'Getting new messages',
|
180
|
+
unread: { count: all_unread.count, ids: all_unread }, to_be_delivered: { count: to_deliver.count, ids: to_deliver } })
|
181
|
+
to_deliver
|
182
|
+
end
|
183
|
+
|
184
|
+
# @private
|
185
|
+
# fetch the email for all given ids in RFC822 format
|
186
|
+
# @param ids [Array<Integer>] list of message ids
|
187
|
+
# @return [Array<MailRoom::IMAP::Message>] the net/imap messages for the given ids
|
188
|
+
def messages_for_ids(uids)
|
189
|
+
return [] if uids.empty?
|
190
|
+
|
191
|
+
# uid_fetch marks as SEEN, will not be re-fetched for UNSEEN
|
192
|
+
imap_messages = imap.uid_fetch(uids, 'RFC822')
|
193
|
+
|
194
|
+
imap_messages.each_with_object([]) do |msg, messages|
|
195
|
+
messages << ::MailRoom::IMAP::Message.new(uid: msg.attr['UID'], body: msg.attr['RFC822'], seqno: msg.seqno)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal:true
|
2
|
+
|
3
|
+
module MailRoom
|
4
|
+
module IMAP
|
5
|
+
class Message < MailRoom::Message
|
6
|
+
attr_reader :seqno
|
7
|
+
|
8
|
+
def initialize(uid:, body:, seqno:)
|
9
|
+
super(uid: uid, body: body)
|
10
|
+
|
11
|
+
@seqno = seqno
|
12
|
+
end
|
13
|
+
|
14
|
+
def ==(other)
|
15
|
+
super && seqno == other.seqno
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/mail_room/mailbox.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "mail_room/delivery"
|
2
2
|
require "mail_room/arbitration"
|
3
|
+
require "mail_room/imap"
|
3
4
|
|
4
5
|
module MailRoom
|
5
6
|
# Mailbox Configuration fields
|
@@ -102,13 +103,13 @@ module MailRoom
|
|
102
103
|
arbitrator.deliver?(uid)
|
103
104
|
end
|
104
105
|
|
105
|
-
# deliver the
|
106
|
-
# @param message [
|
106
|
+
# deliver the email message
|
107
|
+
# @param message [MailRoom::Message]
|
107
108
|
def deliver(message)
|
108
|
-
body = message.
|
109
|
+
body = message.body
|
109
110
|
return true unless body
|
110
111
|
|
111
|
-
logger.info({context: context, uid: message.
|
112
|
+
logger.info({context: context, uid: message.uid, action: "sending to deliverer", deliverer: delivery.class.name, byte_size: body.bytesize})
|
112
113
|
delivery.deliver(body)
|
113
114
|
end
|
114
115
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "mail_room/connection"
|
2
|
+
|
1
3
|
module MailRoom
|
2
4
|
# TODO: split up between processing and idling?
|
3
5
|
|
@@ -61,7 +63,7 @@ module MailRoom
|
|
61
63
|
|
62
64
|
private
|
63
65
|
def connection
|
64
|
-
@connection ||= Connection.new(@mailbox)
|
66
|
+
@connection ||= ::MailRoom::IMAP::Connection.new(@mailbox)
|
65
67
|
end
|
66
68
|
end
|
67
69
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MailRoom
|
4
|
+
class Message
|
5
|
+
attr_reader :uid, :body
|
6
|
+
|
7
|
+
def initialize(uid:, body:)
|
8
|
+
@uid = uid
|
9
|
+
@body = body
|
10
|
+
end
|
11
|
+
|
12
|
+
def ==(other)
|
13
|
+
self.class == other.class && uid == other.uid && body == other.body
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/mail_room/version.rb
CHANGED
data/mail_room.gemspec
CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |gem|
|
|
21
21
|
gem.add_development_dependency "rspec", "~> 3.9"
|
22
22
|
gem.add_development_dependency "mocha", "~> 1.11"
|
23
23
|
gem.add_development_dependency "simplecov"
|
24
|
+
gem.add_development_dependency "webrick", "~> 1.6"
|
24
25
|
|
25
26
|
# for testing delivery methods
|
26
27
|
gem.add_development_dependency "faraday"
|
data/spec/lib/cli_spec.rb
CHANGED
@@ -5,14 +5,14 @@ describe MailRoom::CLI do
|
|
5
5
|
let!(:configuration) {MailRoom::Configuration.new({:config_path => config_path})}
|
6
6
|
let(:coordinator) {stub(:run => true, :quit => true)}
|
7
7
|
let(:configuration_args) { anything }
|
8
|
-
let(:coordinator_args) { anything }
|
8
|
+
let(:coordinator_args) { [anything, anything] }
|
9
9
|
|
10
10
|
describe '.new' do
|
11
11
|
let(:args) {["-c", "a path"]}
|
12
12
|
|
13
13
|
before :each do
|
14
14
|
MailRoom::Configuration.expects(:new).with(configuration_args).returns(configuration)
|
15
|
-
MailRoom::Coordinator.stubs(:new).with(coordinator_args).returns(coordinator)
|
15
|
+
MailRoom::Coordinator.stubs(:new).with(*coordinator_args).returns(coordinator)
|
16
16
|
end
|
17
17
|
|
18
18
|
context 'with configuration args' do
|
@@ -27,7 +27,7 @@ describe MailRoom::CLI do
|
|
27
27
|
|
28
28
|
context 'with coordinator args' do
|
29
29
|
let(:coordinator_args) do
|
30
|
-
configuration.mailboxes
|
30
|
+
[configuration.mailboxes, anything]
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'creates a new coordinator with configuration' do
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe MailRoom::Configuration do
|
4
4
|
let(:config_path) {File.expand_path('../fixtures/test_config.yml', File.dirname(__FILE__))}
|
5
5
|
|
6
|
-
describe '
|
6
|
+
describe '#initalize' do
|
7
7
|
context 'with config_path' do
|
8
8
|
let(:configuration) { MailRoom::Configuration.new(:config_path => config_path) }
|
9
9
|
|
@@ -12,6 +12,10 @@ describe MailRoom::Configuration do
|
|
12
12
|
|
13
13
|
expect(configuration.mailboxes).to eq(['mailbox1', 'mailbox2'])
|
14
14
|
end
|
15
|
+
|
16
|
+
it 'parses health check' do
|
17
|
+
expect(configuration.health_check).to be_a(MailRoom::HealthCheck)
|
18
|
+
end
|
15
19
|
end
|
16
20
|
|
17
21
|
context 'without config_path' do
|
@@ -23,6 +27,10 @@ describe MailRoom::Configuration do
|
|
23
27
|
|
24
28
|
expect(configuration.mailboxes).to eq([])
|
25
29
|
end
|
30
|
+
|
31
|
+
it 'sets the health check to nil' do
|
32
|
+
expect(configuration.health_check).to be_nil
|
33
|
+
end
|
26
34
|
end
|
27
35
|
end
|
28
36
|
end
|
@@ -15,6 +15,13 @@ describe MailRoom::Coordinator do
|
|
15
15
|
coordinator = MailRoom::Coordinator.new([])
|
16
16
|
expect(coordinator.watchers).to eq([])
|
17
17
|
end
|
18
|
+
|
19
|
+
it 'sets the health check' do
|
20
|
+
health_check = MailRoom::HealthCheck.new({ address: '127.0.0.1', port: 8080})
|
21
|
+
coordinator = MailRoom::Coordinator.new([], health_check)
|
22
|
+
|
23
|
+
expect(coordinator.health_check).to eq(health_check)
|
24
|
+
end
|
18
25
|
end
|
19
26
|
|
20
27
|
describe '#run' do
|
@@ -22,15 +29,22 @@ describe MailRoom::Coordinator do
|
|
22
29
|
watcher = stub
|
23
30
|
watcher.stubs(:run)
|
24
31
|
watcher.stubs(:quit)
|
32
|
+
|
33
|
+
health_check = stub
|
34
|
+
health_check.stubs(:run)
|
35
|
+
health_check.stubs(:quit)
|
36
|
+
|
25
37
|
MailRoom::MailboxWatcher.stubs(:new).returns(watcher)
|
26
|
-
coordinator = MailRoom::Coordinator.new(['mailbox1'])
|
38
|
+
coordinator = MailRoom::Coordinator.new(['mailbox1'], health_check)
|
27
39
|
coordinator.stubs(:sleep_while_running)
|
28
40
|
watcher.expects(:run)
|
29
41
|
watcher.expects(:quit)
|
42
|
+
health_check.expects(:run)
|
43
|
+
health_check.expects(:quit)
|
30
44
|
|
31
45
|
coordinator.run
|
32
46
|
end
|
33
|
-
|
47
|
+
|
34
48
|
it 'should go to sleep after running watchers' do
|
35
49
|
coordinator = MailRoom::Coordinator.new([])
|
36
50
|
coordinator.stubs(:running=)
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe MailRoom::HealthCheck do
|
6
|
+
let(:address) { '127.0.0.1' }
|
7
|
+
let(:port) { 8000 }
|
8
|
+
let(:params) { { address: address, port: port } }
|
9
|
+
subject { described_class.new(params) }
|
10
|
+
|
11
|
+
describe '#initialize' do
|
12
|
+
context 'with valid parameters' do
|
13
|
+
it 'validates successfully' do
|
14
|
+
expect(subject).to be_a(described_class)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'with invalid address' do
|
19
|
+
let(:address) { nil }
|
20
|
+
|
21
|
+
it 'raises an error' do
|
22
|
+
expect { subject }.to raise_error('No health check address specified')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'with invalid port' do
|
27
|
+
let(:port) { nil }
|
28
|
+
|
29
|
+
it 'raises an error' do
|
30
|
+
expect { subject }.to raise_error('Health check port 0 is invalid')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#run' do
|
36
|
+
it 'sets running to true' do
|
37
|
+
server = stub(start: true)
|
38
|
+
subject.stubs(:create_server).returns(server)
|
39
|
+
|
40
|
+
subject.run
|
41
|
+
|
42
|
+
expect(subject.running).to be true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#quit' do
|
47
|
+
it 'sets running to false' do
|
48
|
+
server = stub(start: true, shutdown: true)
|
49
|
+
subject.stubs(:create_server).returns(server)
|
50
|
+
|
51
|
+
subject.run
|
52
|
+
subject.quit
|
53
|
+
|
54
|
+
expect(subject.running).to be false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe MailRoom::Connection do
|
3
|
+
describe MailRoom::IMAP::Connection do
|
4
4
|
let(:imap) {stub}
|
5
5
|
let(:mailbox) {build_mailbox(delete_after_delivery: true, expunge_deleted: true)}
|
6
6
|
|
@@ -9,7 +9,9 @@ describe MailRoom::Connection do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
context "with imap set up" do
|
12
|
-
let(:connection) {MailRoom::Connection.new(mailbox)}
|
12
|
+
let(:connection) {MailRoom::IMAP::Connection.new(mailbox)}
|
13
|
+
let(:uid) { 1 }
|
14
|
+
let(:seqno) { 8 }
|
13
15
|
|
14
16
|
before :each do
|
15
17
|
imap.stubs(:starttls)
|
@@ -36,19 +38,21 @@ describe MailRoom::Connection do
|
|
36
38
|
end
|
37
39
|
|
38
40
|
it "waits for a message to process" do
|
39
|
-
new_message = 'a message'
|
40
|
-
new_message.stubs(:seqno).returns(8)
|
41
|
+
new_message = MailRoom::IMAP::Message.new(uid: uid, body: 'a message', seqno: seqno)
|
41
42
|
|
42
43
|
connection.on_new_message do |message|
|
43
44
|
expect(message).to eq(new_message)
|
44
45
|
true
|
45
46
|
end
|
46
47
|
|
48
|
+
attr = { 'UID' => uid, 'RFC822' => new_message.body }
|
49
|
+
fetch_data = Net::IMAP::FetchData.new(seqno, attr)
|
50
|
+
|
47
51
|
imap.expects(:idle)
|
48
|
-
imap.stubs(:uid_search).with(mailbox.search_command).returns([], [
|
49
|
-
imap.expects(:uid_fetch).with([
|
50
|
-
mailbox.expects(:deliver?).with(
|
51
|
-
imap.expects(:store).with(
|
52
|
+
imap.stubs(:uid_search).with(mailbox.search_command).returns([], [uid])
|
53
|
+
imap.expects(:uid_fetch).with([uid], "RFC822").returns([fetch_data])
|
54
|
+
mailbox.expects(:deliver?).with(uid).returns(true)
|
55
|
+
imap.expects(:store).with(seqno, "+FLAGS", [Net::IMAP::DELETED])
|
52
56
|
imap.expects(:expunge).once
|
53
57
|
|
54
58
|
connection.wait
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal:true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'securerandom'
|
5
|
+
|
6
|
+
describe MailRoom::IMAP::Message do
|
7
|
+
let(:uid) { SecureRandom.hex }
|
8
|
+
let(:body) { 'hello world' }
|
9
|
+
let(:seqno) { 5 }
|
10
|
+
|
11
|
+
subject { described_class.new(uid: uid, body: body, seqno: seqno) }
|
12
|
+
|
13
|
+
describe '#initalize' do
|
14
|
+
it 'initializes with required parameters' do
|
15
|
+
subject
|
16
|
+
|
17
|
+
expect(subject.uid).to eq(uid)
|
18
|
+
expect(subject.body).to eq(body)
|
19
|
+
expect(subject.seqno).to eq(seqno)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#==' do
|
24
|
+
let(:dup) { described_class.new(uid: uid, body: body, seqno: seqno) }
|
25
|
+
let(:base_msg) { MailRoom::Message.new(uid: uid, body: body) }
|
26
|
+
|
27
|
+
it 'matches an equivalent message' do
|
28
|
+
expect(dup == subject).to be true
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'does not match a base message' do
|
32
|
+
expect(subject == base_msg).to be false
|
33
|
+
expect(base_msg == subject).to be false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/spec/lib/mailbox_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe MailRoom::Mailbox do
|
4
|
-
let(:sample_message) {
|
4
|
+
let(:sample_message) { MailRoom::Message.new(uid: 123, body: 'a message') }
|
5
5
|
|
6
6
|
describe "#deliver" do
|
7
7
|
context "with arbitration_method of noop" do
|
@@ -36,9 +36,9 @@ describe MailRoom::Mailbox do
|
|
36
36
|
noop = stub(:deliver)
|
37
37
|
MailRoom::Delivery['noop'].stubs(:new => noop)
|
38
38
|
|
39
|
-
noop.expects(:deliver).with(
|
39
|
+
noop.expects(:deliver).with(sample_message.body)
|
40
40
|
|
41
|
-
mailbox.deliver(
|
41
|
+
mailbox.deliver(sample_message)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -48,9 +48,9 @@ describe MailRoom::Mailbox do
|
|
48
48
|
logger = stub(:deliver)
|
49
49
|
MailRoom::Delivery['logger'].stubs(:new => logger)
|
50
50
|
|
51
|
-
logger.expects(:deliver).with(
|
51
|
+
logger.expects(:deliver).with(sample_message.body)
|
52
52
|
|
53
|
-
mailbox.deliver(
|
53
|
+
mailbox.deliver(sample_message)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
@@ -60,9 +60,9 @@ describe MailRoom::Mailbox do
|
|
60
60
|
postback = stub(:deliver)
|
61
61
|
MailRoom::Delivery['postback'].stubs(:new => postback)
|
62
62
|
|
63
|
-
postback.expects(:deliver).with(
|
63
|
+
postback.expects(:deliver).with(sample_message.body)
|
64
64
|
|
65
|
-
mailbox.deliver(
|
65
|
+
mailbox.deliver(sample_message)
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
@@ -72,9 +72,9 @@ describe MailRoom::Mailbox do
|
|
72
72
|
letter_opener = stub(:deliver)
|
73
73
|
MailRoom::Delivery['letter_opener'].stubs(:new => letter_opener)
|
74
74
|
|
75
|
-
letter_opener.expects(:deliver).with(
|
75
|
+
letter_opener.expects(:deliver).with(sample_message.body)
|
76
76
|
|
77
|
-
mailbox.deliver(
|
77
|
+
mailbox.deliver(sample_message)
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
@@ -85,7 +85,7 @@ describe MailRoom::Mailbox do
|
|
85
85
|
MailRoom::Delivery['noop'].stubs(:new => noop)
|
86
86
|
noop.expects(:deliver).never
|
87
87
|
|
88
|
-
mailbox.deliver(
|
88
|
+
mailbox.deliver(MailRoom::Message.new(uid: 1234, body: nil))
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
@@ -19,9 +19,9 @@ describe MailRoom::MailboxWatcher do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'loops over wait while running' do
|
22
|
-
connection = MailRoom::Connection.new(mailbox)
|
22
|
+
connection = MailRoom::IMAP::Connection.new(mailbox)
|
23
23
|
|
24
|
-
MailRoom::Connection.stubs(:new).returns(connection)
|
24
|
+
MailRoom::IMAP::Connection.stubs(:new).returns(connection)
|
25
25
|
|
26
26
|
watcher.expects(:running?).twice.returns(true, false)
|
27
27
|
connection.expects(:wait).once
|
@@ -41,11 +41,11 @@ describe MailRoom::MailboxWatcher do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'closes and waits for the connection' do
|
44
|
-
connection = MailRoom::Connection.new(mailbox)
|
44
|
+
connection = MailRoom::IMAP::Connection.new(mailbox)
|
45
45
|
connection.stubs(:wait)
|
46
46
|
connection.stubs(:quit)
|
47
47
|
|
48
|
-
MailRoom::Connection.stubs(:new).returns(connection)
|
48
|
+
MailRoom::IMAP::Connection.stubs(:new).returns(connection)
|
49
49
|
|
50
50
|
watcher.run
|
51
51
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal:true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'securerandom'
|
5
|
+
|
6
|
+
describe MailRoom::Message do
|
7
|
+
let(:uid) { SecureRandom.hex }
|
8
|
+
let(:body) { 'hello world' }
|
9
|
+
|
10
|
+
subject { described_class.new(uid: uid, body: body) }
|
11
|
+
|
12
|
+
describe '#initalize' do
|
13
|
+
it 'initializes with required parameters' do
|
14
|
+
subject
|
15
|
+
|
16
|
+
expect(subject.uid).to eq(uid)
|
17
|
+
expect(subject.body).to eq(body)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#==' do
|
22
|
+
let(:dup) { described_class.new(uid: uid, body: body) }
|
23
|
+
|
24
|
+
it 'matches an equivalent message' do
|
25
|
+
expect(dup == subject).to be true
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'does not match a message with a different UID' do
|
29
|
+
msg = described_class.new(uid: '12345', body: body)
|
30
|
+
|
31
|
+
expect(subject == msg).to be false
|
32
|
+
expect(msg == subject).to be false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gitlab-mail_room
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Pitale
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: webrick
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.6'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.6'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: faraday
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -200,9 +214,14 @@ files:
|
|
200
214
|
- lib/mail_room/delivery/postback.rb
|
201
215
|
- lib/mail_room/delivery/que.rb
|
202
216
|
- lib/mail_room/delivery/sidekiq.rb
|
217
|
+
- lib/mail_room/health_check.rb
|
218
|
+
- lib/mail_room/imap.rb
|
219
|
+
- lib/mail_room/imap/connection.rb
|
220
|
+
- lib/mail_room/imap/message.rb
|
203
221
|
- lib/mail_room/logger/structured.rb
|
204
222
|
- lib/mail_room/mailbox.rb
|
205
223
|
- lib/mail_room/mailbox_watcher.rb
|
224
|
+
- lib/mail_room/message.rb
|
206
225
|
- lib/mail_room/version.rb
|
207
226
|
- logfile.log
|
208
227
|
- mail_room.gemspec
|
@@ -210,7 +229,6 @@ files:
|
|
210
229
|
- spec/lib/arbitration/redis_spec.rb
|
211
230
|
- spec/lib/cli_spec.rb
|
212
231
|
- spec/lib/configuration_spec.rb
|
213
|
-
- spec/lib/connection_spec.rb
|
214
232
|
- spec/lib/coordinator_spec.rb
|
215
233
|
- spec/lib/crash_handler_spec.rb
|
216
234
|
- spec/lib/delivery/letter_opener_spec.rb
|
@@ -218,9 +236,13 @@ files:
|
|
218
236
|
- spec/lib/delivery/postback_spec.rb
|
219
237
|
- spec/lib/delivery/que_spec.rb
|
220
238
|
- spec/lib/delivery/sidekiq_spec.rb
|
239
|
+
- spec/lib/health_check_spec.rb
|
240
|
+
- spec/lib/imap/connection_spec.rb
|
241
|
+
- spec/lib/imap/message_spec.rb
|
221
242
|
- spec/lib/logger/structured_spec.rb
|
222
243
|
- spec/lib/mailbox_spec.rb
|
223
244
|
- spec/lib/mailbox_watcher_spec.rb
|
245
|
+
- spec/lib/message_spec.rb
|
224
246
|
- spec/spec_helper.rb
|
225
247
|
homepage: http://github.com/tpitale/mail_room
|
226
248
|
licenses: []
|
@@ -250,7 +272,6 @@ test_files:
|
|
250
272
|
- spec/lib/arbitration/redis_spec.rb
|
251
273
|
- spec/lib/cli_spec.rb
|
252
274
|
- spec/lib/configuration_spec.rb
|
253
|
-
- spec/lib/connection_spec.rb
|
254
275
|
- spec/lib/coordinator_spec.rb
|
255
276
|
- spec/lib/crash_handler_spec.rb
|
256
277
|
- spec/lib/delivery/letter_opener_spec.rb
|
@@ -258,7 +279,11 @@ test_files:
|
|
258
279
|
- spec/lib/delivery/postback_spec.rb
|
259
280
|
- spec/lib/delivery/que_spec.rb
|
260
281
|
- spec/lib/delivery/sidekiq_spec.rb
|
282
|
+
- spec/lib/health_check_spec.rb
|
283
|
+
- spec/lib/imap/connection_spec.rb
|
284
|
+
- spec/lib/imap/message_spec.rb
|
261
285
|
- spec/lib/logger/structured_spec.rb
|
262
286
|
- spec/lib/mailbox_spec.rb
|
263
287
|
- spec/lib/mailbox_watcher_spec.rb
|
288
|
+
- spec/lib/message_spec.rb
|
264
289
|
- spec/spec_helper.rb
|