echi-converter 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -61,8 +61,21 @@
61
61
 
62
62
  * Major enhancement(s):
63
63
  * Minor enhancement(s):
64
- * Removed some extraneous comments to the log and added others
64
+ * Removed some extraneous comments to the log
65
65
  * Added 'standard' schema definitions for revision 12 & 13 to the config directory
66
66
  * Bug fix(es):
67
67
  * Fixed bug #14020 issue with binary offset
68
- * In binary handling properly insert a Y/N for the booleans
68
+ * In binary handling properly insert a Y/N for the booleans
69
+
70
+ == 0.2.0 2007-10-21
71
+
72
+ * Major enhancement(s):
73
+ * FR#14853 - Added support for ActiveRecord transactions on a per file basis
74
+ * Minor enhancement(s):
75
+ * FR#14855 - Store processed files in a year/month directory structure based on processed date (ie - 2007/10)
76
+ * If the 'echi_ftp_directory' option in application.yml is left blank/nil, the system will not attempt a change directory
77
+ * The system now builds the files to process array from the to_process directory instead of the ftp list, to allow for better recovery if a failure occurs
78
+ * FR#14997 - Added support for sending email alerts if ECHI fails to connect to either the database or an ftp server
79
+ * Bug fix(es):
80
+ * Fixed bug #14585 requiring Hoe for the install
81
+ * Will now properly toggle between the standard schema and the Presence schema (ie - override ActiveRecord defaults)
data/Manifest.txt CHANGED
@@ -6,6 +6,7 @@ Rakefile
6
6
  lib/main.rb
7
7
  lib/echi-converter/version.rb
8
8
  lib/database.rb
9
+ lib/database_presence.rb
9
10
  lib/main.rb
10
11
  lib/echi-converter.rb
11
12
  scripts/txt2html
data/Rakefile CHANGED
@@ -79,6 +79,7 @@ hoe = Hoe.new(GEM_NAME, VERS) do |p|
79
79
  ['activesupport', '>=1.4.2'],
80
80
  ['daemons', '>=1.0.7'],
81
81
  ['fastercsv', '>=1.2.0'],
82
+ ['hoe', '>=1.2.2'],
82
83
  ['rake', '>=0.7.3']
83
84
  ]
84
85
  #p.spec_extras = {} # A hash of extra values to set in the gemspec.
@@ -3,10 +3,10 @@
3
3
  #Connection details for the Avaya CMS/ECHI host
4
4
  echi_host: localhost
5
5
  echi_port: 22
6
- echi_username: your_uname
7
- echi_password: your_passwd
6
+ echi_username: anonymous
7
+ echi_password:
8
8
  echi_connect_type: ftp #only ftp supported now, possible for ssh in the future
9
- echi_ftp_directory: /Users/ftp/anonymous
9
+ echi_ftp_directory: #/Users/ftp/anonymous #If blank/nil, the system will not do a CD at the start
10
10
  echi_ftp_retry: 3
11
11
  echi_ftp_delete: N #to not delete the files off of the FTP server set to N
12
12
  echi_schema: extended_version13.yml
@@ -35,6 +35,12 @@ log_number: 10
35
35
  #The size of each individual log file
36
36
  log_length: 10240000
37
37
 
38
+ #Email address to send alerts to, specifically failures to connect to the DB or FTP servers
39
+ #currently does not support an SMTP server that requires authentication
40
+ alert_email_address: jgoecke@presenceco.com
41
+ smtp_server: mail.presenceco.com
42
+ smtp_port: 25
43
+
38
44
  #Special settings for a specific application database
39
45
  pco_process: N #Set to yes or no if running with a PCO database
40
46
  pco_record_tablename: PCO_ECHIRECORD
@@ -34,6 +34,7 @@ files_to_copy:
34
34
  - name: examples/extended_version12/chr0003
35
35
  - name: examples/extended_version12/chr0003.txt
36
36
  - name: lib/database.rb
