]> git.cworth.org Git - sup/blob - lib/sup/source.rb
improved source error handling
[sup] / lib / sup / source.rb
1 module Redwood
2
3 class SourceError < StandardError; end
4 class OutOfSyncSourceError < SourceError; end
5 class FatalSourceError < SourceError; end
6
7 class Source
8   ## Implementing a new source is typically quite easy, because Sup
9   ## only needs to be able to:
10   ##  1. See how many messages it contains
11   ##  2. Get an arbirtrary message
12   ##  3. (optional) see whether the source has marked it read or not
13   ##
14   ## In particular, Sup doesn't need to move messages, mark them as
15   ## read, delete them, or anything else. (Well, at some point it will
16   ## need to delete them, but that will be an optional capability.)
17   ##
18   ## On the other hand, Sup assumes that you can assign each message a
19   ## unique integer id, such that newer messages have higher ids than
20   ## earlier ones, and that those ids stay constant across sessions
21   ## (in the absence of some other client going in and fucking
22   ## everything up). For example, for mboxes I use the file offset of
23   ## the start of the message. If a source does NOT have that
24   ## capability, e.g. IMAP, then you have to do a little more work to
25   ## simulate it.
26   ##
27   ## To write a new source, subclass this class, and implement:
28   ##
29   ## - start_offset
30   ## - end_offset (exclusive!)
31   ## - load_header offset
32   ## - load_message offset
33   ## - raw_header offset
34   ## - raw_full_message offset
35   ## - check
36   ## - next (or each, if you prefer)
37   ##
38   ## ... where "offset" really means unique id. (You can tell I
39   ## started with mbox.)
40   ##
41   ## All exceptions relating to accessing the source must be caught
42   ## and rethrown as FatalSourceErrors or OutOfSyncSourceErrors.
43   ## OutOfSyncSourceErrors should be used for problems that a call to
44   ## sup-sync will fix (namely someone's been playing with the source
45   ## from another client); FatalSourceErrors can be used for anything
46   ## else (e.g. the imap server is down or the maildir is missing.)
47   ##
48   ## Finally, be sure the source is thread-safe, since it WILL be
49   ## pummeled from multiple threads at once.
50   ##
51   ## Examples for you to look at: mbox/loader.rb, imap.rb, and
52   ## maildir.rb.
53
54   ## let's begin!
55   ##
56   ## dirty? means cur_offset has changed, so the source info needs to
57   ## be re-saved to sources.yaml.
58   bool_reader :usual, :archived, :dirty
59   attr_reader :uri, :cur_offset
60   attr_accessor :id
61
62   def initialize uri, initial_offset=nil, usual=true, archived=false, id=nil
63     @uri = uri
64     @cur_offset = initial_offset || start_offset
65     @usual = usual
66     @archived = archived
67     @id = id
68     @dirty = false
69   end
70
71   def to_s; @uri.to_s; end
72   def seek_to! o; self.cur_offset = o; end
73   def reset!; seek_to! start_offset; end
74   def == o; o.to_s == to_s; end
75   def done?; (self.cur_offset ||= start_offset) >= end_offset; end
76   def is_source_for? uri; URI(self.uri) == URI(uri); end
77
78   ## check should throw a FatalSourceError or an OutOfSyncSourcError
79   ## if it can detect a problem. it is called when the sup starts up
80   ## to proactively notify the user of any source problems.
81   def check; end
82
83   def each
84     self.cur_offset ||= start_offset
85     until done?
86       n, labels = self.next
87       raise "no message" unless n
88       yield n, labels
89     end
90   end
91
92 protected
93   
94   def cur_offset= o
95     @cur_offset = o
96     @dirty = true
97   end
98 end
99
100 Redwood::register_yaml(Source, %w(uri cur_offset usual archived id))
101
102 end