cdr-fetcher 1.0.1

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/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Carl Hicks
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,51 @@
1
+ = cdr-fetcher
2
+
3
+ A rubygem for fetching CDR's from a remote system via SSH/SFTP.
4
+ Supports fetching all files, or a delta from a given offset.
5
+
6
+ == FEATURES/PROBLEMS:
7
+
8
+ * Supports asterisk cdr-csv output format
9
+ * Supports multiple directories
10
+ * Returns a format-neutral data structure
11
+
12
+ == SYNOPSIS:
13
+
14
+ require 'cdr-fetcher'
15
+ require 'pp'
16
+
17
+ cdrs = CDR::Fetcher.new(
18
+ 'hostname',
19
+ 'username',
20
+ :password => 'password',
21
+ :base_dir => '/var/log/asterisk/cdr-csv',
22
+ :last_dir => 'old-cdrs',
23
+ :last_file => 'old-cdr.csv')
24
+
25
+ cdrs.each do |cdr|
26
+ pp cdr
27
+ end
28
+
29
+ == REQUIREMENTS:
30
+
31
+ * net-ssh gem
32
+ * net-sftp gem
33
+
34
+ == INSTALL:
35
+
36
+ * sudo gem install cdr-fetcher
37
+
38
+
39
+ == Note on Patches/Pull Requests
40
+
41
+ * Fork the project.
42
+ * Make your feature addition or bug fix.
43
+ * Add tests for it. This is important so I don't break it in a
44
+ future version unintentionally.
45
+ * Commit, do not mess with rakefile, version, or history.
46
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
47
+ * Send me a pull request. Bonus points for topic branches.
48
+
49
+ == Copyright
50
+
51
+ Copyright (c) 2010 Carl Hicks. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "cdr-fetcher"
8
+ gem.summary = %Q{A gem for fetching CDR's from a remote system.}
9
+ gem.description = %Q{A gem for fetching CDR data from a remote system via SSH/SFTP. Supports fetching all files, or a delta from a given offset.}
10
+ gem.email = "carl.hicks@gmail.com"
11
+ gem.homepage = "http://github.com/chicks/cdr-fetcher"
12
+ gem.authors = ["Carl Hicks"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ gem.add_dependency 'net-sftp'
15
+ gem.add_dependency 'net-ssh'
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ end
22
+
23
+ require 'rake/testtask'
24
+ Rake::TestTask.new(:test) do |test|
25
+ test.libs << 'lib' << 'test'
26
+ test.pattern = 'test/**/test_*.rb'
27
+ test.verbose = true
28
+ end
29
+
30
+ begin
31
+ require 'rcov/rcovtask'
32
+ Rcov::RcovTask.new do |test|
33
+ test.libs << 'test'
34
+ test.pattern = 'test/**/test_*.rb'
35
+ test.verbose = true
36
+ end
37
+ rescue LoadError
38
+ task :rcov do
39
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
40
+ end
41
+ end
42
+
43
+ task :test => :check_dependencies
44
+
45
+ task :default => :test
46
+
47
+ require 'rake/rdoctask'
48
+ Rake::RDocTask.new do |rdoc|
49
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "cdr-fetcher #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.1
@@ -0,0 +1,59 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{cdr-fetcher}
8
+ s.version = "1.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Carl Hicks"]
12
+ s.date = %q{2010-07-15}
13
+ s.description = %q{A gem for fetching CDR data from a remote system via SSH/SFTP. Supports fetching all files, or a delta from a given offset.}
14
+ s.email = %q{carl.hicks@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".gitignore",
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "cdr-fetcher.gemspec",
26
+ "lib/cdr-fetcher.rb",
27
+ "test/helper.rb",
28
+ "test/test_cdr-fetcher.rb"
29
+ ]
30
+ s.homepage = %q{http://github.com/chicks/cdr-fetcher}
31
+ s.rdoc_options = ["--charset=UTF-8"]
32
+ s.require_paths = ["lib"]
33
+ s.rubygems_version = %q{1.3.7}
34
+ s.summary = %q{A gem for fetching CDR's from a remote system.}
35
+ s.test_files = [
36
+ "test/helper.rb",
37
+ "test/test_cdr-fetcher.rb"
38
+ ]
39
+
40
+ if s.respond_to? :specification_version then
41
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
42
+ s.specification_version = 3
43
+
44
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
45
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
46
+ s.add_runtime_dependency(%q<net-sftp>, [">= 0"])
47
+ s.add_runtime_dependency(%q<net-ssh>, [">= 0"])
48
+ else
49
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
50
+ s.add_dependency(%q<net-sftp>, [">= 0"])
51
+ s.add_dependency(%q<net-ssh>, [">= 0"])
52
+ end
53
+ else
54
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
55
+ s.add_dependency(%q<net-sftp>, [">= 0"])
56
+ s.add_dependency(%q<net-ssh>, [">= 0"])
57
+ end
58
+ end
59
+
@@ -0,0 +1,210 @@
1
+ module CDR
2
+
3
+ require 'csv'
4
+ require 'rubygems'
5
+ require 'net/ssh'
6
+ require 'net/sftp'
7
+
8
+ # Fetch CDR's from a remote server.
9
+ #
10
+ # :base_dir defaults to "/var/log/asterisk/cdr-csv".
11
+ # :last_dir defaults to the first sub-directory
12
+ # in :base_dir.
13
+ # :last_file defaults to the first file in :last_dir.
14
+ #
15
+ # Usage:
16
+ #
17
+ # require 'cdr-fetcher'
18
+ # require 'pp'
19
+ #
20
+ # cdrs = CDR::Fetcher.new(
21
+ # 'hostname',
22
+ # 'username',
23
+ # :password => 'password',
24
+ # :base_dir => '/var/log/asterisk/cdr-csv',
25
+ # :last_dir => 'old-cdrs',
26
+ # :last_file=> 'old-cdr.csv')
27
+ #
28
+ # cdrs.each do |cdr|
29
+ # pp cdr
30
+ # end
31
+ #
32
+ class Fetcher
33
+ attr :hostname, false
34
+ attr :username, false
35
+ attr :password, false
36
+ attr :base_dir, false
37
+ attr :last_dir, true
38
+ attr :last_file, true
39
+
40
+ # Create a new instance of Fetcher
41
+ #
42
+ # :base_dir defaults to "/var/log/asterisk/cdr-csv".
43
+ # :last_dir defaults to the first sub-directory
44
+ # in :base_dir.
45
+ # :last_file defaults to the first file in :last_dir.
46
+ def initialize(hostname, username, opts={})
47
+ # Process options and arguments
48
+ opts = { :password => nil,
49
+ :base_dir => nil,
50
+ :last_dir => nil,
51
+ :last_file=> nil
52
+ }.merge!(opts)
53
+ @hostname = hostname
54
+ @username = username
55
+ @password = opts[:password]
56
+ @base_dir = opts[:base_dir]
57
+ @base_dir ||= '/var/log/asterisk/cdr-csv'
58
+
59
+ # Setup SSH and SFTP Connection
60
+ @ssh = Net::SSH.start(@hostname, @username, :password => @password)
61
+ @sftp = Net::SFTP::Session.new(@ssh).connect!
62
+
63
+ # Grab the list of directories, and the current directory attributes
64
+ @directories = directories
65
+ @cur_dir = directory(opts[:last_dir])
66
+ # If we weren't passed an argument, use the first file in the list
67
+ @cur_dir ||= @directories[0]
68
+
69
+ # Grab the list of files from the current directory
70
+ @files = files
71
+ @cur_file = file(opts[:last_file])
72
+ # If we weren't passed an argument, use the first file in the list
73
+ @cur_file ||= @files[0]
74
+ end
75
+
76
+ # Iterator for Files. Returns one file path at a time, automatically
77
+ # moving to the next file or directory until all CDRs have been
78
+ # returned.
79
+ def each_file
80
+ while true
81
+ file = @cur_file
82
+ if file
83
+ yield [@base_dir,@cur_dir.name,@cur_file.name].join("/")
84
+ next_file!
85
+ else
86
+ break
87
+ end
88
+ end
89
+ end
90
+
91
+ # Iterator for CDRs. Returns one CDR at a time, automatically
92
+ # moving to the next file or directory until all CDRs have been
93
+ # returned.
94
+ #
95
+ # CDR files are read into memory one at a time.
96
+ #
97
+ # Line numbers are NOT zero indexed (i.e. line 1 == line 1 NOT line 0)
98
+ def each
99
+ each_file do |file|
100
+ @sftp.download!(file).split(/\n/).each_with_index do |line,i|
101
+ cdr = {
102
+ :hostname => @hostname,
103
+ :file => file,
104
+ :line => i+1,
105
+ :cdr => CSV.parse_line(line)
106
+ }
107
+ yield cdr
108
+ end
109
+ end
110
+ end
111
+
112
+ protected
113
+
114
+ # Set @cur_file to the next file.
115
+ # Changes to next directory if all files in the current directory
116
+ # have been read.
117
+ def next_file!
118
+ @files.each_with_index { |file,i|
119
+ # find our current location
120
+ if @cur_file == file
121
+ next_file = @files[i+1]
122
+ # If we dont hit the end of the array, everything is good.
123
+ if next_file != nil
124
+ @cur_file = next_file
125
+ return @cur_file
126
+ # if we hit the end of the array, we need to go to the next directory
127
+ else
128
+ # If we run out of directories, we need to exit properly.
129
+ dir = next_dir!
130
+ if dir
131
+ return @cur_file
132
+ else
133
+ return false
134
+ end
135
+ end
136
+ end
137
+ }
138
+ end
139
+
140
+ # Set @cur_dir to the next directory.
141
+ # Updates @cur_file to the first file in that directory
142
+ def next_dir!
143
+ @directories.each_with_index {|dir,i|
144
+ # find our current location
145
+ if @cur_dir == dir
146
+ next_dir = @directories[i+1]
147
+ if next_dir != nil
148
+ @cur_dir = next_dir
149
+ @files = files
150
+ @cur_file = @files[0]
151
+ return @cur_dir
152
+ else
153
+ return false
154
+ end
155
+ end
156
+ }
157
+ end
158
+
159
+ # Return an Array of subdirectories in the @base_dir
160
+ def directories
161
+ directories = []
162
+ @sftp.dir.foreach(@base_dir) do |entry|
163
+ # skip parent, or hidden files/directories
164
+ next if entry.name =~ /^\.+$/
165
+ # skip files
166
+ next unless entry.directory?
167
+ # store everything else
168
+ directories << entry
169
+ end
170
+ # Sort directories by modification time
171
+ directories.sort! {|a,b| a.attributes.mtime <=> b.attributes.mtime}
172
+ directories
173
+ end
174
+
175
+ # Searches for a directory entry by name
176
+ # Returns a directory object from the list of directories
177
+ def directory(dir_name)
178
+ @directories.each do |dir|
179
+ return dir if dir.name == dir_name
180
+ end
181
+ false
182
+ end
183
+
184
+ # Return a list of files in @cur_dir
185
+ def files
186
+ files = []
187
+ @sftp.dir.foreach(@base_dir + "/" + @cur_dir.name) do |file|
188
+ # ignore directories
189
+ next unless file.file?
190
+ files << file
191
+ end
192
+ # Sort each file by modification time
193
+ files.sort! {|a,b| a.attributes.mtime <=> b.attributes.mtime }
194
+ files
195
+ end
196
+
197
+ # Searches for a file entry by name
198
+ # Returns a file object from the list of files
199
+ def file(file_name)
200
+ @files.each do |file|
201
+ return file if file.name == file_name
202
+ end
203
+ false
204
+ end
205
+
206
+ end
207
+
208
+ end
209
+
210
+
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'cdr-fetcher'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestCdrFetcher < Test::Unit::TestCase
4
+ #should "probably rename this file and start testing for real" do
5
+ # flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ #end
7
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cdr-fetcher
3
+ version: !ruby/object:Gem::Version
4
+ hash: 21
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 1
10
+ version: 1.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Carl Hicks
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-07-15 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: thoughtbot-shoulda
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: net-sftp
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: net-ssh
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :runtime
62
+ version_requirements: *id003
63
+ description: A gem for fetching CDR data from a remote system via SSH/SFTP. Supports fetching all files, or a delta from a given offset.
64
+ email: carl.hicks@gmail.com
65
+ executables: []
66
+
67
+ extensions: []
68
+
69
+ extra_rdoc_files:
70
+ - LICENSE
71
+ - README.rdoc
72
+ files:
73
+ - .gitignore
74
+ - LICENSE
75
+ - README.rdoc
76
+ - Rakefile
77
+ - VERSION
78
+ - cdr-fetcher.gemspec
79
+ - lib/cdr-fetcher.rb
80
+ - test/helper.rb
81
+ - test/test_cdr-fetcher.rb
82
+ has_rdoc: true
83
+ homepage: http://github.com/chicks/cdr-fetcher
84
+ licenses: []
85
+
86
+ post_install_message:
87
+ rdoc_options:
88
+ - --charset=UTF-8
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ hash: 3
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ hash: 3
106
+ segments:
107
+ - 0
108
+ version: "0"
109
+ requirements: []
110
+
111
+ rubyforge_project:
112
+ rubygems_version: 1.3.7
113
+ signing_key:
114
+ specification_version: 3
115
+ summary: A gem for fetching CDR's from a remote system.
116
+ test_files:
117
+ - test/helper.rb
118
+ - test/test_cdr-fetcher.rb