37
+ - name: lib/database_presence.rb
37
38
  - name: lib/echi-converter.rb
38
39
  - name: lib/main.rb
39
40
  - name: lib/echi-converter/version.rb
@@ -41,6 +42,7 @@ files_to_copy:
41
42
 
42
43
  files_to_upgrade:
43
44
  - name: lib/database.rb
45
+ - name: lib/database_presence.rb
44
46
  - name: lib/echi-converter.rb
45
47
  - name: lib/main.rb
46
48
  - name: lib/echi-converter/version.rb
data/lib/database.rb CHANGED
@@ -1,25 +1,5 @@
1
1
  class EchiRecord < ActiveRecord::Base
2
- #Determine our working directory
3
- workingdirectory = File.expand_path(File.dirname(__FILE__))
4
- #Open the configuration file
5
- configfile = workingdirectory + '/../config/application.yml'
6
- config = YAML::load(File.open(configfile))
7
-
8
- if config["pco_process"] == 'Y'
9
- set_table_name config["pco_record_tablename"]
10
- set_sequence_name config["pco_record_seqname"]
11
- end
12
2
  end
13
3
 
14
4
  class EchiLog < ActiveRecord::Base
15
- #Determine our working directory
16
- workingdirectory = File.expand_path(File.dirname(__FILE__))
17
- #Open the configuration file
18
- configfile = workingdirectory + '/../config/application.yml'
19
- config = YAML::load(File.open(configfile))
20
-
21
- if config["pco_process"] == 'Y'
22
- set_table_name @config["pco_log_tablename"]
23
- set_sequence_name @config["pco_log_seqname"]
24
- end
25
5
  end
@@ -0,0 +1,9 @@
1
+ class EchiRecord < ActiveRecord::Base
2
+ set_table_name config["pco_record_tablename"]
3
+ set_sequence_name config["pco_record_seqname"]
4
+ end
5
+
6
+ class EchiLog < ActiveRecord::Base
7
+ set_table_name @config["pco_log_tablename"]
8
+ set_sequence_name @config["pco_log_seqname"]
9
+ end
@@ -2,6 +2,7 @@ require 'rubygems'
2
2
  require 'active_record'
3
3
  require 'faster_csv'
4
4
  require 'net/ftp'
5
+ require 'net/smtp'
5
6
  require 'fileutils'
6
7
 
7
8
  class Logger
@@ -34,6 +35,7 @@ module EchiConverter
34
35
  @log.info "Successfully connected to the database"
35
36
  rescue => err
36
37
  @log.fatal "Could not connect to the database - " + err
38
+ send_email_alert "DATABASE"
37
39
  end
38
40
  end
39
41
 
@@ -55,6 +57,46 @@ module EchiConverter
55
57
  end
56
58
  end
57
59
 
60
+ #Method to send alert emails
61
+ def send_email_alert reason
62
+ begin
63
+ Net::SMTP.start(@config["smtp_server"], @config["smtp_port"]) do |smtp|
64
+ smtp.open_message_stream('donotreply@echi-converter.rubyforge.org', [@config["alert_email_address"]]) do |f|
65
+ f.puts "From: donotreply@echi-converter.rubyforge.org"
66
+ f.puts "To: " + @config['alert_email_address']
67
+ f.puts "Subject: ECHI-Converter Failure"
68
+ case reason
69
+ when "DATABASE"
70
+ f.puts "Failed to connect to the database."
71
+ when "FTP"
72
+ f.puts "Failed to connect to the ftp server."
73
+ end
74
+ f.puts " "
75
+ f.puts "Please check the ECHI-Converter environment as soon as possible."
76
+ end
77
+ end
78
+ rescue => err
79
+ @log.warn err
80
+ end
81
+ end
82
+
83
+ #Set the working directory to copy processed files to, if it does not exist creat it
84
+ #Directory names based on year/month so as not to exceed 5K files in a single directory
85
+ def set_directory working_directory
86
+ time = Time.now
87
+ directory_year = working_directory + "/../files/processed/" + time.year.to_s
88
+ directory_month = directory_year + "/" + time.month.to_s
89
+
90
+ if File.exists?(directory_month) == false
91
+ if File.exists?(directory_year) == false
92
+ Dir.mkdir(directory_year)
93
+ end
94
+ Dir.mkdir(directory_month)
95
+ end
96
+
97
+ return directory_month
98
+ end
99
+
58
100
  #Method for parsing the various datatypes from the ECH file
