inbox-sync 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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