inbox-sync 0.3.0 → 0.4.0

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/README.md CHANGED
@@ -95,6 +95,10 @@ The (optional) folder on the source to create and archive (move) source inbox me
95
95
 
96
96
  A logger to use. Defaults to ruby's `Logger` on `STDOUT`.
97
97
 
98
+ ### `max_threads`
99
+
100
+ This is the number of threads to sync mail items with. Each time a sync is run, the number of mail items that need to sync'd will be broken into `max_threads` groups and each group will sync its mail items in its own thread. The default is `1` which means each message will be sync'd sequentially.
101
+
98
102
  ## Running
99
103
 
100
104
  InboxSync provides a `Runner` class that will loop indefinitely, running syncs every `:interval` seconds. Stick it in a daemon, a rake task, a CLI, or whatever depending on how you want to invoke it. Here is an example using it in a basic ruby script:
@@ -16,6 +16,7 @@ module InboxSync
16
16
  opt :archive_folder, :default => 'Archived'
17
17
  opt :logger, Logger, :required => true, :default => STDOUT
18
18
  opt :filters, :default => [], :required => true
19
+ opt :max_threads, :default => 1, :required => true
19
20
 
20
21
  def filter(*args, &block)
21
22
  filters << Filter.new(*args, &block)
@@ -17,6 +17,7 @@ module InboxSync
17
17
  @logger = opts[:logger] || Logger.new(STDOUT)
18
18
  @shutdown = false
19
19
  @running_syncs_thread = nil
20
+ @sync_groups = []
20
21
 
21
22
  Signal.trap('SIGINT', lambda{ raise Interrupt, 'SIGINT' })
22
23
  Signal.trap('SIGQUIT', lambda{ raise Interrupt, 'SIGQUIT' })
@@ -93,7 +94,10 @@ module InboxSync
93
94
  thread_log "starting syncs..."
94
95
 
95
96
  begin
96
- run_syncs
97
+ @syncs.each do |sync|
98
+ run_threaded_sync(sync) if !self.shutdown?
99
+ end
100
+ GC.start
97
101
  rescue Exception => err
98
102
  thread_log_error(err, :error)
99
103
  end
@@ -101,22 +105,30 @@ module InboxSync
101
105
  thread_log "...syncs finished"
102
106
  end
103
107
 
104
- def run_syncs
105
- @syncs.each do |sync|
106
- begin
107
- sync.setup
108
- sync.run(self)
109
- rescue Exception => err
110
- run_sync_handle_error(sync, err)
108
+ def run_threaded_sync(sync)
109
+ begin
110
+ sync.setup
111
+ @sync_groups = sync.mail_item_groups
112
+ thread_log "starting #{@sync_groups.size} sync threads..."
113
+ @sync_groups.each do |group|
114
+ thread_log "starting #{group.id} sync thread", :debug
115
+ group.run(self)
116
+ sleep(1)
111
117
  end
118
+ rescue Exception => err
119
+ run_sync_handle_error(sync, err)
120
+ end
112
121
 
113
- begin
114
- sync.teardown
115
- rescue Exception => err
116
- run_sync_handle_error(sync, err)
122
+ begin
123
+ @sync_groups.each do |group|
124
+ thread_log "waiting for #{group.id} sync thread to join...", :debug
125
+ group.join
117
126
  end
127
+ thread_log "... all #{@sync_groups.size} sync threads are finished"
128
+ sync.teardown
129
+ rescue Exception => err
130
+ run_sync_handle_error(sync, err)
118
131
  end
119
- GC.start
120
132
  end
121
133
 
122
134
  def run_sync_handle_error(sync, err)
@@ -0,0 +1,46 @@
1
+ module InboxSync
2
+ class Sync; end
3
+
4
+ class Sync::MailItemGroup
5
+
6
+ attr_reader :thread, :items
7
+
8
+ def initialize(sync)
9
+ @sync = sync
10
+ @thread = nil
11
+ @items = []
12
+ end
13
+
14
+ def id
15
+ "#<#{self.class}:#{'0x%x' % (self.object_id << 1)}>"
16
+ end
17
+
18
+ def add(mail_item)
19
+ @items << mail_item
20
+ end
21
+
22
+ def run(runner=nil)
23
+ @runner = runner
24
+ @thread = Thread.new { run_items_thread }
25
+ end
26
+
27
+ def join
28
+ @thread.join
29
+ @runner = nil
30
+ end
31
+
32
+ protected
33
+
34
+ def run_items_thread
35
+ @items.each do |item|
36
+ if @runner && @runner.shutdown?
37
+ @sync.logger.debug "* the runner has been shutdown - aborting #{id} sync thread"
38
+ break
39
+ end
40
+ @sync.run(item)
41
+ end
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -3,6 +3,7 @@ require 'net/smtp'
3
3
 