59
101
  def dump_binary type, length
60
102
  case type
@@ -116,61 +158,64 @@ module EchiConverter
116
158
  echi_log.version = fileversion
117
159
  end
118
160
 
119
- bool_cnt = 0
120
- record_cnt = 0
121
- while @binary_file.eof == FALSE do
122
- @log.debug '<====================START RECORD ' + record_cnt.to_s + ' ====================>'
123
- echi_record = EchiRecord.new
124
- @echi_schema["fields"].each do | field |
125
- #We handle the 'boolean' fields differently, as they are all encoded as bits in a single 8-bit byte
126
- if field["type"] == 'bool'
127
- if bool_cnt == 0
128
- bytearray = dump_binary field["type"], field["length"]
129
- end
130
- #Ensure we parse the bytearray and set the appropriate flags
131
- #We need to make sure the entire array is not nil, in order to do Y/N
132
- #if Nil we then set all no
133
- if bytearray != nil
134
- if bytearray.slice(bool_cnt,1) == 1
135
- value = 'Y'
136
- else
161
+ #Perform a transaction for each file, including the log table
162
+ #in order to commit as one atomic action upon success
163
+ EchiRecord.transaction do
164
+ bool_cnt = 0
165
+ @record_cnt = 0
166
+ while @binary_file.eof == FALSE do
167
+ @log.debug '<====================START RECORD ' + @record_cnt.to_s + ' ====================>'
168
+ echi_record = EchiRecord.new
169
+ @echi_schema["fields"].each do | field |
170
+ #We handle the 'boolean' fields differently, as they are all encoded as bits in a single 8-bit byte
171
+ if field["type"] == 'bool'
172
+ if bool_cnt == 0
173
+ bytearray = dump_binary field["type"], field["length"]
174
+ end
175
+ #Ensure we parse the bytearray and set the appropriate flags
176
+ #We need to make sure the entire array is not nil, in order to do Y/N
177
+ #if Nil we then set all no
178
+ if bytearray != nil
179
+ if bytearray.slice(bool_cnt,1) == 1
180
+ value = 'Y'
181
+ else
182
+ value = 'N'
183
+ end
184
+ else
137
185
  value = 'N'
138
186
  end
139
- else
140
- value = 'N'
141
- end
142
- bool_cnt += 1
143
- if bool_cnt == 8
144
- bool_cnt = 0
187
+ bool_cnt += 1
188
+ if bool_cnt == 8
189
+ bool_cnt = 0
190
+ end
191
+ else
192
+ #Process 'standard' fields
193
+ value = dump_binary field["type"], field["length"]
194
+ @log.debug field["name"] + " { type => #{field["type"]} & length => #{field["length"]} } value => " + value.to_s
145
195
  end
146
- else
147
- #Process 'standard' fields
148
- value = dump_binary field["type"], field["length"]
149
- @log.debug field["name"] + " { type => #{field["type"]} & length => #{field["length"]} } value => " + value.to_s
196
+ echi_record[field["name"]] = value
150
197
  end
151
- echi_record[field["name"]] = value
152
- end
153
- echi_record.save
198
+ echi_record.save
154
199
 
155
- #Scan past the end of line record
156
- @binary_file.read(1)
157
- @log.debug '<====================STOP RECORD ' + record_cnt.to_s + ' ====================>'
158
- record_cnt += 1
200
+ #Scan past the end of line record
201
+ @binary_file.read(1)
202
+ @log.debug '<====================STOP RECORD ' + @record_cnt.to_s + ' ====================>'
203
+ @record_cnt += 1
204
+ end
205
+ @binary_file.close
159
206
  end
