entp-astrotrain 0.2.1 → 0.3.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/Rakefile CHANGED
@@ -1,4 +1,3 @@
1
- require 'rubygems'
2
1
  require 'rake'
3
2
 
4
3
  begin
@@ -9,7 +8,19 @@ begin
9
8
  gem.email = "technoweenie@gmail.com"
10
9
  gem.homepage = "http://github.com/entp/astrotrain"
11
10
  gem.authors = ["technoweenie"]
12
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
11
+
12
+ dm_ver = "0.9.11"
13
+ gem.add_runtime_dependency 'addressable', '2.0.2'
14
+ gem.add_runtime_dependency "tmail", "1.2.3.1"
15
+ gem.add_runtime_dependency "dm-core", dm_ver # The datamapper ORM
16
+ gem.add_runtime_dependency "dm-aggregates", dm_ver # Provides your DM models with count, sum, avg, min, max, etc.
17
+ gem.add_runtime_dependency "dm-timestamps", dm_ver # Automatically populate created_at, created_on, etc. when those properties are present.
18
+ gem.add_runtime_dependency "dm-types", dm_ver # Provides additional types, including csv, json, yaml.
19
+ gem.add_runtime_dependency "dm-validations", dm_ver # Validation framework
20
+ gem.add_development_dependency "context"
21
+ gem.add_development_dependency "rr"
22
+ gem.add_development_dependency "sinatra"
23
+ gem.add_development_dependency "xmppr4-simple"
13
24
  end
14
25
 
15
26
  rescue LoadError
@@ -67,42 +78,8 @@ namespace :at do
67
78
 
68
79
  desc "Start astrotrain DRb server."
69
80
  task :process => :init do
70
- pid_filename = File.join(Astrotrain.root, 'log', 'astrotrain_job.pid')
71
-
72
- FileUtils.mkdir_p File.dirname(pid_filename)
73
- require 'benchmark'
74
-
75
- begin
76
- File.open(pid_filename, 'w') { |f| f << Process.pid.to_s }
77
- SLEEP = 5
78
-
79
- trap('TERM') { puts 'Exiting...'; $exit = true }
80
- trap('INT') { puts 'Exiting...'; $exit = true }
81
-
82
- loop do
83
- count = nil
84
-
85
- realtime = Benchmark.realtime do
86
- files = Dir["#{Astrotrain::Message.queue_path}/*"]
87
- files.each do |mail|
88
- Astrotrain::Message.receive_file(mail)
89
- end
90
- count = files.size
91
- end
92
-
93
- break if $exit
94
-
95
- if count.zero?
96
- sleep(SLEEP)
97
- else
98
- puts "#{count} mails processed at %.4f m/s ..." % [count / realtime]
99
- end
100
-
101
- break if $exit
102
- end
103
- ensure
104
- FileUtils.rm(pid_filename) rescue nil
105
- end
81
+ require 'astrotrain/worker'
82
+ Astrotrain::Worker.start
106
83
  end
107
84
  end
108
85
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.3.0
data/astrotrain.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{astrotrain}
5
- s.version = "0.2.1"
5
+ s.version = "0.3.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["technoweenie"]
9
- s.date = %q{2009-09-23}
9
+ s.date = %q{2009-09-25}
10
10
  s.email = %q{technoweenie@gmail.com}