4
4
  require 'inbox-sync/config'
5
5
  require 'inbox-sync/filter_actions'
6
+ require 'inbox-sync/sync/mail_item_group'
6
7
  require 'inbox-sync/notice/sync_mail_item_error'
7
8
 
8
9
  module InboxSync
@@ -53,25 +54,36 @@ module InboxSync
53
54
  logger.info "=== #{config_log_detail(@config.source)} sync finished. ==="
54
55
  end
55
56
 
56
- def run(runner=nil)
57
- return if runner && runner.shutdown?
58
- each_source_mail_item(runner) do |mail_item|
59
- begin
60
- logger.debug "** #{mail_item.inspect}"
61
- response = send_to_dest(mail_item)
62
- dest_uid = parse_append_response_uid(response)
63
- apply_dest_filters(dest_uid)
64
- rescue Exception => err
65
- log_error(err)
66
- notify(Notice::SyncMailItemError.new(@notify_smtp, @config.notify, {
67
- :error => err,
68
- :mail_item => mail_item,
69
- :sync => self
70
- }))
71
- ensure
72
- archive_on_source(mail_item)
73
- mail_item = nil
74
- end
57
+ # this splits the mail_items list into `@config.max_threads` lists
58
+ # this spreads mails evenly across the groups with earlier items
59
+ # appearing earliest in each list
60
+
61
+ def mail_item_groups
62
+ num_groups = @config.max_threads
63
+ groups = []
64
+ num_groups.times { groups << MailItemGroup.new(self) }
65
+ get_mail_items.each_with_index do |item, i|
66
+ groups[i % num_groups].add(item)
67
+ end
68
+ groups
69
+ end
70
+
71
+ def run(mail_item)
72
+ begin
73
+ logger.debug "** #{mail_item.inspect}"
74
+ response = send_to_dest(mail_item)
75
+ dest_uid = parse_append_response_uid(response)
76
+ apply_dest_filters(dest_uid)
77
+ rescue Exception => err
78
+ log_error(err)
79
+ notify(Notice::SyncMailItemError.new(@notify_smtp, @config.notify, {
80
+ :error => err,
81
+ :mail_item => mail_item,
82
+ :sync => self
83
+ }))
84
+ ensure
85
+ archive_on_source(mail_item)
86
+ mail_item = nil
75
87
  end
76
88
  end
77
89
 
@@ -98,21 +110,6 @@ module InboxSync
98
110
  true
99
111
  end
100
112
 
101
- def each_source_mail_item(runner=nil)
102
- logger.info "* find: #{config_log_detail(@config.source)}, #{@config.source.inbox.inspect}..."
103
- items = MailItem.find(@source_imap)
104
- logger.info "* ...found #{items.size} mail items"
105
-
106
- items.each do |mail_item|
107
- if runner && runner.shutdown?
108
- logger.info "* the runner has been shutdown - aborting the sync"
109
- break
110
- end
111
- yield mail_item
112
- end
113
- items = nil
114
- end
115
-
116
113
  # Send a mail item to the destination:
117
114
  # The idea here is that destinations may not accept corrupted or invalid
118
115
  # mail items. If appending the original mail item in any way fails,
@@ -223,6 +220,13 @@ module InboxSync
223
220
  end
224
221
  end
225
222
 
223
+ def get_mail_items
224
+ logger.info "* find: #{config_log_detail(@config.source)}, #{@config.source.inbox.inspect}..."
225
+ items = MailItem.find(@source_imap)
226
+ logger.info "* ...found #{items.size} mail items"
227
+ items
228
+ end
229
+
226
230
  def logout_imap(imap, config)
227
231
  logger.debug "* LOGOUT: #{config_log_detail(config)}"
228
232
  imap.logout
@@ -1,3 +1,3 @@
1
1
  module InboxSync
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
data/test/config_test.rb CHANGED
@@ -42,6 +42,11 @@ module InboxSync
42
42
  :required => true
43
43
  }
44
44
 
