Class: Whisper::EmailReceiver
- Inherits:
-
Object
- Object
- Whisper::EmailReceiver
- Includes:
- Loggy
- Defined in:
- lib/whisper/email_receiver.rb
Constant Summary collapse
- DELAY =
20
Instance Method Summary collapse
- #done? ⇒ Boolean
-
#initialize(entryset, commentset, email_sender, authors, mbox_fn, offset_fn, comment_dir) ⇒ EmailReceiver
constructor
A new instance of EmailReceiver.
- #offset=(offset) ⇒ Object
- #process_one_message ⇒ Object
- #pull_out_content_and_vars(body) ⇒ Object
-
#resend_comments(comment, parent_comment, entry) ⇒ Object
resend a new comment to everyone who should get it.
- #start! ⇒ Object
- #step ⇒ Object
- #update_offset! ⇒ Object
- #write_one_message(content, vars) ⇒ Object
Constructor Details
#initialize(entryset, commentset, email_sender, authors, mbox_fn, offset_fn, comment_dir) ⇒ EmailReceiver
Returns a new instance of EmailReceiver.
16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/whisper/email_receiver.rb', line 16 def initialize entryset, commentset, email_sender, , mbox_fn, offset_fn, comment_dir @entryset = entryset @commentset = commentset @email_sender = email_sender @offset_fn = offset_fn @authors = @comment_dir = comment_dir offset = IO.read(offset_fn).to_i rescue 0 @mbox_fn = mbox_fn @mbox = Mbox.new mbox_fn, offset end |
Instance Method Details
#done? ⇒ Boolean
45 |
# File 'lib/whisper/email_receiver.rb', line 45 def done?; @mbox.eof? end |
#offset=(offset) ⇒ Object
28 29 30 |
# File 'lib/whisper/email_receiver.rb', line 28 def offset= offset @mbox = Mbox.new @mbox_fn, offset end |
#process_one_message ⇒ Object
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/whisper/email_receiver.rb', line 91 def offset = @mbox.offset body, headers = @mbox. return unless body , reply_to, from, date = %w(message-id in-reply-to from date).map do |f| headers[f] or begin warn "no #{f} for message at offset #{offset}. have headers: #{headers.keys.inspect}" return end end if =~ /^<(.+?)>$/ = $1 end if reply_to =~ /^<(.+?)>$/ reply_to = $1 end @commentset.refresh! # force comment set to refresh itself before we look for parents entry, parent_comment = case reply_to when /whisper-post-(\S+)@/ unless(entry = @entryset.entries_by_id[$1]) warn "invalid entry id in message-id for message at offset #{offset}: #{$1.inspect}" return end debug "found new message from #{headers['from']} on entry #{entry.id}" [entry, nil] else unless(parent_comment = @commentset.[reply_to]) warn "no such comment id in in-reply-to for message at offset #{offset}: #{reply_to.inspect}" return end unless(entry = @entryset.entries_by_id[parent_comment.entry_id]) warn "comment #{comment.id} doesn't reference a real entry? wtf (offset #{offset})" return end debug "found new message from #{headers['from']} on entry #{entry.id} replying to a comment by #{parent_comment.}" [entry, parent_comment] end ## pull out variables and comments = {} content, = pull_out_content_and_vars body @authors[from.email_address] = vars = { :author => from, :offset => offset, :entry_id => entry.id, :message_id => , :resend_setting => ([Comment::RESEND_SETTING] || @authors[from.email_address][Comment::RESEND_SETTING]), :url_setting => ([Comment::URL_SETTING] || @authors[from.email_address][Comment::RESEND_SETTING]), :published => Time.parse(date), :parent_id => (parent_comment ? parent_comment.id : nil) } [content, vars, entry, parent_comment] end |
#pull_out_content_and_vars(body) ⇒ Object
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/whisper/email_receiver.rb', line 166 def pull_out_content_and_vars body vars = {} last_was_comment = false attribution = nil lines = body.gsub(/^-- \n.*\Z/m, "").lines.to_a content = lines.zip(lines[1 .. -1] || []).map do |l, next_l| case l when /^[^>].*:$/ if next_l =~ /^> ;/ ## top-level attribution followed by comments. may need to consume it. # puts "have attribution: #{l}" attribution = l nil else l end when /^> ! (.*?):\s*(.*?)(\s*;.*)?$/ vars[$1] = $2 nil when /^> ;/ last_was_comment = true nil when /^>\s*$/ last_was_comment ? nil : l when /^> / if attribution both = [attribution, l] attribution = nil both else l end else l end end.flatten.compact.join [content, vars] end |
#resend_comments(comment, parent_comment, entry) ⇒ Object
resend a new comment to everyone who should get it
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/whisper/email_receiver.rb', line 60 def resend_comments comment, parent_comment, entry sent_to = Set.new [comment..email_address] # never send the comment back to the original author if parent_comment addr = parent_comment..email_address resend = parent_comment.resend_setting debug "for parent comment, resend for #{addr} is #{resend.inspect}" if resend == "replies-only" info "scheduling a resend of #{comment.id} to #{addr} because they're the author of the parent comment and resend is #{resend}" sent_to << addr @email_sender.send_comment comment, addr end else ## resend to entry author if it's a top-level comment info "scheduling a resend of top-level comment #{comment.id} to entry author #{entry..email_address}" @email_sender.send_comment comment, entry..email_address end (@commentset.comments_by_entry_id[entry.id] || []).each do |c| # iterate over all comments for the entry addr = c..email_address next if sent_to.member? addr # we've already seen him sent_to << addr resend = c.resend_setting debug "for thread, resend for #{addr} comment #{c.id} is #{resend.inspect}" if resend == "all" info "scheduling a resend of #{comment.id} to #{addr} because they're in the thread and resend is #{resend}" @email_sender.send_comment comment, addr end end end |
#start! ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/whisper/email_receiver.rb', line 32 def start! Thread.new do while true begin sleep DELAY step rescue Exception => e warn ["(#{e.class}) #{e.}", e.backtrace].flatten.join("\n") end end end end |
#step ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/whisper/email_receiver.rb', line 47 def step return false if @mbox.eof? content, vars, entry, parent_comment = if content comment = content, vars resend_comments comment, parent_comment, entry end update_offset! true end |
#update_offset! ⇒ Object
206 207 208 |
# File 'lib/whisper/email_receiver.rb', line 206 def update_offset! File.open(@offset_fn, "w") { |f| f.puts @mbox.offset } end |
#write_one_message(content, vars) ⇒ Object
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/whisper/email_receiver.rb', line 146 def content, vars id = Digest::MD5.hexdigest [vars[:author], vars[:entry_id], vars[:message_id]].join("|") dir = File.join @comment_dir, vars[:entry_id] Dir.mkdir dir unless File.exist? dir name = File.join dir, id yaml_fn = name + ENTRY_METADATA_EXTENSION warn "overwriting comment yaml file: #{yaml_fn}" if File.exist? yaml_fn File.open(yaml_fn, "w") { |f| f.puts vars.merge({ :id => id }).to_yaml } textile_fn = name + ENTRY_CONTENT_EXTENSION warn "overwriting comment textile file: #{textile_fn}" if File.exist? textile_fn File.open(textile_fn, "w") { |f| f.print content } info "wrote comment #{yaml_fn}" Comment.new CachedFile.new(yaml_fn), CachedFile.new(textile_fn) end |