11
11
  s.extra_rdoc_files = [
12
12
  "LICENSE",
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
29
29
  "lib/astrotrain/mapping/transport.rb",
30
30
  "lib/astrotrain/message.rb",
31
31
  "lib/astrotrain/tmail.rb",
32
+ "lib/astrotrain/worker.rb",
32
33
  "lib/vendor/rest-client/README.rdoc",
33
34
  "lib/vendor/rest-client/Rakefile",
34
35
  "lib/vendor/rest-client/bin/restclient",
@@ -45,10 +46,9 @@ Gem::Specification.new do |s|
45
46
  "lib/vendor/rest-client/spec/request_errors_spec.rb",
46
47
  "lib/vendor/rest-client/spec/resource_spec.rb",
47
48
  "lib/vendor/rest-client/spec/rest_client_spec.rb",
48
- "tasks/doc.thor",
49
- "tasks/merb.thor",
50
49
  "test/api_test.rb",
51
50
  "test/fixtures/apple_multipart.txt",
51
+ "test/fixtures/bad_content_type.txt",
52
52
  "test/fixtures/basic.txt",
53
53
  "test/fixtures/custom.txt",
54
54
  "test/fixtures/fwd.txt",
@@ -89,8 +89,41 @@ Gem::Specification.new do |s|
89
89
  s.specification_version = 3
90
90
 
91
91
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
92
+ s.add_runtime_dependency(%q<addressable>, ["= 2.0.2"])
93
+ s.add_runtime_dependency(%q<tmail>, ["= 1.2.3.1"])
94
+ s.add_runtime_dependency(%q<dm-core>, ["= 0.9.11"])
95
+ s.add_runtime_dependency(%q<dm-aggregates>, ["= 0.9.11"])
96
+ s.add_runtime_dependency(%q<dm-timestamps>, ["= 0.9.11"])
97
+ s.add_runtime_dependency(%q<dm-types>, ["= 0.9.11"])
98
+ s.add_runtime_dependency(%q<dm-validations>, ["= 0.9.11"])
99
+ s.add_development_dependency(%q<context>, [">= 0"])
100
+ s.add_development_dependency(%q<rr>, [">= 0"])
101
+ s.add_development_dependency(%q<sinatra>, [">= 0"])
102
+ s.add_development_dependency(%q<xmppr4-simple>, [">= 0"])
92
103
  else
104
+ s.add_dependency(%q<addressable>, ["= 2.0.2"])
105
+ s.add_dependency(%q<tmail>, ["= 1.2.3.1"])
106
+ s.add_dependency(%q<dm-core>, ["= 0.9.11"])
107
+ s.add_dependency(%q<dm-aggregates>, ["= 0.9.11"])
108
+ s.add_dependency(%q<dm-timestamps>, ["= 0.9.11"])
109
+ s.add_dependency(%q<dm-types>, ["= 0.9.11"])
110
+ s.add_dependency(%q<dm-validations>, ["= 0.9.11"])
111
+ s.add_dependency(%q<context>, [">= 0"])
112
+ s.add_dependency(%q<rr>, [">= 0"])
113
+ s.add_dependency(%q<sinatra>, [">= 0"])
114
+ s.add_dependency(%q<xmppr4-simple>, [">= 0"])
93
115
  end
94
116
  else
117
+ s.add_dependency(%q<addressable>, ["= 2.0.2"])
118
+ s.add_dependency(%q<tmail>, ["= 1.2.3.1"])
119
+ s.add_dependency(%q<dm-core>, ["= 0.9.11"])
120
+ s.add_dependency(%q<dm-aggregates>, ["= 0.9.11"])
121
+ s.add_dependency(%q<dm-timestamps>, ["= 0.9.11"])
122
+ s.add_dependency(%q<dm-types>, ["= 0.9.11"])
123
+ s.add_dependency(%q<dm-validations>, ["= 0.9.11"])
124
+ s.add_dependency(%q<context>, [">= 0"])
125
+ s.add_dependency(%q<rr>, [">= 0"])
126
+ s.add_dependency(%q<sinatra>, [">= 0"])
127
+ s.add_dependency(%q<xmppr4-simple>, [">= 0"])
95
128
  end
96
129
  end
data/lib/astrotrain.rb CHANGED
@@ -36,8 +36,6 @@ private
36
36
  def self.load_dependencies
37
37
  require 'rubygems'
38
38
  gem 'addressable', '2.0.2'
39
- gem "tmail", "1.2.3.1"
40
- gem "xmpp4r-simple", "0.8.8"
41
39
 
42
40
  dm_ver = "0.9.11"
43
41
  gem "dm-core", dm_ver # The datamapper ORM
@@ -48,7 +46,7 @@ private
48
46
 
49
47
  $LOAD_PATH.unshift File.join(lib_root, 'vendor', 'rest-client', 'lib')
50
48
 
51
- %w(dm-core dm-aggregates dm-timestamps dm-types dm-validations xmpp4r-simple tmail rest_client).each do |lib|
49
+ %w(dm-core dm-aggregates dm-timestamps dm-types dm-validations tmail rest_client).each do |lib|
52
50
  require lib
53
51
  end
54
52
  end
@@ -1,4 +1,3 @@
1
- require 'rubygems'
2
1
  require 'sinatra'
3
2
 
4
3
  before do
@@ -16,21 +16,26 @@ module Astrotrain
16
16
  property :sender, String, :index => true, :size => 255, :length => 1..255
17
17
  property :recipient, String, :index => true, :size => 255, :length => 1..255
18
18
  property :subject, String, :index => true, :size => 255, :length => 1..255
19
+ property :mail_file, String, :size => 255, :length => 1..255
19
20
  property :created_at, DateTime
20
21
  property :delivered_at, DateTime
21
- property :error_message, String, :size => 255, :length => 1..255
22
+ property :error_message, Text
22
23
 
23
24
  belongs_to :mapping
24
25
 
25
- def self.from(message)
26
+ def self.from(message, file = nil)
26
27
  logged = new
27
28
  begin
28
- logged.sender = Message.parse_email_addresses(message.sender).first
29
- logged.subject = message.subject
29
+ logged.sender = Message.parse_email_addresses(message.sender).first
30
+ logged.subject = message.subject
31
+ logged.mail_file = file if file
30
32
  end
31
33
  if !block_given? || yield(logged)
32
34
  begin
33
35
  logged.save
36
+ if logged.delivered_at && File.exist?(logged.mail_file.to_s)
37
+ FileUtils.rm_rf logged.mail_file
38
+ end
34
39
  rescue
35
40
  puts $!.inspect
36
41
  end
@@ -38,8 +38,8 @@ module Astrotrain
38
38
 
39
39
  # Processes a given message. It finds a mapping, creates a LoggedMail record,
40
40
  # and attempts to process the message.
41
- def self.process(message)
42
- LoggedMail.from(message) do |logged|
41
+ def self.process(message, file = nil)
42
+ LoggedMail.from(message, file) do |logged|
43
43
  save_logged = begin
44
44
  mapping, recipient = match(message.recipients)
45
45
  if mapping
@@ -50,7 +50,7 @@ module Astrotrain
50
50
  end
51
51
  LoggedMail.log_processed # save successfully processed messages?
52
52
  rescue
53
- logged.error_message = "#{$!.class}: #{$!}"
53
+ logged.error_message = "#{$!.message}\n#{$!.backtrace.join("\n")}"
54
54
  end
55
55
  Astrotrain.callback(:post_processing, message, mapping, logged)
56
56
  save_logged
@@ -1,23 +1,28 @@
1
- module Astrotrain
2
- class Mapping
3
- # This is experimental. No attachments are supported.
4
- class Jabber < Transport
5
- class << self
6
- attr_accessor :login, :password
7
- end
1
+ begin
2
+ require 'xmpp4r-simple'
3
+ module Astrotrain
4
+ class Mapping
5
+ # This is experimental. No attachments are supported.
6
+ class Jabber < Transport
7
+ class << self
8
+ attr_accessor :login, :password
9
+ end
8
10
 
9
- def process
10
- return unless Transport.processing
11
- connection.deliver(@mapping.destination, content)
12
- end
11
+ def process
12
+ return unless Transport.processing
13
+ connection.deliver(@mapping.destination, content)
14
+ end
13
15
 
14
- def connection
15
- @connection ||= ::Jabber::Simple.new(self.class.login, self.class.password)
16
- end
16
+ def connection
17
+ @connection ||= ::Jabber::Simple.new(self.class.login, self.class.password)
18
+ end
17
19
 
18
- def content
19
- @content ||= "From: %s\nTo: %s\nSubject: %s\nEmails: %s\n%s" % [fields[:from], fields[:to], fields[:subject], fields[:emails] * ", ", fields[:body]]
20
+ def content
21
+ @content ||= "From: %s\nTo: %s\nSubject: %s\nEmails: %s\n%s" % [fields[:from], fields[:to], fields[:subject], fields[:emails] * ", ", fields[:body]]
22
+ end
20
23
  end
21
24
  end
22
25
  end
26
+ rescue LoadError
27
+ puts "Install xmpp4r-simple for Jabber support."
23
28
  end
@@ -49,25 +49,25 @@ module Astrotrain
49
49
  end
50
50
 
51
51
  # Parses the given raw email text and processes it with a matching Mapping.
52
- def self.receive(raw)
52
+ def self.receive(raw, file = nil)
53
53
  message = parse(raw)
54
54
  Astrotrain.callback(:pre_mapping, message)
55
- Mapping.process(message)
55
+ Mapping.process(message, file)
56
56
  message
57
57
  end
58
58
 
59
59
  # Processes the given file. It parses it by reading the contents, and optionally
60
60
  # archives or removes the original file.
61
- def self.receive_file(path, raw = nil)
62
- message = receive IO.read(path)
61
+ def self.receive_file(path)
62
+ raw = IO.read(path)
63
+ logged_path = path
63
64
  if archive_path
64
65
  daily_archive_path = archive_path / Time.now.year.to_s / Time.now.month.to_s / Time.now.day.to_s
65
66
  FileUtils.mkdir_p(daily_archive_path)
66
- FileUtils.mv path, daily_archive_path / File.basename(path)
67
- else
68
- FileUtils.rm_rf path
67
+ logged_path = daily_archive_path / File.basename(path)
68
+ FileUtils.mv path, logged_path if path != logged_path
69
69
  end
70
- message
70
+ receive(raw, logged_path)
71
71
  end
72
72
 
73
73
  # Parses the raw email headers into a Astrotrain::Message instance.
@@ -0,0 +1,61 @@
1
+ require 'benchmark'
2
+ module Astrotrain
3
+ class Worker
4
+ attr_accessor :logger, :sleep_duration, :name
5
+
6
+ def self.start(options = {})
7
+ new(options).run
8
+ end
9
+
10
+ def initialize(options = {})
11
+ @name = options[:name] || "pid:#{Process.pid}"
12
+ @pid = options[:pid] || File.join(Astrotrain.root, 'log', 'astrotrain_job.pid')
13
+ @sleep_duration = options[:sleep] || 5
14
+ @logger = options.key?(:logger) ? options[:logger] : STDOUT
15
+ end
16
+
17
+ def run
18
+ setup do
19
+ files = 0
20
+ Dir.foreach(Message.queue_path) do |f|
21
+ next if f =~ /^\.{1,2}$/
22
+ files += 1
23
+ file = File.join(Message.queue_path, f)
24
+ Message.receive_file(file)
25
+ end
26
+ files
27
+ end
28
+ end
29
+
30
+ def say(s)
31
+ @logger << "#{s}\n" if @logger
32
+ end
33
+
34
+ def setup
35
+ say "*** Starting Astrotrain::Worker #{@name}"
36
+ FileUtils.mkdir_p File.dirname(@pid)
37
+
38
+ File.open(@pid, 'w') { |f| f << Process.pid.to_s }
39
+
40
+ trap('TERM') { puts 'Exiting...'; $exit = true }
41
+ trap('INT') { puts 'Exiting...'; $exit = true }
42
+
43
+ loop do
44
+ count = nil
45
+ realtime = Benchmark.realtime { count = yield }
46
+
47
+ break if $exit
48
+
49
+ if count.zero?
50
+ sleep(@sleep_duration)
51
+ else
52
+ puts "#{count} mails processed at %.4f m/s ..." % [count / realtime]
53
+ end
54
+
55
+ break if $exit
56
+ end
57
+ ensure
58
+ FileUtils.rm(@pid) rescue nil
59
+ end
60
+ end
61
+ end
@@ -137,7 +137,6 @@ module RestClient
137
137
 
138
138
  net = Net::HTTP.new(uri.host, uri.port)
139
139
  net.use_ssl = uri.is_a?(URI::HTTPS)
140
-
141
140
  net.start do |http|
142
141
  ## Ok. I know this is weird but it's a hack for now
143
142
  ## this lets process_result determine if it should read the body
@@ -5,6 +5,8 @@
5
5
  # Taken from:
6
6
  # http://www.missiondata.com/blog/ruby/29/streaming-data-to-s3-with-ruby/
7
7
 
8
+ Net::HTTP.ssl_context_accessor(:tmp_dh_callback)
9
+
8
10
  module Net
9
11
  class HTTP
10
12
  alias __request__ request
@@ -0,0 +1,27 @@
1
+ Delivered-To: "Processor" <processor@astrotrain.com>
2
+ Message-ID: <a16be7390810161014n52b603e9k1aa6bb803c6735aa@mail.gmail.com>
3
+ Date: Thu, 16 Oct 2008 10:14:18 -0700
4
+ From: Bob <user@example.com>
5
+ To: Processor <processor@astrotrain.com>
6
+ Subject: Fwd: blah blah
7
+ MIME-Version: 1.0
8
+ X-Custom: reply
9
+ Content-Type: multipart/mixed; boundary="====boundary===="
10
+ Content-Transfer-Encoding: 7bit
11
+ Content-Disposition: inline
12
+
13
+ --====boundary====
14
+ Content-Type: text/plain; charset="us-ascii"
15
+
16
+ This message is being generated automatically to notify you
17
+ that PowerMTA has crashed on mtasv.net.
18
+
19
+ As the information below is likely to be essential for debugging
20
+ the problem, please forward this message to <support@port25.com>.
21
+ Thank you.
22
+
23
+ --====boundary====
24
+ Content-Type: text/plain; charset="us-ascii"
25
+
26
+ Yo
27
+ --====boundary====--
@@ -7,7 +7,7 @@ class Astrotrain::LoggedMailTest < Astrotrain::TestCase
7
7
  @mapping = Astrotrain::Mapping.create!(:email_user => '*')
8
8
  @raw = mail(:custom)
9
9
  @message = Astrotrain::Message.parse(@raw)
10
- @logged = Astrotrain::LoggedMail.from(@message) do |l|
10
+ @logged = Astrotrain::LoggedMail.from(@message, 'foo/bar') do |l|
11
11
  l.recipient = @message.recipients(%w(delivered_to)).first
12
12
  l.mapping = @mapping
13
13
  end
@@ -17,6 +17,10 @@ class Astrotrain::LoggedMailTest < Astrotrain::TestCase
17
17
  assert_equal @message.recipients(%w(delivered_to)).first, @logged.recipient
18
18
  end
19
19
 
20
+ it "sets mail_file" do
21
+ assert_equal 'foo/bar', @logged.mail_file
22
+ end
23
+
20
24
  it "sets sender" do
21
25
  assert_equal 'user@example.com', @logged.sender
22
26
  end
data/test/test_helper.rb CHANGED
@@ -18,6 +18,9 @@ module Astrotrain
18
18
  })
19
19
  end
20
20
 
21
+ LoggedMail.auto_migrate!
22
+ Mapping.auto_migrate!
23
+
21
24
  LoggedMail.log_path = Astrotrain.root / 'messages'
22
25
  FileUtils.rm_rf LoggedMail.log_path
23
26
  FileUtils.mkdir_p LoggedMail.log_path