pollter_geist 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 05f056b84468423bb3113a3bc2e844e3c3dabb7e
4
- data.tar.gz: 78cc138e11dd795c7cc106c81eff536c98117175
3
+ metadata.gz: 03fbdbda08f63a1cf041006fc4ae9c31447e078f
4
+ data.tar.gz: c8b3ba475deffa7328ae24ac6702115793210aa1
5
5
  SHA512:
6
- metadata.gz: 8c08c5c6b54cd65e0ab5ebff4013fae453f2cccfdb2552091475744cdc421e6f16764c7b5583784f3b5d5758116f6c2779c764783e28dac6804878cf93f7219d
7
- data.tar.gz: a1184580b5972401a0e31e18a31015dd1a56c04bc38b250bd0369195963ea5486ce4443ca4c53f1c272cd21d98fabdd273eda21723a57c6341e91feb450836ff
6
+ metadata.gz: ebf69e6c55a0724232051b3295d60284ed078d4d7f18ae62c25da94bfecf3e4a76d4461afbaec0730bd2536aac3eb6ccf16c4729ae1b3714c54efbba79d953ed
7
+ data.tar.gz: c21efcbc291ac43e2e074481950e1c4a0378bb3c2dafc610df451d0b968814e1b0916f7383bc42a260c2e2f61b5d59ffc5ca9e322b5bceea25c0c680a54e8ceb
data/lib/pollter_geist.rb CHANGED
@@ -6,3 +6,4 @@ end
6
6
  require_relative 'pollter_geist/imap_commands'
7
7
  require_relative 'pollter_geist/imap_idler'
8
8
  require_relative 'pollter_geist/poller'
9
+ require_relative 'pollter_geist/change_listener'
@@ -0,0 +1,38 @@
1
+ module PollterGeist
2
+ class ChangeListener
3
+ def initialize
4
+ @previous = []
5
+ @current = []
6
+ @added = []
7
+ @removed = []
8
+ end
9
+
10
+ def tick current
11
+ @previous = @current
12
+ @current = current
13
+
14
+ @added = @current - @previous
15
+ @removed = @previous - @current
16
+ end
17
+
18
+ def added
19
+ @added
20
+ end
21
+
22
+ def added?
23
+ !added.empty?
24
+ end
25
+
26
+ def removed?
27
+ !removed.empty?
28
+ end
29
+
30
+ def changed?
31
+ added? || removed?
32
+ end
33
+
34
+ def removed
35
+ @removed
36
+ end
37
+ end
38
+ end
@@ -15,13 +15,15 @@ module PollterGeist
15
15
  # Issues IDLE command for the imap server, it takes a list of events to listen for and returns once one of
16
16
  # events occured or if there was a timeout.
17
17
  #
18
- # @param events [events] a list of events to listen for, EXPUNGE, RECENT
18
+ # @param events [events] a list of events to listen for, EXPUNGE, RECENT, EXISTS
19
19
  # @param timeout [Numeric] a timeout, if no event has ocoured for this time
20
20
  # @return will return an object which responds to #success?, #timeout? and #event
21
21
  def wait_for events, timeout = 29*60
22
22
  @idler.idle(events, timeout)
23
23
  end
24
24
 
25
+ # fetches a list of message UIDs
26
+ # @return [Array] of message UIDs
25
27
  def message_uids
26
28
  @logger.debug('fetching uids')
27
29
  # Searching for all messages where TO include @ is a workaround, since the imap#status method
@@ -31,11 +33,36 @@ module PollterGeist
31
33
  result.map { |r| r.attr['UID'].to_i }
32
34
  end
33
35
 
36
+ def remove uid
37
+ @logger.debug("removing #{uid}")
38
+ @imap.uid_store uid, "+FLAGS", [:Deleted]
39
+ end
40
+
41
+ def expunge
42
+ @logger.debug("expunge, remove all messages with Delete flag")
43
+ @imap.expunge
44
+ end
45
+
34
46
  def fetch uids
35
47
  logger.debug "fetching: #{uids}"