45
+ should have_option :max_threads, {
46
+ :default => 1,
47
+ :required => true
48
+ }
49
+
45
50
  should have_instance_methods :validate!, :filter
46
51
  should have_instance_methods :contains, :like, :includes, :inc
47
52
  should have_instance_methods :starts_with, :ends_with, :sw, :ew
@@ -45,66 +45,4 @@ module InboxSync
45
45
 
46
46
  end
47
47
 
48
- class LoggedInTests < ConfiguredSyncTests
49
- desc 'and is logged in and ready to run'
50
- before do
51
- reset_source_inbox(@sync)
52
- reset_source_archive(@sync)
53
-
54
- @sync_archive_folder = @sync.config.archive_folder
55
- @mail_item = MailItem.find(@sync.source_imap).first
56
- end
57
-
58
- after do
59
- @sync.config.archive_folder = @sync_archive_folder
60
- @sync.source_imap.select(@sync.config.source.inbox)
61
-
62
- reset_source_archive(@sync)
63
- end
64
-
65
- should "run without any errors" do
66
- assert_nothing_raised do
67
- subject.run
68
- end
69
- end
70
-
71
- end
72
-
73
- # class ArchiveTests < RunTests
74
- # should "remove the message from the inbox" do
75
- # @sync.archive_from_source(@mail_item)
76
-
77
- # assert_not_included @mail_item.uid, @sync.source_imap.uid_search(['ALL'])
78
- # assert_empty @sync.source_imap.uid_search(['ALL'])
79
- # end
80
-
81
- # should "move it to the archive folder" do
82
- # @sync.archive_from_source(@mail_item)
83
- # @sync.source_imap.select(@sync.config.archive_folder)
84
-
85
- # assert_equal 1, @sync.source_imap.uid_search(['ALL']).size
86
- # end
87
-
88
- # should "not archive if no archive folder configured" do
89
- # @sync.config.archive_folder = nil
90
- # @sync.archive_from_source(@mail_item)
91
- # @sync.source_imap.select(@sync.config.source.inbox)
92
-
93
- # assert_not_included @mail_item.uid, @sync.source_imap.uid_search(['ALL'])
94
- # end
95
-
96
- # end
97
-
98
- # class AppendTests < LoggedInTests
99
- # should "append a source msg onto the dest" do
100
- # assert_nothing_raised do
101
- # @sync.append_to_dest(test_mail_item)
102
- # end
103
- # end
104
-
105
- # should "parse the destination UID when appending mail items" do
106
- # assert_match /\A\d+\Z/, @sync.append_to_dest(test_mail_item)
107
- # end
108
- # end
109
-
110
48
  end
@@ -0,0 +1,19 @@
1
+ require 'assert'
2
+
3
+ require 'inbox-sync/sync/mail_item_group'
4
+
5
+ module InboxSync
6
+
7
+ class SyncMailItemGroupTests < Assert::Context
8
+ desc "a runner mail item group"
9
+ before do
10
+ @group = Sync::MailItemGroup.new('dummy sync')
11
+ end
12
+ subject { @group }
13
+
14
+ should have_readers :thread, :items
15
+ should have_instance_methods :id, :add, :run, :join
16
+
17
+ end
18
+
19
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inbox-sync
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 3
8
+ - 4
9
9
  - 0
10
- version: 0.3.0
10
+ version: 0.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Kelly Redding
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-06-15 00:00:00 Z
18
+ date: 2012-06-16 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  type: :development
@@ -91,6 +91,7 @@ files:
91
91
  - lib/inbox-sync/notice/sync_mail_item_error.rb
92
92
  - lib/inbox-sync/runner.rb
93
93
  - lib/inbox-sync/sync.rb
94
+ - lib/inbox-sync/sync/mail_item_group.rb
94
95
  - lib/inbox-sync/version.rb
95
96
  - log/.gitkeep
96
97
  - test/config/filter_test.rb
@@ -102,6 +103,7 @@ files:
102
103
  - test/runner_test.rb
103
104
  - test/sync/basic_test.rb
104
105
  - test/sync/login_test.rb
106
+ - test/sync/mail_item_group_test.rb
105
107
  homepage: http://github.com/kellyredding/inbox-sync
106
108
  licenses: []
107
109
 
@@ -145,3 +147,4 @@ test_files:
145
147
  - test/runner_test.rb
146
148
  - test/sync/basic_test.rb
147
149
  - test/sync/login_test.rb
150
+ - test/sync/mail_item_group_test.rb