160
- @binary_file.close
161
207
 
162
208
  #Move the file to the processed directory
163
- destination_directory = @workingdirectory + '/../files/processed/'
164
- FileUtils.mv(echi_file, destination_directory)
209
+ FileUtils.mv(echi_file, @processeddirectory)
165
210
 
166
211
  if @config["echi_process_log"] == "Y"
167
212
  #Finish logging the details on the file
168
- echi_log.records = record_cnt
213
+ echi_log.records = @record_cnt
169
214
  echi_log.processed_at = Time.now
170
215
  echi_log.save
171
216
  end
172
217
 
173
- return record_cnt
218
+ return @record_cnt
174
219
  end
175
220
 
176
221
  def connect_ftpsession
@@ -188,6 +233,7 @@ module EchiConverter
188
233
  end
189
234
  rescue => err
190
235
  @log.fatal "Could not connect with the FTP server - " + err
236
+ send_email_alert "FTP"
191
237
  return -1
192
238
  end
193
239
  return ftp_session
@@ -210,7 +256,9 @@ module EchiConverter
210
256
  end
211
257
  if ftp_session != 0
212
258
  begin
213
- ftp_session.chdir(@config["echi_ftp_directory"])
259
+ if @config["echi_ftp_directory"] != nil
260
+ ftp_session.chdir(@config["echi_ftp_directory"])
261
+ end
214
262
  files = ftp_session.list('chr*')
215
263
  file_cnt = 0
216
264
  files.each do | file |
@@ -249,47 +297,50 @@ def process_ascii filename
249
297
  #echi_log.version = fileversion
250
298
  end
251
299
 
252
- record_cnt = 0
253
- FasterCSV.foreach(echi_file) do |row|
254
- if row != nil
255
- @log.debug '<====================START RECORD ' + record_cnt.to_s + ' ====================>'
256
- echi_record = EchiRecord.new
257
- cnt = 0
258
- @echi_schema["fields"].each do | field |
259
- if field["type"] == "bool" || field["type"] == "bool_int"
260
- case row[cnt]
261
- when "0"
262
- echi_record[field["name"]] = "N"
263
- when "1"
264
- echi_record[field["name"]] = "Y"
265
- end
266
- @log.debug field["name"] + ' == ' + row[cnt]
267
- else
268
- echi_record[field["name"]] = row[cnt]
269
- if row[cnt] != nil
300
+ #Perform a transaction for each file, including the log table
301
+ #in order to commit as one atomic action upon success
302
+ EchiRecord.transaction do
303
+ @record_cnt = 0
304
+ FasterCSV.foreach(echi_file) do |row|
305
+ if row != nil
306
+ @log.debug '<====================START RECORD ' + @record_cnt.to_s + ' ====================>'
307
+ echi_record = EchiRecord.new
308
+ cnt = 0
309
+ @echi_schema["fields"].each do | field |
310
+ if field["type"] == "bool" || field["type"] == "bool_int"
311
+ case row[cnt]
312
+ when "0"
313
+ echi_record[field["name"]] = "N"
314
+ when "1"
315
+ echi_record[field["name"]] = "Y"
316
+ end
270
317
  @log.debug field["name"] + ' == ' + row[cnt]
318
+ else
319
+ echi_record[field["name"]] = row[cnt]
320
+ if row[cnt] != nil
321
+ @log.debug field["name"] + ' == ' + row[cnt]
322
+ end
271
323
  end
324
+ cnt += 1
272
325
  end
273
- cnt += 1
326
+ echi_record.save
327
+ @log.debug '<====================STOP RECORD ' + @record_cnt.to_s + ' ====================>'
328
+ @record_cnt += 1
274
329
  end
275
- echi_record.save
276
- @log.debug '<====================STOP RECORD ' + record_cnt.to_s + ' ====================>'
277
- record_cnt += 1
278
330
  end