36
48
  @imap.uid_fetch(uids, ['RFC822']).map { |r| r.attr['RFC822'] }
37
49
  end
38
50
 
51
+ def wait_for_changes timeout = 20*60
52
+ logger.debug('waiting for changes in inbox')
53
+ change_set = ChangeListener.new
54
+ change_set.tick(message_uids)
55
+ result = wait_for(['RECENT', 'EXPUNGE'], timeout)
56
+ logger.debug('updating current view')
57
+ change_set.tick(message_uids)
58
+ if change_set.changed?
59
+ logger.debug('changes detected!')
60
+ yield(change_set)
61
+ else
62
+ logger.debug('no changes detected')
63
+ end
64
+ end
65
+
39
66
  def logger
40
67
  @logger
41
68
  end
@@ -1,4 +1,6 @@
1
1
  require 'timeout'
2
+ require 'thread'
3
+
2
4
  module PollterGeist
3
5
  class ImapIdler
4
6
  class IdleResult
@@ -26,21 +28,30 @@ module PollterGeist
26
28
  end
27
29
 
28
30
  def idle listen_for = ['RECENT'], timeout = false
29
- begin
30
- Timeout::timeout(timeout) do
31
- loop do
32
- event = do_idle
33
- if listen_for.include? event
34
- return IdleResult.new(true, event)
35
- else
36
- logger.debug "nope, we are not listening for #{event}"
31
+ Thread.handle_interrupt(Timeout::Error => :never, Interrupt => :never) do
32
+ begin
33
+ Timeout::timeout(timeout) do
34
+ loop do
35
+ event = nil
36
+ Thread.handle_interrupt(Timeout::Error => :immediate, Interrupt => :on_blocking) {
37
+ event = do_idle
38
+ }
39
+ if listen_for.include? event
40
+ logger.debug("returning event #{event} to caller")
41
+ return IdleResult.new(true, event)
42
+ else
43
+ logger.debug "nope, we are not listening for #{event}"
44
+ end
37
45
  end
38
46
  end
47
+ rescue Timeout::Error
48
+ imap.idle_done
49
+ logger.debug 'idle timed out'
50
+ return IdleResult.new(false, 'TIMEOUT')
51
+ rescue Interrupt => e
52
+ logger.debug 'idle was interrupted'
53
+ raise e
39
54
  end
40
- rescue Timeout::Error
41
- imap.idle_done
42
- logger.debug 'idle timed out'
43
- return IdleResult.new(false, 'TIMEOUT')
44
55
  end
45
56
  end
46
57
 
@@ -54,12 +65,15 @@ module PollterGeist
54
65
  end
55
66
 
56
67
  def do_idle
57
- event = ''
68
+ @events ||= Queue.new
69
+ until @events.empty?
70
+ return @events.pop
71
+ end
58
72
  imap.idle do |message|
59
73
  case message
60
74
  when Net::IMAP::UntaggedResponse
61
75
  logger.debug "event: #{message.name}, data: #{message.data}"
62
- event = message.name
76
+ @events.push(message.name)
63
77
  imap.idle_done
64
78
  when Net::IMAP::ContinuationRequest
65
79
  logger.debug 'IDLE accepted by the server'
@@ -67,7 +81,8 @@ module PollterGeist
67
81
  logger.warn "Unhandled IDLE response: #{message.class}, #{message.inspect}"
68
82
  end
69
83
  end
70
- event
84
+ logger.debug 'returning from idle'
85
+ @events.pop
71
86
  end
72
87
  end
73
88
  end
@@ -1,3 +1,3 @@
1
1
  module PollterGeist
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -18,6 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency('mail')
22
+ spec.add_dependency('virtus')
23
+
21
24
  spec.add_development_dependency "bundler", "~> 1.3"
22
25
  spec.add_development_dependency "minitest", "~> 5.0.6"