279
331
  end
280
332
 
281
333
  #Move the file to the processed directory
282
- destination_directory = @workingdirectory + '/../files/processed/' + filename
283
- FileUtils.mv(echi_file, destination_directory)
334
+ FileUtils.mv(echi_file, @processeddirectory)
284
335
 
285
336
  if @config["echi_process_log"] == "Y"
286
337
  #Finish logging the details on the file
287
- echi_log.records = record_cnt
338
+ echi_log.records = @record_cnt
288
339
  echi_log.processed_at = Time.now
289
340
  echi_log.save
290
341
  end
291
342
 
292
- return record_cnt
343
+ return @record_cnt
293
344
  end
294
345
 
295
346
  require @workingdirectory + '/echi-converter/version.rb'
@@ -1,8 +1,8 @@
1
1
  module EchiConverter #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 1
5
- TINY = 1
4
+ MINOR = 2
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/lib/main.rb CHANGED
@@ -11,7 +11,11 @@ configfile = @workingdirectory + '/../config/application.yml'
11
11
  @config = YAML::load(File.open(configfile))
12
12
 
13
13
  #Load ActiveRecord Models
14
- require @workingdirectory + '/database.rb'
14
+ if @config["pco_process"] == 'Y'
15
+ require @workingdirectory + '/database_presence.rb'
16
+ else
17
+ require @workingdirectory + '/database.rb'
18
+ end
15
19
 
16
20
  #Load the configured schema
17
21
  schemafile = @workingdirectory + "/../config/" + @config["echi_schema"]
@@ -29,12 +33,21 @@ end
29
33
 
30
34
  loop do
31
35
  #Process the files
32
- files = fetch_ftp_files
33
- files.each do | file |
34
- if @config["echi_format"] == 'BINARY'
35
- record_cnt = convert_binary_file file
36
- elsif @config["echi_format"] == 'ASCII'
37
- record_cnt = process_ascii file
36
+ ftp_files = fetch_ftp_files
37
+ #Grab filenames from the to_process directory after an FTP fetch, so if the
38
+ #system fails it may pick up where it left off
39
+ to_process_dir = @workingdirectory + "/../files/to_process/"
40
+
41
+ #Establish where to copy the processed files to
42
+ @processeddirectory = set_directory(@workingdirectory)
43
+
44
+ Dir.entries(to_process_dir).each do | file |
45
+ if file != "." && file != ".."
46
+ if @config["echi_format"] == 'BINARY'
47
+ record_cnt = convert_binary_file file
48
+ elsif @config["echi_format"] == 'ASCII'
49
+ record_cnt = process_ascii file
50
+ end
38
51
  end
39
52
  @log.info "Processed file #{file} with #{record_cnt.to_s} records"
40
53
  end
data/website/index.html CHANGED
@@ -33,7 +33,7 @@
33
33
  <h1>ECHI Converter</h1>
34
34
  <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/echi-converter"; return false'>
35
35
  <p>Get Version</p>
36
- <a href="http://rubyforge.org/projects/echi-converter" class="numbers">0.1.1</a>
36
+ <a href="http://rubyforge.org/projects/echi-converter" class="numbers">0.2.0</a>
37
37
  </div>
38
38
  <h1>&#x2192; &#8216;echi-converter&#8217;</h1>
39
39
 
@@ -61,7 +61,7 @@
61
61
  <li>Generate your schema via ActiveRecord Migrations</li>
62
62
  <li>Fetch Binary or <span class="caps">ASCII CSV</span> files from the Avaya <span class="caps">CMS</span> platform via <span class="caps">FTP</span></li>
63
63
  <li>Convert from the defined Binary format to <span class="caps">ASCII</span></li>
64
- <li>Insert the records into the defined database table</li>
64
+ <li>Insert the records into the defined database table using database transactions, via ActiveRecord, on a per file basis to support recovery on failure</li>
65
65
  <li>Change schema structure via <span class="caps">YML</span> configuration file to accommodate various releases of the <span class="caps">ECHI</span> format</li>
66
66
  </ol>
67
67
 
@@ -86,6 +86,7 @@
86
86
  <li><a href="http://daemons.rubyforge.org/">Daemons v1.0.7+</a></li>
87
87
  <li><a href="http://fastercsv.rubyforge.org/">FasterCSV v1.2.0+</a></li>
88
88
  <li><a href="http://rake.rubyforge.org/">Rake v0.7.3+</a></li>
89
+ <li><a href="http://rubyforge.org/projects/seattlerb/">Hoe v1.2.2+</a></li>
89
90
  </ol>
90
91
 
91
92
 
@@ -175,6 +176,12 @@
175
176
  </ol>
176
177
 
177
178
 
179
+ <h2>Screencast</h2>
180
+
181
+
182
+ <p>You may view the screencast on howto install and use the <span class="caps">ECHI</span>-Converter <a href="http://www.screencast.com/t/lQQkIVkUZMr">here</a>.</p>
183
+
184
+
178
185
  <h2>Forum</h2>
179
186
 
180
187
 
@@ -201,7 +208,7 @@
201
208
 
202
209
  <p>Comments are welcome. Send an email to <a href="mailto:jason@goecke.net">jason [at] goecke.net</a>.</p>
203
210
  <p class="coda">
204
- <a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, 17th September 2007<br>
211
+ <a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, 23rd October 2007<br>
205
212
  Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
206
213
  </p>
207
214
  </div>
data/website/index.txt CHANGED
@@ -20,7 +20,7 @@ The utility provides the following capabilities:
20
20
  # Generate your schema via ActiveRecord Migrations
21
21
  # Fetch Binary or ASCII CSV files from the Avaya CMS platform via FTP
22
22
  # Convert from the defined Binary format to ASCII
23
- # Insert the records into the defined database table
23
+ # Insert the records into the defined database table using database transactions, via ActiveRecord, on a per file basis to support recovery on failure
24
24
  # Change schema structure via YML configuration file to accommodate various releases of the ECHI format
25
25
 
26
26
  # Table names:
@@ -37,6 +37,7 @@ h2. Requirements
37
37
  # "Daemons v1.0.7+":http://daemons.rubyforge.org/
38
38
  # "FasterCSV v1.2.0+":http://fastercsv.rubyforge.org/
39
39
  # "Rake v0.7.3+":http://rake.rubyforge.org/
40
+ # "Hoe v1.2.2+":http://rubyforge.org/projects/seattlerb/
40
41
 
41
42
 
42
43
  h2. Installing
@@ -97,6 +98,9 @@ Items to be done to move this out of alpha stage:
97
98
 
98
99
  # 'echi-converter create' works fine with OSX/Linux, need to test validate with a Win32 platform, therefore currently recommended to only run on a Linux/OSX platform, could use "VMWare":http://www.vmware.com to do this on Windows.
99
100
 
101
+ h2. Screencast
102
+
103
+ You may view the screencast on howto install and use the ECHI-Converter "here":http://www.screencast.com/t/lQQkIVkUZMr.
100
104
 
101
105
  h2. Forum
102
106
 
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: echi-converter
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.1
7
- date: 2007-09-17 00:00:00 -07:00
6
+ version: 0.2.0
7
+ date: 2007-10-23 00:00:00 -07:00
8
8
  summary: ECHI Conversion Utility - Provides a utility to fetch Avaya CMS / ECHI binary files, convert them and insert into a database table via ActiveRecord
9
9
  require_paths:
10
10
  - lib
@@ -37,6 +37,7 @@ files:
37
37
  - lib/main.rb
38
38
  - lib/echi-converter/version.rb
39
39
  - lib/database.rb
40
+ - lib/database_presence.rb
40
41
  - lib/echi-converter.rb
41
42
  - scripts/txt2html
42
43
  - setup.rb