23
26
  spec.add_development_dependency "rake"
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+
3
+ describe PollterGeist::ChangeListener do
4
+ describe '#new' do
5
+ it 'should allow empty' do
6
+ PollterGeist::ChangeListener.new
7
+ end
8
+ end
9
+
10
+ describe '#added' do
11
+ it 'should show added messages' do
12
+ cl = PollterGeist::ChangeListener.new
13
+ cl.added.must_be_kind_of Array
14
+ cl.added.must_be_empty
15
+
16
+ cl.tick([1, 2, 3])
17
+ cl.added.wont_be_empty
18
+ cl.added.must_include 1
19
+ cl.added.must_include 2
20
+ cl.added.must_include 3
21
+ cl.tick([1, 4])
22
+ cl.added.size.must_equal 1
23
+ cl.tick([])
24
+ cl.added.must_be_empty
25
+ end
26
+ end
27
+
28
+ describe '#removed' do
29
+ it 'should show removed messages' do
30
+ cl = PollterGeist::ChangeListener.new
31
+ cl.removed.must_be_kind_of Array
32
+ cl.removed.must_be_empty
33
+
34
+ cl.tick([1, 2, 3])
35
+ cl.removed.must_be_empty
36
+ cl.tick([1, 4])
37
+ cl.removed.size.must_equal 2
38
+ cl.removed.must_include 2
39
+ cl.removed.must_include 3
40
+ cl.tick([])
41
+ cl.removed.wont_be_empty
42
+ cl.tick([])
43
+ cl.removed.must_be_empty
44
+ end
45
+ end
46
+ end
@@ -3,10 +3,36 @@ require 'test_helper'
3
3
  describe PollterGeist::Poller do
4
4
  describe '#session' do
5
5
  it 'should create a session' do
6
- poller = PollterGeist::Poller.new(CONFIG)
6
+ poller = PollterGeist::Poller.new(CONFIG)
7
+ changer = PollterGeist::ChangeListener.new
7
8
  poller.session do |imap|
8
9
  imap.select_mailbox('INBOX')
9
- imap.wait_for('RECENT', 1)
10
+ uids = imap.message_uids
11
+ changer.tick(uids)
12
+ changer.tick(uids)
13
+
14
+
15
+ =begin
16
+ 1.times do
17
+ imap.wait_for('RECENT', 1)
18
+ changer.tick(imap.message_uids)
19
+ imap.logger.debug("+#{changer.added} -#{changer.removed}")
20
+ if changer.added?
21
+ puts imap.fetch(changer.added)
22
+ end
23
+ end
24
+ =end
25
+
26
+
27
+ loop do
28
+ begin
29
+ imap.wait_for_changes(10 * 60) do |changes|
30
+ imap.logger.debug(changes)
31
+ end
32
+ rescue Interrupt => e
33
+ break
34
+ end
35
+ end
10
36
  end
11
37
  end
12
38
  end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pollter_geist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - kwando
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-23 00:00:00.000000000 Z
11
+ date: 2013-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mail
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: virtus
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: bundler
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -65,12 +93,14 @@ files:
65
93
  - README.md
66
94
  - Rakefile
67
95
  - lib/pollter_geist.rb
96
+ - lib/pollter_geist/change_listener.rb
68
97
  - lib/pollter_geist/imap_commands.rb
69
98
  - lib/pollter_geist/imap_idler.rb
70
99
  - lib/pollter_geist/poller.rb
71
100
  - lib/pollter_geist/version.rb
72
101
  - pollter_geist.gemspec
73
102
  - test/test_helper.rb
103
+ - test/unit/pollter_geist/change_listener_test.rb
74
104
  - test/unit/pollter_geist/poller_test.rb
75
105
  - test/unit/pollter_geist_test.rb
76
106
  homepage: ''
@@ -99,5 +129,6 @@ specification_version: 4
99
129
  summary: A small abstraction layer for polling IMAP servers for changes.
100
130
  test_files:
101
131
  - test/test_helper.rb
132
+ - test/unit/pollter_geist/change_listener_test.rb
102
133
  - test/unit/pollter_geist/poller_test.rb
103
134
  - test/unit/pollter_geist_test.rb