Introduction
Introduction Statistics Contact Development Disclaimer Help
Tabs to spaces - warvox - VoIP based wardialing tool, forked from rapid7/warvox.
Log
Files
Refs
README
---
commit 6fc7895fc496df7a5acdc2f22d6e60fb70f1ca65
parent 922c8b67c39f72646441de35353bb87401adea71
Author: HD Moore <[email protected]>
Date: Wed, 2 Mar 2016 16:04:08 -0600
Tabs to spaces
Diffstat:
M app/controllers/application_contro… | 100 ++++++++++++++++-----------…
M app/controllers/calls_controller.rb | 46 ++++++++++++++++-------------…
M app/controllers/home_controller.rb | 38 ++++++++++++++++-------------…
M app/controllers/jobs_controller.rb | 684 ++++++++++++++++-------------…
M app/controllers/projects_controlle… | 266 ++++++++++++++++-----------…
M app/controllers/providers_controll… | 28 ++++++++++++++--------------
M app/controllers/user_sessions_cont… | 36 ++++++++++++++++-----------…
M app/helpers/analyze_helper.rb | 12 ++++++------
M app/helpers/application_helper.rb | 344 +++++++++++++++---------------
M app/models/call_medium.rb | 4 ++--
M app/models/job.rb | 284 ++++++++++++++++-------------…
M app/models/line.rb | 24 ++++++++++++------------
M app/models/line_attribute.rb | 4 ++--
M app/models/project.rb | 18 +++++++++---------
M app/models/provider.rb | 10 +++++-----
M app/models/settings.rb | 2 +-
M app/models/signature.rb | 2 +-
M app/models/signature_fp.rb | 2 +-
M app/models/user.rb | 14 +++++++-------
M app/models/user_session.rb | 2 +-
M bin/adduser | 72 ++++++++++++++++-------------…
M bin/analyze_result.rb | 14 +++++++-------
M bin/audio_raw_to_fprint.rb | 16 ++++++++--------
M bin/audio_raw_to_wav.rb | 16 ++++++++--------
M bin/audio_trim.rb | 20 ++++++++++----------
M bin/cache_clear.rb | 2 +-
M bin/export_audio.rb | 98 ++++++++++++++++-------------…
M bin/export_list.rb | 46 ++++++++++++++++-------------…
M bin/iaxrecord.rb | 62 ++++++++++++++++-------------…
M bin/identify_matches.rb | 68 ++++++++++++++++-------------…
M bin/import_audio.rb | 110 ++++++++++++++++-------------…
M bin/resetpw | 40 ++++++++++++++++-------------…
M bin/verify_install.rb | 34 ++++++++++++++++-------------…
M bin/warvox.rb | 64 ++++++++++++++++-------------…
M bin/worker.rb | 44 ++++++++++++++++-------------…
M bin/worker_manager.rb | 220 ++++++++++++++++-------------…
M config/classifiers/01.default.rb | 28 ++++++++++++++--------------
M config/classifiers/99.default.rb | 8 ++++----
M db/migrate/20121228171549_initial_… | 360 ++++++++++++++++-----------…
M lib/warvox.rb | 10 +++++-----
M lib/warvox/audio/raw.rb | 646 ++++++++++++++++-------------…
M lib/warvox/config.rb | 310 ++++++++++++++++-------------…
M lib/warvox/jobs.rb | 118 ++++++++++++++++-------------…
M lib/warvox/jobs/analysis.rb | 828 +++++++++++++++---------------
M lib/warvox/jobs/base.rb | 52 ++++++++++++++++-------------…
M lib/warvox/jobs/dialer.rb | 438 ++++++++++++++++-------------…
M lib/warvox/phone.rb | 96 ++++++++++++++++-------------…
M lib/warvox/proto/iax2/client.rb | 10 +++++-----
M spec/factories/call_media.rb | 8 ++++----
M spec/factories/calls.rb | 12 ++++++------
M spec/factories/jobs.rb | 22 +++++++++++-----------
M spec/factories/lines.rb | 8 ++++----
M spec/factories/projects.rb | 8 ++++----
M spec/factories/providers.rb | 18 +++++++++---------
M spec/factories/settings.rb | 6 +++---
M spec/factories/signature_fps.rb | 6 +++---
M spec/factories/signatures.rb | 16 ++++++++--------
M spec/factories/users.rb | 14 +++++++-------
M spec/features/projects_spec.rb | 38 ++++++++++++++++-------------…
M spec/features/visitor/logins_spec.… | 100 ++++++++++++++++-----------…
M spec/models/call_medium_spec.rb | 10 +++++-----
M spec/models/call_spec.rb | 14 +++++++-------
M spec/models/job_spec.rb | 12 ++++++------
M spec/models/line_spec.rb | 10 +++++-----
M spec/models/project_spec.rb | 20 ++++++++++----------
M spec/models/provider_spec.rb | 28 ++++++++++++++--------------
M spec/models/settings_spec.rb | 6 +++---
M spec/models/signature_spec.rb | 12 ++++++------
M spec/models/user_spec.rb | 10 +++++-----
M spec/rails_helper.rb | 44 ++++++++++++++++-------------…
M spec/support/auth_logic_helpers.rb | 28 ++++++++++++++--------------
71 files changed, 3100 insertions(+), 3100 deletions(-)
---
diff --git a/app/controllers/application_controller.rb b/app/controllers/applic…
@@ -1,68 +1,68 @@
class ApplicationController < ActionController::Base
- protect_from_forgery
- helper :all
+ protect_from_forgery
+ helper :all
- helper_method :current_user_session, :current_user
- before_filter :require_user, :load_project
- add_breadcrumb :projects, :root_path
+ helper_method :current_user_session, :current_user
+ before_filter :require_user, :load_project
+ add_breadcrumb :projects, :root_path
- include ActionView::Helpers::NumberHelper
+ include ActionView::Helpers::NumberHelper
private
- def current_user_session
- return @current_user_session if defined?(@current_user_session)
- @current_user_session = UserSession.find
- end
+ def current_user_session
+ return @current_user_session if defined?(@current_user_session)
+ @current_user_session = UserSession.find
+ end
- def current_user
- return @current_user if defined?(@current_user)
- @current_user = current_user_session && current_user_session.r…
- end
+ def current_user
+ return @current_user if defined?(@current_user)
+ @current_user = current_user_session && current_user_session.record
+ end
- def require_user
- unless current_user
- store_location
- flash.now[:notice] = "You must be logged in to access …
- redirect_to '/login'
- return false
- end
- end
+ def require_user
+ unless current_user
+ store_location
+ flash.now[:notice] = "You must be logged in to access this page"
+ redirect_to '/login'
+ return false
+ end
+ end
- def require_no_user
- if current_user
- store_location
- flash[:notice] = "You must be logged out to access thi…
- redirect_to user_path(current_user)
- return false
- end
- end
+ def require_no_user
+ if current_user
+ store_location
+ flash[:notice] = "You must be logged out to access this page"
+ redirect_to user_path(current_user)
+ return false
+ end
+ end
- def store_location
- session[:return_to] = request.fullpath
- end
+ def store_location
+ session[:return_to] = request.fullpath
+ end
- def redirect_back_or_default(default)
- redirect_to(session[:return_to] || default)
- session[:return_to] = nil
- end
+ def redirect_back_or_default(default)
+ redirect_to(session[:return_to] || default)
+ session[:return_to] = nil
+ end
- def load_project
- # Only load this when we are logged in
- return true unless current_user
+ def load_project
+ # Only load this when we are logged in
+ return true unless current_user
- if params[:project_id]
- @project = Project.where(:id => params[:project_id].to…
- elsif session[:project_id]
- @project = Project.where(:id => session[:project_id].t…
- end
+ if params[:project_id]
+ @project = Project.where(:id => params[:project_id].to_i).first
+ elsif session[:project_id]
+ @project = Project.where(:id => session[:project_id].to_i).first
+ end
- if @project and @project.id and not (session[:project_id] and …
- session[:project_id] = @project.id
- end
+ if @project and @project.id and not (session[:project_id] and session[:pro…
+ session[:project_id] = @project.id
+ end
- true
- end
+ true
+ end
end
diff --git a/app/controllers/calls_controller.rb b/app/controllers/calls_contro…
@@ -4,9 +4,9 @@ class CallsController < ApplicationController
# GET /calls.xml
def index
@jobs = @project.jobs.order('id DESC').where('task = ? AND completed_at IS…
- :page => params[:page],
- :per_page => 30
- )
+ :page => params[:page],
+ :per_page => 30
+ )
respond_to do |format|
format.html # index.html.erb
@@ -18,21 +18,21 @@ class CallsController < ApplicationController
# GET /calls/1/view.xml
def view
@calls = Call.order('id DESC').where(:job_id => params[:id]).paginate(
- :page => params[:page],
- :per_page => 30
- )
-
- unless @calls and @calls.length > 0
- redirect_to :action => :index
- return
- end
- @call_results = {
- :Timeout => Call.count(:conditions =>['job_id = ? and answere…
- :Busy => Call.count(:conditions =>['job_id = ? and busy = …
- :Answered => Call.count(:conditions =>['job_id = ? and answere…
- }
-
- respond_to do |format|
+ :page => params[:page],
+ :per_page => 30
+ )
+
+ unless @calls and @calls.length > 0
+ redirect_to :action => :index
+ return
+ end
+ @call_results = {
+ :Timeout => Call.count(:conditions =>['job_id = ? and answered = ?', para…
+ :Busy => Call.count(:conditions =>['job_id = ? and busy = ?', params[:…
+ :Answered => Call.count(:conditions =>['job_id = ? and answered = ?', para…
+ }
+
+ respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @calls }
end
@@ -43,10 +43,10 @@ class CallsController < ApplicationController
def show
@call = Call.find(params[:id])
- unless @call
- redirect_to :action => :index
- return
- end
+ unless @call
+ redirect_to :action => :index
+ return
+ end
respond_to do |format|
format.html # show.html.erb
@@ -109,7 +109,7 @@ class CallsController < ApplicationController
def destroy
@job = Job.find(params[:id])
- @job.destroy
+ @job.destroy
respond_to do |format|
format.html { redirect_to :action => 'index' }
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controll…
@@ -1,27 +1,27 @@
class HomeController < ApplicationController
- def index
+ def index
- end
+ end
- def about
- begin
- @has_kissfft = "MISSING"
- require 'kissfft'
- @has_kissfft = $LOADED_FEATURES.grep(/kissfft/)[0]
- rescue ::LoadError
- end
- end
+ def about
+ begin
+ @has_kissfft = "MISSING"
+ require 'kissfft'
+ @has_kissfft = $LOADED_FEATURES.grep(/kissfft/)[0]
+ rescue ::LoadError
+ end
+ end
- def help
- end
+ def help
+ end
- def check
- @has_project = ( Project.count > 0 )
- @has_provider = ( Provider.where(:enabled => true).count > 0 )
- @has_job = ( Job.where(:task => 'dialer').count > 0 )
- @has_result = ( Call.where(:answered => true ).count > 0 )
- @has_analysis = ( Call.where('analysis_completed_at IS NOT NUL…
- end
+ def check
+ @has_project = ( Project.count > 0 )
+ @has_provider = ( Provider.where(:enabled => true).count > 0 )
+ @has_job = ( Job.where(:task => 'dialer').count > 0 )
+ @has_result = ( Call.where(:answered => true ).count > 0 )
+ @has_analysis = ( Call.where('analysis_completed_at IS NOT NULL').count > …
+ end
end
diff --git a/app/controllers/jobs_controller.rb b/app/controllers/jobs_controll…
@@ -1,346 +1,346 @@
class JobsController < ApplicationController
- require 'shellwords'
-
- def index
- @reload_interval = 20000
-
- @submitted_jobs = Job.where(:status => ['submitted', 'schedule…
- @active_jobs = Job.where(:status => 'running', :completed_a…
- @inactive_jobs = Job.order('id DESC').where('status NOT IN (?…
- :page => params[:page],
- :per_page => 30
- )
-
- if @active_jobs.length > 0
- @reload_interval = 5000
- end
-
- if @submitted_jobs.length > 0
- @reload_interval = 3000
- end
-
- respond_to do |format|
- format.html
- end
- end
-
- def results
- @jobs = @project.jobs.order('id DESC').where('(task = ? OR tas…
- :page => params[:page],
- :per_page => 30
- )
-
- respond_to do |format|
- format.html
- end
- end
-
- def view_results
- @job = Job.find(params[:id])
-
- @call_results = {
- :Timeout => @job.calls.count(:conditions => { :answer…
- :Busy => @job.calls.count(:conditions => { :busy …
- :Answered => @job.calls.count(:conditions => { :answer…
- }
-
- sort_by = params[:sort_by] || 'number'
- sort_dir = params[:sort_dir] || 'asc'
-
- @results = []
- @results_total_count = @job.calls.count()
-
- if request.format.json?
- if params[:iDisplayLength] == '-1'
- @results_per_page = nil
- else
- @results_per_page = (params[:iDisplayLength] |…
- end
- @results_offset = (params[:iDisplayStart] || 0).to_i
-
- calls_search
- @results = @job.calls.includes(:provider).where(@searc…
- @results_total_display_count = @job.calls.includes(:pr…
- end
-
- respond_to do |format|
- format.html
- format.json {
- render :content_type => 'application/json', :j…
- }
- end
- end
-
- # Generate a SQL sort by option based on the incoming DataTables param…
- #
- # Returns the SQL String.
- def calls_sort_option
- column = case params[:iSortCol_0].to_s
- when '1'
- 'number'
- when '2'
- 'caller_id'
- when '3'
- 'providers.name'
- when '4'
- 'answered'
- when '5'
- 'busy'
- when '6'
- 'audio_length'
- when '7'
- 'ring_length'
- end
- column + ' ' + (params[:sSortDir_0] =~ /^A/i ? 'asc' : 'desc')…
- end
-
- def calls_search
- @search_conditions = []
- terms = params[:sSearch].to_s
- terms = Shellword.shellwords(terms) rescue terms.split(/\s+/)
- where = ""
- param = []
- glue = ""
- terms.each do |w|
- next if w.downcase == 'undefined'
- where << glue
- case w
- when 'answered'
- where << "answered = ? "
- param << true
- when 'busy'
- where << "busy = ? "
- param << true
- else
- where << "( number ILIKE ? OR caller_i…
- param << "%#{w}%"
- param << "%#{w}%"
- end
- glue = "AND " if glue.empty?
- @search_conditions = [ where, *param ]
- end
- end
-
- def new_dialer
- @job = Job.new
- if @project
- @job.project = @project
- else
- @job.project = Project.last
- end
-
- if params[:result_ids]
- nums = ""
- Call.find_each(:conditions => { :id => params[:result_…
- nums << call.number + "\n"
- end
- @job.range = nums
- end
-
- respond_to do |format|
- format.html
- end
- end
-
- def purge_calls
- Call.delete_all(:id => params[:result_ids])
- CallMedium.delete_all(:call_id => params[:result_ids])
- flash[:notice] = "Purged #{params[:result_ids].length} calls"
- if params[:id]
- @job = Job.find(params[:id])
- redirect_to view_results_path(@job.project_id, @job.id)
- else
- redirect_to analyze_path(@project)
- end
- end
-
- def dialer
- @job = Job.new(params[:job])
- @job.created_by = @current_user.login
- @job.task = 'dialer'
- @job.range.to_s.gsub!(/[^0-9X:,\n]/, '')
- @job.cid_mask.to_s.gsub!(/[^0-9X]/, '') if @job.cid_mask != "S…
-
- if @job.range_file.to_s != ""
- @job.range = @job.range_file.read.gsub(/[^0-9X:,\n]/, …
- end
-
- respond_to do |format|
- if @job.schedule
- flash[:notice] = 'Job was successfully created…
- format.html { redirect_to :action => :index }
- else
- format.html { render :action => "new_dialer" }
- end
- end
- end
-
- def new_analyze
- @job = Job.new
- if @project
- @job.project = @project
- else
- @job.project = Project.last
- end
-
- if params[:result_ids]
- nums = ""
- Call.find_each(:conditions => { :id => params[:result_…
- nums << call.number + "\n"
- end
- @job.range = nums
- end
-
- respond_to do |format|
- format.html
- end
- end
-
- def new_identify
- @job = Job.new
- if @project
- @job.project = @project
- else
- @job.project = Project.last
- end
-
- if params[:result_ids]
- nums = ""
- Call.find_each(:conditions => { :id => params[:result_…
- nums << call.number + "\n"
- end
- @job.range = nums
- end
-
- respond_to do |format|
- format.html
- end
- end
-
- def reanalyze_job
- @job = Job.find(params[:id])
- @new = Job.new({
- :task => 'analysis', :scope => 'job', :target_id => @j…
- :project_id => @project.id, :status => 'submitted'
- })
- @new.created_by = @current_user.login
- respond_to do |format|
- if @new.schedule
- flash[:notice] = 'Analysis job was successfull…
- format.html { redirect_to jobs_path }
- else
- flash[:notice] = 'Analysis job could not run: …
- format.html { redirect_to results_path(@projec…
- end
- end
- end
-
- def analyze_job
- @job = Job.find(params[:id])
-
- # Handle analysis of specific call IDs via checkbox submission
- if params[:result_ids]
- @new = Job.new({
- :task => 'analysis', :scope => 'calls', :targe…
- :project_id => @project.id, :status => 'submit…
- })
- else
- # Otherwise analyze the entire Job
- @new = Job.new({
- :task => 'analysis', :scope => 'job', :target_…
- :project_id => @project.id, :status => 'submit…
- })
- end
-
- @new.created_by = @current_user.login
-
- respond_to do |format|
- if @new.schedule
- flash[:notice] = 'Analysis job was successfull…
- format.html { redirect_to jobs_path }
- else
- flash[:notice] = 'Analysis job could not run: …
- format.html { redirect_to results_path(@projec…
- end
- end
- end
-
-
- def analyze_project
-
- # Handle analysis of specific call IDs via checkbox submission
- if params[:result_ids]
- @new = Job.new({
- :task => 'analysis', :scope => 'calls', :targe…
- :project_id => @project.id, :status => 'submit…
- })
- else
- # Otherwise analyze the entire Project
- @new = Job.new({
- :task => 'analysis', :scope => 'project', :tar…
- :project_id => @project.id, :status => 'submit…
- })
- end
-
- @new.created_by = @current_user.login
-
- respond_to do |format|
- if @new.schedule
- flash[:notice] = 'Analysis job was successfull…
- format.html { redirect_to jobs_path }
- else
- flash[:notice] = 'Analysis job could not run: …
- format.html { redirect_to results_path(@projec…
- end
- end
- end
-
- def identify_job
- @job = Job.find(params[:id])
-
- # Handle identification of specific lines via checkbox submiss…
- if params[:result_ids]
- @new = Job.new({
- :task => 'identify', :scope => 'calls', :targe…
- :project_id => @project.id, :status => 'submit…
- })
- else
- # Otherwise analyze the entire Job
- @new = Job.new({
- :task => 'identify', :scope => 'job', :target_…
- :project_id => @project.id, :status => 'submit…
- })
- end
-
- @new.created_by = @current_user.login
-
- respond_to do |format|
- if @new.schedule
- flash[:notice] = 'Identify job was successfull…
- format.html { redirect_to jobs_path }
- else
- flash[:notice] = 'Identify job could not run: …
- format.html { redirect_to results_path(@projec…
- end
- end
- end
-
- def stop
- @job = Job.find(params[:id])
- @job.stop
- flash[:notice] = "Job has been cancelled"
- redirect_to :action => 'index'
- end
-
- def destroy
- @job = Job.find(params[:id])
- @job.destroy
-
- respond_to do |format|
- format.html { redirect_to(jobs_url) }
- format.xml { head :ok }
- end
- end
+ require 'shellwords'
+
+ def index
+ @reload_interval = 20000
+
+ @submitted_jobs = Job.where(:status => ['submitted', 'scheduled'], :comple…
+ @active_jobs = Job.where(:status => 'running', :completed_at => nil)
+ @inactive_jobs = Job.order('id DESC').where('status NOT IN (?)', ['submit…
+ :page => params[:page],
+ :per_page => 30
+ )
+
+ if @active_jobs.length > 0
+ @reload_interval = 5000
+ end
+
+ if @submitted_jobs.length > 0
+ @reload_interval = 3000
+ end
+
+ respond_to do |format|
+ format.html
+ end
+ end
+
+ def results
+ @jobs = @project.jobs.order('id DESC').where('(task = ? OR task = ?) AND c…
+ :page => params[:page],
+ :per_page => 30
+ )
+
+ respond_to do |format|
+ format.html
+ end
+ end
+
+ def view_results
+ @job = Job.find(params[:id])
+
+ @call_results = {
+ :Timeout => @job.calls.count(:conditions => { :answered => false }),
+ :Busy => @job.calls.count(:conditions => { :busy => true }),
+ :Answered => @job.calls.count(:conditions => { :answered => true }),
+ }
+
+ sort_by = params[:sort_by] || 'number'
+ sort_dir = params[:sort_dir] || 'asc'
+
+ @results = []
+ @results_total_count = @job.calls.count()
+
+ if request.format.json?
+ if params[:iDisplayLength] == '-1'
+ @results_per_page = nil
+ else
+ @results_per_page = (params[:iDisplayLength] || 20).to_i
+ end
+ @results_offset = (params[:iDisplayStart] || 0).to_i
+
+ calls_search
+ @results = @job.calls.includes(:provider).where(@search_conditions).limi…
+ @results_total_display_count = @job.calls.includes(:provider).where(@sea…
+ end
+
+ respond_to do |format|
+ format.html
+ format.json {
+ render :content_type => 'application/json', :json => render_to_string(…
+ }
+ end
+ end
+
+ # Generate a SQL sort by option based on the incoming DataTables paramater.
+ #
+ # Returns the SQL String.
+ def calls_sort_option
+ column = case params[:iSortCol_0].to_s
+ when '1'
+ 'number'
+ when '2'
+ 'caller_id'
+ when '3'
+ 'providers.name'
+ when '4'
+ 'answered'
+ when '5'
+ 'busy'
+ when '6'
+ 'audio_length'
+ when '7'
+ 'ring_length'
+ end
+ column + ' ' + (params[:sSortDir_0] =~ /^A/i ? 'asc' : 'desc') if column
+ end
+
+ def calls_search
+ @search_conditions = []
+ terms = params[:sSearch].to_s
+ terms = Shellword.shellwords(terms) rescue terms.split(/\s+/)
+ where = ""
+ param = []
+ glue = ""
+ terms.each do |w|
+ next if w.downcase == 'undefined'
+ where << glue
+ case w
+ when 'answered'
+ where << "answered = ? "
+ param << true
+ when 'busy'
+ where << "busy = ? "
+ param << true
+ else
+ where << "( number ILIKE ? OR caller_id ILIKE ? ) "
+ param << "%#{w}%"
+ param << "%#{w}%"
+ end
+ glue = "AND " if glue.empty?
+ @search_conditions = [ where, *param ]
+ end
+ end
+
+ def new_dialer
+ @job = Job.new
+ if @project
+ @job.project = @project
+ else
+ @job.project = Project.last
+ end
+
+ if params[:result_ids]
+ nums = ""
+ Call.find_each(:conditions => { :id => params[:result_ids] }) do |call|
+ nums << call.number + "\n"
+ end
+ @job.range = nums
+ end
+
+ respond_to do |format|
+ format.html
+ end
+ end
+
+ def purge_calls
+ Call.delete_all(:id => params[:result_ids])
+ CallMedium.delete_all(:call_id => params[:result_ids])
+ flash[:notice] = "Purged #{params[:result_ids].length} calls"
+ if params[:id]
+ @job = Job.find(params[:id])
+ redirect_to view_results_path(@job.project_id, @job.id)
+ else
+ redirect_to analyze_path(@project)
+ end
+ end
+
+ def dialer
+ @job = Job.new(params[:job])
+ @job.created_by = @current_user.login
+ @job.task = 'dialer'
+ @job.range.to_s.gsub!(/[^0-9X:,\n]/, '')
+ @job.cid_mask.to_s.gsub!(/[^0-9X]/, '') if @job.cid_mask != "SELF"
+
+ if @job.range_file.to_s != ""
+ @job.range = @job.range_file.read.gsub(/[^0-9X:,\n]/, '')
+ end
+
+ respond_to do |format|
+ if @job.schedule
+ flash[:notice] = 'Job was successfully created.'
+ format.html { redirect_to :action => :index }
+ else
+ format.html { render :action => "new_dialer" }
+ end
+ end
+ end
+
+ def new_analyze
+ @job = Job.new
+ if @project
+ @job.project = @project
+ else
+ @job.project = Project.last
+ end
+
+ if params[:result_ids]
+ nums = ""
+ Call.find_each(:conditions => { :id => params[:result_ids] }) do |call|
+ nums << call.number + "\n"
+ end
+ @job.range = nums
+ end
+
+ respond_to do |format|
+ format.html
+ end
+ end
+
+ def new_identify
+ @job = Job.new
+ if @project
+ @job.project = @project
+ else
+ @job.project = Project.last
+ end
+
+ if params[:result_ids]
+ nums = ""
+ Call.find_each(:conditions => { :id => params[:result_ids] }) do |call|
+ nums << call.number + "\n"
+ end
+ @job.range = nums
+ end
+
+ respond_to do |format|
+ format.html
+ end
+ end
+
+ def reanalyze_job
+ @job = Job.find(params[:id])
+ @new = Job.new({
+ :task => 'analysis', :scope => 'job', :target_id => @job.id, :force => t…
+ :project_id => @project.id, :status => 'submitted'
+ })
+ @new.created_by = @current_user.login
+ respond_to do |format|
+ if @new.schedule
+ flash[:notice] = 'Analysis job was successfully created.'
+ format.html { redirect_to jobs_path }
+ else
+ flash[:notice] = 'Analysis job could not run: ' + @new.errors.inspect
+ format.html { redirect_to results_path(@project) }
+ end
+ end
+ end
+
+ def analyze_job
+ @job = Job.find(params[:id])
+
+ # Handle analysis of specific call IDs via checkbox submission
+ if params[:result_ids]
+ @new = Job.new({
+ :task => 'analysis', :scope => 'calls', :target_ids => params[:result_…
+ :project_id => @project.id, :status => 'submitted'
+ })
+ else
+ # Otherwise analyze the entire Job
+ @new = Job.new({
+ :task => 'analysis', :scope => 'job', :target_id => @job.id,
+ :project_id => @project.id, :status => 'submitted'
+ })
+ end
+
+ @new.created_by = @current_user.login
+
+ respond_to do |format|
+ if @new.schedule
+ flash[:notice] = 'Analysis job was successfully created.'
+ format.html { redirect_to jobs_path }
+ else
+ flash[:notice] = 'Analysis job could not run: ' + @new.errors.inspect
+ format.html { redirect_to results_path(@project) }
+ end
+ end
+ end
+
+
+ def analyze_project
+
+ # Handle analysis of specific call IDs via checkbox submission
+ if params[:result_ids]
+ @new = Job.new({
+ :task => 'analysis', :scope => 'calls', :target_ids => params[:result_…
+ :project_id => @project.id, :status => 'submitted'
+ })
+ else
+ # Otherwise analyze the entire Project
+ @new = Job.new({
+ :task => 'analysis', :scope => 'project', :target_id => @project.id,
+ :project_id => @project.id, :status => 'submitted'
+ })
+ end
+
+ @new.created_by = @current_user.login
+
+ respond_to do |format|
+ if @new.schedule
+ flash[:notice] = 'Analysis job was successfully created.'
+ format.html { redirect_to jobs_path }
+ else
+ flash[:notice] = 'Analysis job could not run: ' + @new.errors.inspect
+ format.html { redirect_to results_path(@project) }
+ end
+ end
+ end
+
+ def identify_job
+ @job = Job.find(params[:id])
+
+ # Handle identification of specific lines via checkbox submission
+ if params[:result_ids]
+ @new = Job.new({
+ :task => 'identify', :scope => 'calls', :target_ids => params[:result_…
+ :project_id => @project.id, :status => 'submitted'
+ })
+ else
+ # Otherwise analyze the entire Job
+ @new = Job.new({
+ :task => 'identify', :scope => 'job', :target_id => @job.id,
+ :project_id => @project.id, :status => 'submitted'
+ })
+ end
+
+ @new.created_by = @current_user.login
+
+ respond_to do |format|
+ if @new.schedule
+ flash[:notice] = 'Identify job was successfully created.'
+ format.html { redirect_to jobs_path }
+ else
+ flash[:notice] = 'Identify job could not run: ' + @new.errors.inspect
+ format.html { redirect_to results_path(@project) }
+ end
+ end
+ end
+
+ def stop
+ @job = Job.find(params[:id])
+ @job.stop
+ flash[:notice] = "Job has been cancelled"
+ redirect_to :action => 'index'
+ end
+
+ def destroy
+ @job = Job.find(params[:id])
+ @job.destroy
+
+ respond_to do |format|
+ format.html { redirect_to(jobs_url) }
+ format.xml { head :ok }
+ end
+ end
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_…
@@ -1,136 +1,136 @@
class ProjectsController < ApplicationController
- def index
- @projects = Project.order('id DESC').paginate(
- :page => params[:page],
- :per_page => 10
- )
-
- @new_project = Project.new
-
- respond_to do |format|
- format.html
- format.xml { render :xml => @projects }
- end
- end
-
- def show
- @project = Project.find(params[:id])
- @active_jobs = @project.jobs.where(:status => 'running', :comp…
- @inactive_jobs = @project.jobs.order('id DESC').where('…
- :page => params[:page],
- :per_page => 30
- )
-
- @boxes = {
- :called => { :cnt => @project.calls.count },
- :answered => { :cnt => @project.calls.where(:answered…
- :analyzed => { :cnt => @project.calls.where('analysis…
- :voice => { :cnt => @project.lines.where(:line_typ…
- :voicemail => { :cnt => @project.lines.where(:line_typ…
- :fax => { :cnt => @project.lines.where(:line_typ…
- :modem => { :cnt => @project.lines.where(:line_typ…
- }
-
- if @boxes[:called][:cnt] == 0
- @boxes[:called][:txt] = '0'
- @boxes[:called][:cls] = 'nodata'
-
- # No calls, so everything else is unknown
- [ :answered, :analyzed, :voice, :voicemail, :fax, :mod…
- @boxes[t][:txt] = '?'
- @boxes[t][:cls] = 'nodata'
- end
-
- else
-
- [ :called, :answered, :analyzed].each do |t|
- @boxes[t][:txt] = number_with_delimiter(@boxes…
- @boxes[t][:cls] = 'completed'
- end
-
- if @boxes[:answered][:cnt] == 0
- @boxes[:answered][:txt] = '0'
- @boxes[:answered][:cls] = 'nodata'
- end
-
- if @boxes[:analyzed][:cnt] == 0
- [ :voice, :voicemail, :fax, :modem ].each do |…
- @boxes[t][:txt] = '?'
- @boxes[t][:cls] = 'nodata'
- end
- @boxes[:analyzed][:cls] = 'nodata'
- else
-
- @boxes[:voice][:txt] = number_with_delimiter(@…
- @boxes[:voice][:cls] = 'voice'
-
- @boxes[:voicemail][:txt] = number_with_delimit…
- @boxes[:voicemail][:cls] = 'voicemail'
-
- @boxes[:fax][:txt] = number_with_delimiter(@bo…
- @boxes[:fax][:cls] = 'fax'
-
- @boxes[:modem][:txt] = number_with_delimiter(@…
- @boxes[:modem][:cls] = 'modem'
- end
- end
-
- respond_to do |format|
- format.html
- format.xml { render :xml => @project }
- end
- end
-
- def new
- @new_project = Project.new
- respond_to do |format|
- format.html
- format.xml { render :xml => @new_project }
- end
- end
-
-
- def edit
- @project = Project.find(params[:id])
- end
-
- def create
- @new_project = Project.new(params[:project])
- @new_project.created_by = current_user.login
-
- respond_to do |format|
- if @new_project.save
- format.html { redirect_to(project_path(@new_pr…
- format.xml { render :xml => @project, :…
- else
- format.html { render :action => "new" }
- format.xml { render :xml => @new_projec…
- end
- end
- end
-
- def update
- @project = Project.find(params[:id])
-
- respond_to do |format|
- if @project.update_attributes(params[:project])
- format.html { redirect_to projects_path }
- format.xml { head :ok }
- else
- format.html { render :action => "edit" }
- format.xml { render :xml => @project.er…
- end
- end
- end
-
- def destroy
- @project = Project.find(params[:id])
- @project.destroy
-
- respond_to do |format|
- format.html { redirect_to(projects_url) }
- format.xml { head :ok }
- end
- end
+ def index
+ @projects = Project.order('id DESC').paginate(
+ :page => params[:page],
+ :per_page => 10
+ )
+
+ @new_project = Project.new
+
+ respond_to do |format|
+ format.html
+ format.xml { render :xml => @projects }
+ end
+ end
+
+ def show
+ @project = Project.find(params[:id])
+ @active_jobs = @project.jobs.where(:status => 'running', :completed_at => …
+ @inactive_jobs = @project.jobs.order('id DESC').where('status NOT IN (?)'…
+ :page => params[:page],
+ :per_page => 30
+ )
+
+ @boxes = {
+ :called => { :cnt => @project.calls.count },
+ :answered => { :cnt => @project.calls.where(:answered => true).count },
+ :analyzed => { :cnt => @project.calls.where('analysis_completed_at IS N…
+ :voice => { :cnt => @project.lines.where(:line_type => 'voice').coun…
+ :voicemail => { :cnt => @project.lines.where(:line_type => 'voicemail').…
+ :fax => { :cnt => @project.lines.where(:line_type => 'fax').count …
+ :modem => { :cnt => @project.lines.where(:line_type => 'modem').coun…
+ }
+
+ if @boxes[:called][:cnt] == 0
+ @boxes[:called][:txt] = '0'
+ @boxes[:called][:cls] = 'nodata'
+
+ # No calls, so everything else is unknown
+ [ :answered, :analyzed, :voice, :voicemail, :fax, :modem ].each do |t|
+ @boxes[t][:txt] = '?'
+ @boxes[t][:cls] = 'nodata'
+ end
+
+ else
+
+ [ :called, :answered, :analyzed].each do |t|
+ @boxes[t][:txt] = number_with_delimiter(@boxes[t][:cnt])
+ @boxes[t][:cls] = 'completed'
+ end
+
+ if @boxes[:answered][:cnt] == 0
+ @boxes[:answered][:txt] = '0'
+ @boxes[:answered][:cls] = 'nodata'
+ end
+
+ if @boxes[:analyzed][:cnt] == 0
+ [ :voice, :voicemail, :fax, :modem ].each do |t|
+ @boxes[t][:txt] = '?'
+ @boxes[t][:cls] = 'nodata'
+ end
+ @boxes[:analyzed][:cls] = 'nodata'
+ else
+
+ @boxes[:voice][:txt] = number_with_delimiter(@boxes[:voice][:cnt])
+ @boxes[:voice][:cls] = 'voice'
+
+ @boxes[:voicemail][:txt] = number_with_delimiter(@boxes[:voicemail][:c…
+ @boxes[:voicemail][:cls] = 'voicemail'
+
+ @boxes[:fax][:txt] = number_with_delimiter(@boxes[:fax][:cnt])
+ @boxes[:fax][:cls] = 'fax'
+
+ @boxes[:modem][:txt] = number_with_delimiter(@boxes[:modem][:cnt])
+ @boxes[:modem][:cls] = 'modem'
+ end
+ end
+
+ respond_to do |format|
+ format.html
+ format.xml { render :xml => @project }
+ end
+ end
+
+ def new
+ @new_project = Project.new
+ respond_to do |format|
+ format.html
+ format.xml { render :xml => @new_project }
+ end
+ end
+
+
+ def edit
+ @project = Project.find(params[:id])
+ end
+
+ def create
+ @new_project = Project.new(params[:project])
+ @new_project.created_by = current_user.login
+
+ respond_to do |format|
+ if @new_project.save
+ format.html { redirect_to(project_path(@new_project)) }
+ format.xml { render :xml => @project, :status => :created, :location …
+ else
+ format.html { render :action => "new" }
+ format.xml { render :xml => @new_project.errors, :status => :unproces…
+ end
+ end
+ end
+
+ def update
+ @project = Project.find(params[:id])
+
+ respond_to do |format|
+ if @project.update_attributes(params[:project])
+ format.html { redirect_to projects_path }
+ format.xml { head :ok }
+ else
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @project.errors, :status => :unprocessabl…
+ end
+ end
+ end
+
+ def destroy
+ @project = Project.find(params[:id])
+ @project.destroy
+
+ respond_to do |format|
+ format.html { redirect_to(projects_url) }
+ format.xml { head :ok }
+ end
+ end
end
diff --git a/app/controllers/providers_controller.rb b/app/controllers/provider…
@@ -2,13 +2,13 @@ class ProvidersController < ApplicationController
def index
- @providers = Provider.order('id DESC').paginate(
- :page => params[:page],
- :per_page => 10
- )
+ @providers = Provider.order('id DESC').paginate(
+ :page => params[:page],
+ :per_page => 10
+ )
- @new_provider = Provider.new
- @new_provider.enabled = true
+ @new_provider = Provider.new
+ @new_provider.enabled = true
respond_to do |format|
format.html # index.html.erb
@@ -18,8 +18,8 @@ class ProvidersController < ApplicationController
def new
@provider = Provider.new
- @provider.enabled = true
- @provider.port = 4569
+ @provider.enabled = true
+ @provider.port = 4569
respond_to do |format|
format.html # new.html.erb
@@ -29,12 +29,12 @@ class ProvidersController < ApplicationController
def edit
@provider = Provider.find(params[:id])
- @provider.pass = "********"
+ @provider.pass = "********"
end
def create
@provider = Provider.new(params[:provider])
- @provider.enabled = true
+ @provider.enabled = true
respond_to do |format|
if @provider.save
@@ -52,10 +52,10 @@ class ProvidersController < ApplicationController
def update
@provider = Provider.find(params[:id])
- # Dont set the password if its the placeholder
- if params[:provider] and params[:provider][:pass] and params[:provider…
- params[:provider].delete(:pass)
- end
+ # Dont set the password if its the placeholder
+ if params[:provider] and params[:provider][:pass] and params[:provider][:pas…
+ params[:provider].delete(:pass)
+ end
respond_to do |format|
if @provider.update_attributes(params[:provider])
diff --git a/app/controllers/user_sessions_controller.rb b/app/controllers/user…
@@ -1,23 +1,23 @@
class UserSessionsController < ApplicationController
- before_filter :require_no_user, :only => [:new, :create]
- before_filter :require_user, :only => :destroy
- layout 'login'
+ before_filter :require_no_user, :only => [:new, :create]
+ before_filter :require_user, :only => :destroy
+ layout 'login'
- def new
- @user_session = UserSession.new
- end
+ def new
+ @user_session = UserSession.new
+ end
- def create
- @user_session = UserSession.new(params[:user_session])
- if @user_session.save
- redirect_back_or_default projects_path
- else
- render :action => :new
- end
- end
+ def create
+ @user_session = UserSession.new(params[:user_session])
+ if @user_session.save
+ redirect_back_or_default projects_path
+ else
+ render :action => :new
+ end
+ end
- def destroy
- current_user_session.destroy
- redirect_back_or_default login_url
- end
+ def destroy
+ current_user_session.destroy
+ redirect_back_or_default login_url
+ end
end
diff --git a/app/helpers/analyze_helper.rb b/app/helpers/analyze_helper.rb
@@ -2,21 +2,21 @@ module AnalyzeHelper
def fwd_match_html(pct)
- %Q|<span class="badge fwd_match_span" style='background-color: #{pct_t…
+ %Q|<span class="badge fwd_match_span" style='background-color: #{pct_to_colo…
- #{"%.3f" % pct.to_f}% Match
+ #{"%.3f" % pct.to_f}% Match
- </span>
+ </span>
- |
+ |
end
def rev_match_html(pct)
- %Q|<span class="rev_match_span" style='padding-left: #{ (pct.to_i * 2)…
+ %Q|<span class="rev_match_span" style='padding-left: #{ (pct.to_i * 2).to_i …
end
def pct_to_color(pct)
- "#" + "20" + (pct.to_i * 2.00).to_i.to_s(16).rjust(2, "0") + "20"
+ "#" + "20" + (pct.to_i * 2.00).to_i.to_s(16).rjust(2, "0") + "20"
end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper…
@@ -1,178 +1,178 @@
# Methods added to this helper will be available to all templates in the appli…
module ApplicationHelper
- def select_tag_for_filter(nvpairs, params)
- _url = ( url_for :overwrite_params => { }).split('?')[0]
- _html = %{<span class="pull-left filter-label">Filter: </span> }
- _html << %{<select name="show" class="filter-select" }
- _html << %{onchange="window.location='#{_url}' + '?show=' + this.val…
- nvpairs.each do |pair|
- _html << %{<option value="#{h(pair[:scope])}" }
- if params[:show] == pair[:scope] || ((params[:show].nil? || params…
- _html << %{ selected="selected" }
- end
- _html << %{>#{pair[:label]} }
- _html << %{</option>}
- end
- _html << %{</select>}
- raw(_html)
- end
-
- def select_match_scope(nvpairs, params)
- _url = ( url_for :overwrite_params => { }).split('?')[0]
- _html = %{<span class="pull-left filter-label">Matching Scope: </spa…
- _html << %{<select name="match_scope" class="filter-select" }
- _html << %{onchange="window.location='#{_url}' + '?match_scope=' + t…
- nvpairs.each do |pair|
- _html << %{<option value="#{h(pair[:scope])}" }
- if params[:match_scope] == pair[:scope] || ((params[:match_scope].…
- _html << %{ selected="selected" }
- end
- _html << %{>#{pair[:label]} }
- _html << %{</option>}
- end
- _html << %{</select>}
- raw(_html)
- end
-
- def set_focus(element_id)
- javascript_tag(" $elem = $(\"#{element_id}\"); if (null !== $e…
- end
-
- def format_job_details(job)
- begin
- info = Marshal.load(job.args.to_s)
-
- ttip = raw("<div class='task_args_formatted'>")
- info.each_pair do |k,v|
- ttip << raw("<div class='task_args_var'>") + h…
- ttip << raw("<div class='task_args_val'>") + h…
- end
- ttip << raw("</div>\n")
- outp = raw("<span class='xpopover' rel='popover' data-…
- outp
- rescue ::Exception => e
- job.status.to_s.capitalize
- end
- end
-
- def format_job_status(job)
- case job.status
- when 'error'
- ttip = h(job.error.to_s)
- outp = raw("<span class='xpopover' rel='popover' data-…
- outp
- else
- job.status.to_s.capitalize
- end
- end
-
- def format_job_rate(job)
- pluralize( (job.rate * 60.0).to_i, "call") + "/min"
- end
-
- #
- # Includes any javascripts specific to this view. The hosts/show view
- # will automatically include any javascripts at public/javascripts/hos…
- #
- # @return [void]
- def include_view_javascript
- #
- # Sprockets treats index.js as special, so the js for the inde…
- # http://guides.rubyonrails.org/asset_pipeline.html#using-inde…
- #
-
- controller_action_name = controller.action_name
-
- if controller_action_name == 'index'
- safe_action_name = '_index'
- else
- safe_action_name = controller_action_name
- end
-
- include_view_javascript_named(safe_action_name)
- end
-
- # Includes the named javascript for this controller if it exists.
- #
- # @return [void]
- def include_view_javascript_named(name)
-
- controller_path = controller.controller_path
- extensions = ['.coffee', '.js.coffee']
- javascript_controller_pathname = Rails.root.join('app', 'asset…
- pathnames = extensions.collect { |extension|
- javascript_controller_pathname.join("#{name}#{extensio…
- }
-
- if pathnames.any?(&:exist?)
- path = File.join(controller_path, name)
- content_for(:view_javascript) do
- javascript_include_tag path
- end
- end
- end
-
- def escape_javascript_dq(str)
- escape_javascript(str.strip).gsub("\\'", "'").gsub("\t", " …
- end
-
- def submit_checkboxes_to(name, path, html={})
- if html[:confirm]
- confirm = html.delete(:confirm)
- link_to(name, "#", html.merge({:onclick => "if(confirm…
- else
- link_to(name, "#", html.merge({:onclick => "submit_che…
- end
- end
-
- # Scrub out data that can break the JSON parser
- #
- # data - The String json to be scrubbed.
- #
- # Returns the String json with invalid data removed.
- def json_data_scrub(data)
- data.to_s.gsub(/[\x00-\x1f]/){ |x| "\\x%.2x" % x.unpack("C*")[…
- end
-
- # Returns the properly escaped sEcho parameter that DataTables expects.
- def echo_data_tables
- h(params[:sEcho]).to_json.html_safe
- end
-
- # Generate the markup for the call's row checkbox.
- # Returns the String markup html, escaped for json.
- def call_checkbox_tag(call)
- check_box_tag("result_ids[]", call.id, false, :id => nil).to_j…
- end
-
- def call_number_html(call)
- json_data_scrub(h(call.number)).to_json.html_safe
- end
-
- def call_caller_id_html(call)
- json_data_scrub(h(call.caller_id)).to_json.html_safe
- end
-
- def call_provider_html(call)
- json_data_scrub(h(call.provider.name)).to_json.html_safe
- end
-
- def call_answered_html(call)
- json_data_scrub(h(call.answered ? "Yes" : "No")).to_json.html_…
- end
-
- def call_busy_html(call)
- json_data_scrub(h(call.busy ? "Yes" : "No")).to_json.html_safe
- end
-
- def call_audio_length_html(call)
- json_data_scrub(h(call.audio_length.to_s)).to_json.html_safe
- end
-
- def call_ring_length_html(call)
- json_data_scrub(h(call.ring_length.to_s)).to_json.html_safe
- end
+ def select_tag_for_filter(nvpairs, params)
+ _url = ( url_for :overwrite_params => { }).split('?')[0]
+ _html = %{<span class="pull-left filter-label">Filter: </span> }
+ _html << %{<select name="show" class="filter-select" }
+ _html << %{onchange="window.location='#{_url}' + '?show=' + this.value"> }
+ nvpairs.each do |pair|
+ _html << %{<option value="#{h(pair[:scope])}" }
+ if params[:show] == pair[:scope] || ((params[:show].nil? || params[:show…
+ _html << %{ selected="selected" }
+ end
+ _html << %{>#{pair[:label]} }
+ _html << %{</option>}
+ end
+ _html << %{</select>}
+ raw(_html)
+ end
+
+ def select_match_scope(nvpairs, params)
+ _url = ( url_for :overwrite_params => { }).split('?')[0]
+ _html = %{<span class="pull-left filter-label">Matching Scope: </span> }
+ _html << %{<select name="match_scope" class="filter-select" }
+ _html << %{onchange="window.location='#{_url}' + '?match_scope=' + this.va…
+ nvpairs.each do |pair|
+ _html << %{<option value="#{h(pair[:scope])}" }
+ if params[:match_scope] == pair[:scope] || ((params[:match_scope].nil? |…
+ _html << %{ selected="selected" }
+ end
+ _html << %{>#{pair[:label]} }
+ _html << %{</option>}
+ end
+ _html << %{</select>}
+ raw(_html)
+ end
+
+ def set_focus(element_id)
+ javascript_tag(" $elem = $(\"#{element_id}\"); if (null !== $elem && $elem…
+ end
+
+ def format_job_details(job)
+ begin
+ info = Marshal.load(job.args.to_s)
+
+ ttip = raw("<div class='task_args_formatted'>")
+ info.each_pair do |k,v|
+ ttip << raw("<div class='task_args_var'>") + h(truncate(k.to_s, :lengt…
+ ttip << raw("<div class='task_args_val'>") + h(truncate((v.to_s), :len…
+ end
+ ttip << raw("</div>\n")
+ outp = raw("<span class='xpopover' rel='popover' data-title=\"#{job.task…
+ outp
+ rescue ::Exception => e
+ job.status.to_s.capitalize
+ end
+ end
+
+ def format_job_status(job)
+ case job.status
+ when 'error'
+ ttip = h(job.error.to_s)
+ outp = raw("<span class='xpopover' rel='popover' data-title=\"Task Detai…
+ outp
+ else
+ job.status.to_s.capitalize
+ end
+ end
+
+ def format_job_rate(job)
+ pluralize( (job.rate * 60.0).to_i, "call") + "/min"
+ end
+
+ #
+ # Includes any javascripts specific to this view. The hosts/show view
+ # will automatically include any javascripts at public/javascripts/hosts/sho…
+ #
+ # @return [void]
+ def include_view_javascript
+ #
+ # Sprockets treats index.js as special, so the js for the index action mus…
+ # http://guides.rubyonrails.org/asset_pipeline.html#using-index-files
+ #
+
+ controller_action_name = controller.action_name
+
+ if controller_action_name == 'index'
+ safe_action_name = '_index'
+ else
+ safe_action_name = controller_action_name
+ end
+
+ include_view_javascript_named(safe_action_name)
+ end
+
+ # Includes the named javascript for this controller if it exists.
+ #
+ # @return [void]
+ def include_view_javascript_named(name)
+
+ controller_path = controller.controller_path
+ extensions = ['.coffee', '.js.coffee']
+ javascript_controller_pathname = Rails.root.join('app', 'assets', 'javascr…
+ pathnames = extensions.collect { |extension|
+ javascript_controller_pathname.join("#{name}#{extension}")
+ }
+
+ if pathnames.any?(&:exist?)
+ path = File.join(controller_path, name)
+ content_for(:view_javascript) do
+ javascript_include_tag path
+ end
+ end
+ end
+
+ def escape_javascript_dq(str)
+ escape_javascript(str.strip).gsub("\\'", "'").gsub("\t", " ")
+ end
+
+ def submit_checkboxes_to(name, path, html={})
+ if html[:confirm]
+ confirm = html.delete(:confirm)
+ link_to(name, "#", html.merge({:onclick => "if(confirm('#{h confirm}')){…
+ else
+ link_to(name, "#", html.merge({:onclick => "submit_checkboxes_to('#{path…
+ end
+ end
+
+ # Scrub out data that can break the JSON parser
+ #
+ # data - The String json to be scrubbed.
+ #
+ # Returns the String json with invalid data removed.
+ def json_data_scrub(data)
+ data.to_s.gsub(/[\x00-\x1f]/){ |x| "\\x%.2x" % x.unpack("C*")[0] }
+ end
+
+ # Returns the properly escaped sEcho parameter that DataTables expects.
+ def echo_data_tables
+ h(params[:sEcho]).to_json.html_safe
+ end
+
+ # Generate the markup for the call's row checkbox.
+ # Returns the String markup html, escaped for json.
+ def call_checkbox_tag(call)
+ check_box_tag("result_ids[]", call.id, false, :id => nil).to_json.html_safe
+ end
+
+ def call_number_html(call)
+ json_data_scrub(h(call.number)).to_json.html_safe
+ end
+
+ def call_caller_id_html(call)
+ json_data_scrub(h(call.caller_id)).to_json.html_safe
+ end
+
+ def call_provider_html(call)
+ json_data_scrub(h(call.provider.name)).to_json.html_safe
+ end
+
+ def call_answered_html(call)
+ json_data_scrub(h(call.answered ? "Yes" : "No")).to_json.html_safe
+ end
+
+ def call_busy_html(call)
+ json_data_scrub(h(call.busy ? "Yes" : "No")).to_json.html_safe
+ end
+
+ def call_audio_length_html(call)
+ json_data_scrub(h(call.audio_length.to_s)).to_json.html_safe
+ end
+
+ def call_ring_length_html(call)
+ json_data_scrub(h(call.ring_length.to_s)).to_json.html_safe
+ end
end
diff --git a/app/models/call_medium.rb b/app/models/call_medium.rb
@@ -15,6 +15,6 @@
#
class CallMedium < ActiveRecord::Base
- belongs_to :call
- belongs_to :project
+ belongs_to :call
+ belongs_to :project
end
diff --git a/app/models/job.rb b/app/models/job.rb
@@ -20,152 +20,152 @@
class Job < ActiveRecord::Base
- reportable :hourly, :aggregation => :count, :grouping => :hour, :date_…
- reportable :daily, :aggregation => :count, :grouping => :day, :date_co…
- reportable :weeky, :aggregation => :count, :grouping => :week, :date_c…
- reportable :monthly, :aggregation => :count, :grouping => :month, :dat…
-
- class JobValidator < ActiveModel::Validator
- def validate(record)
- case record.task
- when 'dialer'
-
- cracked_range = WarVOX::Phone.crack_mask(recor…
- unless cracked_range.length > 0
- record.errors[:range] << "No valid ran…
- end
-
- cracked_mask = WarVOX::Phone.crack_mask(record…
- unless cracked_mask.length > 0
- record.errors[:cid_mask] << "No valid …
- end
-
- unless record.seconds.to_i > 0 and record.seco…
- record.errors[:seconds] << "Seconds sh…
- end
-
- unless record.lines.to_i > 0 and record.lines.…
- record.errors[:lines] << "Lines should…
- end
-
- $stderr.puts "Errors: #{record.errors.map{|x| …
-
- when 'analysis'
- unless ['calls', 'job', 'project', 'global'].i…
- record.errors[:scope] << "Scope must b…
- end
- if record.scope == "job" and Job.where(:id => …
- record.errors[:job_id] << "The job_id …
- end
- if record.scope == "project" and Project.where…
- record.errors[:project_id] << "The pro…
- end
- if record.scope == "calls" and (record.target_…
- record.errors[:target_ids] << "The tar…
- end
- when 'import'
- else
- record.errors[:base] << "Invalid task specifie…
- end
- end
- end
-
- # XXX: Purging a single job will be slow, but deleting the project is …
- has_many :calls, :dependent => :destroy
-
- belongs_to :project
-
- attr_accessible :task, :status, :progress
-
- validates_presence_of :project_id
-
- attr_accessible :project_id
-
-
- # Allow the base Job class to be used for Dial Jobs
- attr_accessor :range
- attr_accessor :range_file
- attr_accessor :lines
- attr_accessor :seconds
- attr_accessor :cid_mask
-
- attr_accessible :range, :seconds, :lines, :cid_mask, :range_file
-
- attr_accessor :scope
- attr_accessor :force
- attr_accessor :target_id
- attr_accessor :target_ids
-
- attr_accessible :scope, :force, :target_id, :target_ids
-
-
- validates_with JobValidator
-
- def stop
- self.class.where(id: self.id).update_all(status: 'cancelled')
- end
-
- def update_progress(pct)
- if pct >= 100
- self.class.where(id: self.id).update_all(:progress => …
- else
- self.class.where(id: self.id).update_all(:progress => …
- end
- end
-
- def details
- Marshal.load(self.args) rescue {}
- end
-
- def schedule
- case task
- when 'dialer'
- self.status = 'submitted'
- self.args = Marshal.dump({
- :range => self.range,
- :lines => self.lines.to_i,
- :seconds => self.seconds.to_i,
- :cid_mask => self.cid_mask
- })
-
- return self.save
-
- when 'analysis'
- self.status = 'submitted'
- d = {
+ reportable :hourly, :aggregation => :count, :grouping => :hour, :date_column…
+ reportable :daily, :aggregation => :count, :grouping => :day, :date_column =…
+ reportable :weeky, :aggregation => :count, :grouping => :week, :date_column …
+ reportable :monthly, :aggregation => :count, :grouping => :month, :date_colu…
+
+ class JobValidator < ActiveModel::Validator
+ def validate(record)
+ case record.task
+ when 'dialer'
+
+ cracked_range = WarVOX::Phone.crack_mask(record.range) rescue []
+ unless cracked_range.length > 0
+ record.errors[:range] << "No valid ranges were specified"
+ end
+
+ cracked_mask = WarVOX::Phone.crack_mask(record.cid_mask) rescue []
+ unless cracked_mask.length > 0
+ record.errors[:cid_mask] << "No valid Caller ID mask was specified"
+ end
+
+ unless record.seconds.to_i > 0 and record.seconds.to_i < 300
+ record.errors[:seconds] << "Seconds should be between 1 and 300"
+ end
+
+ unless record.lines.to_i > 0 and record.lines.to_i < 10000
+ record.errors[:lines] << "Lines should be between 1 and 10,000"
+ end
+
+ $stderr.puts "Errors: #{record.errors.map{|x| x.inspect}}"
+
+ when 'analysis'
+ unless ['calls', 'job', 'project', 'global'].include?(record.scope)
+ record.errors[:scope] << "Scope must be calls, job, project, or glob…
+ end
+ if record.scope == "job" and Job.where(:id => record.target_id.to_i, :…
+ record.errors[:job_id] << "The job_id is not valid"
+ end
+ if record.scope == "project" and Project.where(:id => record.target_id…
+ record.errors[:project_id] << "The project_id is not valid"
+ end
+ if record.scope == "calls" and (record.target_ids.nil? or record.targe…
+ record.errors[:target_ids] << "The target_ids list is empty"
+ end
+ when 'import'
+ else
+ record.errors[:base] << "Invalid task specified"
+ end
+ end
+ end
+
+ # XXX: Purging a single job will be slow, but deleting the project is fast
+ has_many :calls, :dependent => :destroy
+
+ belongs_to :project
+
+ attr_accessible :task, :status, :progress
+
+ validates_presence_of :project_id
+
+ attr_accessible :project_id
+
+
+ # Allow the base Job class to be used for Dial Jobs
+ attr_accessor :range
+ attr_accessor :range_file
+ attr_accessor :lines
+ attr_accessor :seconds
+ attr_accessor :cid_mask
+
+ attr_accessible :range, :seconds, :lines, :cid_mask, :range_file
+
+ attr_accessor :scope
+ attr_accessor :force
+ attr_accessor :target_id
+ attr_accessor :target_ids
+
+ attr_accessible :scope, :force, :target_id, :target_ids
+
+
+ validates_with JobValidator
+
+ def stop
+ self.class.where(id: self.id).update_all(status: 'cancelled')
+ end
+
+ def update_progress(pct)
+ if pct >= 100
+ self.class.where(id: self.id).update_all(:progress => pct, :completed_at…
+ else
+ self.class.where(id: self.id).update_all(:progress => pct)
+ end
+ end
+
+ def details
+ Marshal.load(self.args) rescue {}
+ end
+
+ def schedule
+ case task
+ when 'dialer'
+ self.status = 'submitted'
+ self.args = Marshal.dump({
+ :range => self.range,
+ :lines => self.lines.to_i,
+ :seconds => self.seconds.to_i,
+ :cid_mask => self.cid_mask
+ })
+
+ return self.save
+
+ when 'analysis'
+ self.status = 'submitted'
+ d = {
:scope => self.scope, # job / pr…
:force => !!(self.force), # true / f…
:target_id => self.target_id.to_i, # job_id o…
:target_ids => (self.target_ids || []).map{|x|…
}
- $stderr.puts d.inspect
-
- self.args = Marshal.dump({
- :scope => self.scope, # job / pr…
- :force => !!(self.force), # true / f…
- :target_id => self.target_id.to_i, # job_id o…
- :target_ids => (self.target_ids || []).map{|x|…
- })
- return self.save
- else
- raise ::RuntimeError, "Unsupported Job type"
- end
- end
-
- def rate
- tend = (self.completed_at || Time.now)
- tlen = tend.to_f - self.started_at.to_f
-
- case self.task
- when 'dialer'
- Call.where('job_id = ?', self.id).count() / tlen
- when 'analysis'
- Call.where('job_id = ? AND analysis_completed_at > ? A…
- when 'import'
- Call.where('job_id = ?', self.id).count() / tlen
- else
- 0
- end
- end
+ $stderr.puts d.inspect
+
+ self.args = Marshal.dump({
+ :scope => self.scope, # job / project/ global
+ :force => !!(self.force), # true / false
+ :target_id => self.target_id.to_i, # job_id or project_id or nil
+ :target_ids => (self.target_ids || []).map{|x| x.to_i }
+ })
+ return self.save
+ else
+ raise ::RuntimeError, "Unsupported Job type"
+ end
+ end
+
+ def rate
+ tend = (self.completed_at || Time.now)
+ tlen = tend.to_f - self.started_at.to_f
+
+ case self.task
+ when 'dialer'
+ Call.where('job_id = ?', self.id).count() / tlen
+ when 'analysis'
+ Call.where('job_id = ? AND analysis_completed_at > ? AND analysis_comple…
+ when 'import'
+ Call.where('job_id = ?', self.id).count() / tlen
+ else
+ 0
+ end
+ end
end
diff --git a/app/models/line.rb b/app/models/line.rb
@@ -12,18 +12,18 @@
#
class Line < ActiveRecord::Base
- has_many :line_attributes, :dependent => :delete_all
- belongs_to :project
+ has_many :line_attributes, :dependent => :delete_all
+ belongs_to :project
- def set_attribute(name, value, ctype='text/plain')
- la = LineAttribute.where(line_id: self.id, project_id: self.pr…
- la.value = value
- la.ctype = ctype
- la.save
- la
- end
+ def set_attribute(name, value, ctype='text/plain')
+ la = LineAttribute.where(line_id: self.id, project_id: self.project_id, na…
+ la.value = value
+ la.ctype = ctype
+ la.save
+ la
+ end
- def get_attribute(name)
- LineAttribute.where(:line_id => self[:id], :name => name).first
- end
+ def get_attribute(name)
+ LineAttribute.where(:line_id => self[:id], :name => name).first
+ end
end
diff --git a/app/models/line_attribute.rb b/app/models/line_attribute.rb
@@ -13,6 +13,6 @@
#
class LineAttribute < ActiveRecord::Base
- belongs_to :line
- belongs_to :project
+ belongs_to :line
+ belongs_to :project
end
diff --git a/app/models/project.rb b/app/models/project.rb
@@ -14,15 +14,15 @@
class Project < ActiveRecord::Base
- validates_presence_of :name
- validates_uniqueness_of :name
+ validates_presence_of :name
+ validates_uniqueness_of :name
- attr_accessible :name, :description, :included, :excluded
+ attr_accessible :name, :description, :included, :excluded
- # This is optimized for fast project deletion, even with thousands of …
- has_many :lines, :dependent => :delete_all
- has_many :line_attributes, :dependent => :delete_all
- has_many :calls, :dependent => :delete_all
- has_many :call_media, :dependent => :delete_all
- has_many :jobs, :dependent => :delete_all
+ # This is optimized for fast project deletion, even with thousands of calls/…
+ has_many :lines, :dependent => :delete_all
+ has_many :line_attributes, :dependent => :delete_all
+ has_many :calls, :dependent => :delete_all
+ has_many :call_media, :dependent => :delete_all
+ has_many :jobs, :dependent => :delete_all
end
diff --git a/app/models/provider.rb b/app/models/provider.rb
@@ -15,11 +15,11 @@
#
class Provider < ActiveRecord::Base
- has_many :dial_results
+ has_many :dial_results
- validates_presence_of :name, :host, :port, :user, :pass, :lines
- validates_numericality_of :port, :less_than => 65536, :greater_than =>…
- validates_numericality_of :lines, :less_than => 255, :greater_than => 0
+ validates_presence_of :name, :host, :port, :user, :pass, :lines
+ validates_numericality_of :port, :less_than => 65536, :greater_than => 0
+ validates_numericality_of :lines, :less_than => 255, :greater_than => 0
- attr_accessible :enabled, :name, :host, :port, :user, :pass, :lines
+ attr_accessible :enabled, :name, :host, :port, :user, :pass, :lines
end
diff --git a/app/models/settings.rb b/app/models/settings.rb
@@ -12,5 +12,5 @@
#
class Settings < RailsSettings::CachedSettings
- attr_accessible :var
+ attr_accessible :var
end
diff --git a/app/models/signature.rb b/app/models/signature.rb
@@ -14,6 +14,6 @@
#
class Signature < ActiveRecord::Base
- has_many :signature_fps
+ has_many :signature_fps
end
diff --git a/app/models/signature_fp.rb b/app/models/signature_fp.rb
@@ -1,4 +1,4 @@
class SignatureFp < ActiveRecord::Base
- belongs_to :signature
+ belongs_to :signature
end
diff --git a/app/models/user.rb b/app/models/user.rb
@@ -24,11 +24,11 @@
#
class User < ActiveRecord::Base
- include RailsSettings::Extend
- acts_as_authentic do |c|
- c.validate_email_field = false
- c.merge_validates_length_of_password_field_options :minimum =>…
- c.merge_validates_length_of_password_confirmation_field_option…
- c.logged_in_timeout = 1.day
- end
+ include RailsSettings::Extend
+ acts_as_authentic do |c|
+ c.validate_email_field = false
+ c.merge_validates_length_of_password_field_options :minimum => 8
+ c.merge_validates_length_of_password_confirmation_field_options :minimum =…
+ c.logged_in_timeout = 1.day
+ end
end
diff --git a/app/models/user_session.rb b/app/models/user_session.rb
@@ -1,3 +1,3 @@
class UserSession < Authlogic::Session::Base
- logout_on_timeout true
+ logout_on_timeout true
end
diff --git a/bin/adduser b/bin/adduser
@@ -17,19 +17,19 @@ require APP_PATH
Rails.application.require_environment!
def generate_password
- set = ( [*(0x21 .. 0x2f)] + [*(0x3a .. 0x3F)] + [*(0x5b .. 0x60)] + [*…
- set << "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
- str = ''
- cnt = 0
- while not (str.length >= 8 and str =~ /[A-Za-z]/ and str =~ /[0-9]/ an…
- if str.length > 12
- str = str[0,4]
- next
- end
- str << set[ rand(set.length), 1]
- cnt += 1
- end
- str
+ set = ( [*(0x21 .. 0x2f)] + [*(0x3a .. 0x3F)] + [*(0x5b .. 0x60)] + [*(0x7b …
+ set << "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+ str = ''
+ cnt = 0
+ while not (str.length >= 8 and str =~ /[A-Za-z]/ and str =~ /[0-9]/ and str …
+ if str.length > 12
+ str = str[0,4]
+ next
+ end
+ str << set[ rand(set.length), 1]
+ cnt += 1
+ end
+ str
end
@@ -40,32 +40,32 @@ user = username ? User.find_by_login(username) : nil
if not user
- if ! username
- $stdout.write "[*] Please enter a username: "
- $stdout.flush
- username = $stdin.readline.strip
- end
+ if ! username
+ $stdout.write "[*] Please enter a username: "
+ $stdout.flush
+ username = $stdin.readline.strip
+ end
- if ! (username and username.strip.length > 0)
- $stdout.puts "[-] Invalid username specified"
- exit(0)
- end
+ if ! (username and username.strip.length > 0)
+ $stdout.puts "[-] Invalid username specified"
+ exit(0)
+ end
- if not password
- randpass = generate_password
- $stdout.puts ""
- $stdout.puts "[*] Creating user '#{username}' with password '#…
- $stdout.puts ""
- password = randpass
- end
+ if not password
+ randpass = generate_password
+ $stdout.puts ""
+ $stdout.puts "[*] Creating user '#{username}' with password '#{randpass}' …
+ $stdout.puts ""
+ password = randpass
+ end
- user = User.new()
- user.login = username
- user.password = password
- user.password_confirmation = password
- user.save!
+ user = User.new()
+ user.login = username
+ user.password = password
+ user.password_confirmation = password
+ user.save!
- $stdout.puts "[*] User #{user.login} has been created, please change y…
+ $stdout.puts "[*] User #{user.login} has been created, please change your pa…
else
- $stdout.puts "[*] That user account already exists, please try 'resetp…
+ $stdout.puts "[*] That user account already exists, please try 'resetpw' scr…
end
diff --git a/bin/analyze_result.rb b/bin/analyze_result.rb
@@ -6,7 +6,7 @@
#
base = __FILE__
while File.symlink?(base)
- base = File.expand_path(File.readlink(base), File.dirname(base))
+ base = File.expand_path(File.readlink(base), File.dirname(base))
end
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..', 'lib'))
require 'warvox'
@@ -23,13 +23,13 @@ $0 = "warvox(analyzer): #{inp} #{num}"
begin
$stdout.write(
- Marshal.dump(
- WarVOX::Jobs::Analysis.analyze_call(
- inp, num
- )
- )
+ Marshal.dump(
+ WarVOX::Jobs::Analysis.analyze_call(
+ inp, num
+ )
+ )
)
rescue ::Errno::EPIPE
- # Hide pipe errors (parent is killed when task was cancelled)
+ # Hide pipe errors (parent is killed when task was cancelled)
end
diff --git a/bin/audio_raw_to_fprint.rb b/bin/audio_raw_to_fprint.rb
@@ -6,15 +6,15 @@
#
base = __FILE__
while File.symlink?(base)
- base = File.expand_path(File.readlink(base), File.dirname(base))
+ base = File.expand_path(File.readlink(base), File.dirname(base))
end
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..', 'lib'))
require 'warvox'
def usage
- $stderr.puts "Usage: #{$0} <input.raw> <output.txt>"
- exit
+ $stderr.puts "Usage: #{$0} <input.raw> <output.txt>"
+ exit
end
#
@@ -25,14 +25,14 @@ inp = ARGV.shift
out = ARGV.shift
if (inp and inp == "-h") or not inp
- usage()
+ usage()
end
raw = WarVOX::Audio::Raw.from_file(inp)
if out
- ::File.open(out, "wb") do |fd|
- fd.write( "{" + raw.to_freq_sig.map{|x| x.to_s}.join(",") + "}…
- end
+ ::File.open(out, "wb") do |fd|
+ fd.write( "{" + raw.to_freq_sig.map{|x| x.to_s}.join(",") + "}" )
+ end
else
- $stdout.write( "{" + raw.to_freq_sig.map{|x| x.to_s}.join(",") + "}" )
+ $stdout.write( "{" + raw.to_freq_sig.map{|x| x.to_s}.join(",") + "}" )
end
diff --git a/bin/audio_raw_to_wav.rb b/bin/audio_raw_to_wav.rb
@@ -6,15 +6,15 @@
#
base = __FILE__
while File.symlink?(base)
- base = File.expand_path(File.readlink(base), File.dirname(base))
+ base = File.expand_path(File.readlink(base), File.dirname(base))
end
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..', 'lib'))
require 'warvox'
def usage
- $stderr.puts "Usage: #{$0} <input.raw> <output.wav>"
- exit
+ $stderr.puts "Usage: #{$0} <input.raw> <output.wav>"
+ exit
end
#
@@ -25,14 +25,14 @@ inp = ARGV.shift
out = ARGV.shift
if (inp and inp == "-h") or not inp
- usage()
+ usage()
end
raw = WarVOX::Audio::Raw.from_file(inp)
if out
- ::File.open(out, "wb") do |fd|
- fd.write(raw.to_wav)
- end
+ ::File.open(out, "wb") do |fd|
+ fd.write(raw.to_wav)
+ end
else
- $stdout.write(raw.to_wav)
+ $stdout.write(raw.to_wav)
end
diff --git a/bin/audio_trim.rb b/bin/audio_trim.rb
@@ -6,15 +6,15 @@
#
base = __FILE__
while File.symlink?(base)
- base = File.expand_path(File.readlink(base), File.dirname(base))
+ base = File.expand_path(File.readlink(base), File.dirname(base))
end
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..', 'lib'))
require 'warvox'
def usage
- $stderr.puts "Usage: #{$0} [offset] [length] <input.raw> <output.raw>"
- exit
+ $stderr.puts "Usage: #{$0} [offset] [length] <input.raw> <output.raw>"
+ exit
end
#
@@ -27,26 +27,26 @@ inp = ARGV.shift
out = ARGV.shift
if (off and off == "-h") or not off
- usage()
+ usage()
end
buf = ''
ifd = nil
if inp
- ifd = ::File.open(inp, "rb")
+ ifd = ::File.open(inp, "rb")
else
- $stdin.binmode
- ifd = $stdin
+ $stdin.binmode
+ ifd = $stdin
end
ofd = nil
if out
- ofd = ::File.open(out, "wb")
+ ofd = ::File.open(out, "wb")
else
- $stdout.binmode
- ofd = $stdout
+ $stdout.binmode
+ ofd = $stdout
end
diff --git a/bin/cache_clear.rb b/bin/cache_clear.rb
@@ -6,7 +6,7 @@
#
base = __FILE__
while File.symlink?(base)
- base = File.expand_path(File.readlink(base), File.dirname(base))
+ base = File.expand_path(File.readlink(base), File.dirname(base))
end
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..', 'lib'))
diff --git a/bin/export_audio.rb b/bin/export_audio.rb
@@ -6,7 +6,7 @@
#
base = __FILE__
while File.symlink?(base)
- base = File.expand_path(File.readlink(base), File.dirname(base))
+ base = File.expand_path(File.readlink(base), File.dirname(base))
end
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..', 'lib'))
@@ -18,8 +18,8 @@ ENV['RAILS_ENV'] ||= 'production'
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..'))
def usage
- $stderr.puts "Usage: #{$0} [Output Dir] [Project ID] <Line Type>"
- exit
+ $stderr.puts "Usage: #{$0} [Output Dir] [Project ID] <Line Type>"
+ exit
end
#
@@ -31,61 +31,61 @@ project_id = ARGV.shift
line_type = ARGV.shift
if(output and output == "-h") or (! output)
- usage()
+ usage()
end
require 'config/boot'
require 'config/environment'
if project_id.to_i == 0
- $stderr.puts "Listing all projects"
- $stderr.puts "===================="
- Project.all.each do |j|
- puts "#{j.id}\t#{j.name}\t#{j.created_at}"
- end
- exit
+ $stderr.puts "Listing all projects"
+ $stderr.puts "===================="
+ Project.all.each do |j|
+ puts "#{j.id}\t#{j.name}\t#{j.created_at}"
+ end
+ exit
end
FileUtils.mkdir_p(output)
begin
- cond = { :project_id => project_id.to_i, :answered => true, :busy => f…
- if line_type
- cond[:line_type] = line_type.downcase
- end
-
- Call.where(cond).order(number: :asc).each do |r|
- m = r.media
- if m and m.audio
-
- ::File.open(File.join(output, "#{r.number}.raw"), "wb"…
- fd.write(m.audio)
- end
-
- ::File.open(File.join(output, "#{r.number}.yml"), "wb"…
- fd.write(r.to_yaml)
- end
-
- if m.mp3
- ::File.open(File.join(output, "#{r.number}.mp3…
- fd.write(m.mp3)
- end
- end
-
- if m.png_big
- ::File.open(File.join(output, "#{r.number}_wav…
- fd.write(m.png_big)
- end
- end
-
- if m.png_big_freq
- ::File.open(File.join(output, "#{r.number}_fre…
- fd.write(m.png_big_freq)
- end
- end
-
- $stderr.puts "[*] Exported #{r.number}..."
-
- end
- end
+ cond = { :project_id => project_id.to_i, :answered => true, :busy => false }
+ if line_type
+ cond[:line_type] = line_type.downcase
+ end
+
+ Call.where(cond).order(number: :asc).each do |r|
+ m = r.media
+ if m and m.audio
+
+ ::File.open(File.join(output, "#{r.number}.raw"), "wb") do |fd|
+ fd.write(m.audio)
+ end
+
+ ::File.open(File.join(output, "#{r.number}.yml"), "wb") do |fd|
+ fd.write(r.to_yaml)
+ end
+
+ if m.mp3
+ ::File.open(File.join(output, "#{r.number}.mp3"), "wb") do |fd|
+ fd.write(m.mp3)
+ end
+ end
+
+ if m.png_big
+ ::File.open(File.join(output, "#{r.number}_wave.png"), "wb") do |fd|
+ fd.write(m.png_big)
+ end
+ end
+
+ if m.png_big_freq
+ ::File.open(File.join(output, "#{r.number}_freq.png"), "wb") do |fd|
+ fd.write(m.png_big_freq)
+ end
+ end
+
+ $stderr.puts "[*] Exported #{r.number}..."
+
+ end
+ end
end
diff --git a/bin/export_list.rb b/bin/export_list.rb
@@ -6,7 +6,7 @@
#
base = __FILE__
while File.symlink?(base)
- base = File.expand_path(File.readlink(base), File.dirname(base))
+ base = File.expand_path(File.readlink(base), File.dirname(base))
end
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..', 'lib'))
@@ -17,8 +17,8 @@ ENV['RAILS_ENV'] ||= 'production'
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..'))
def usage
- $stderr.puts "Usage: #{$0} [Job ID] <Type>"
- exit
+ $stderr.puts "Usage: #{$0} [Job ID] <Type>"
+ exit
end
#
@@ -29,37 +29,37 @@ project_id = ARGV.shift
line_type = ARGV.shift
if(project_id and project_id == "-h")
- usage()
+ usage()
end
if project_id.to_i == 0
- usage()
+ usage()
end
require 'config/boot'
require 'config/environment'
if(not project_id)
- $stderr.puts "Listing all projects"
- $stderr.puts "===================="
- Project.all.each do |j|
- puts "#{j.id}\t#{j.name}\t#{j.created_at}"
- end
- exit
+ $stderr.puts "Listing all projects"
+ $stderr.puts "===================="
+ Project.all.each do |j|
+ puts "#{j.id}\t#{j.name}\t#{j.created_at}"
+ end
+ exit
end
fields = %W{ number line_type caller_id answered busy audio_length ring_length…
begin
- $stdout.puts fields.to_csv
- cond = { :project_id => project_id.to_i }
- if line_type
- cond[:line_type] = line_type.downcase
- end
- Call.where(cond).order(number: :asc).each do |r|
- out = []
- fields.each do |f|
- out << r[f].to_s
- end
- $stdout.puts out.to_csv
- end
+ $stdout.puts fields.to_csv
+ cond = { :project_id => project_id.to_i }
+ if line_type
+ cond[:line_type] = line_type.downcase
+ end
+ Call.where(cond).order(number: :asc).each do |r|
+ out = []
+ fields.each do |f|
+ out << r[f].to_s
+ end
+ $stdout.puts out.to_csv
+ end
end
diff --git a/bin/iaxrecord.rb b/bin/iaxrecord.rb
@@ -4,7 +4,7 @@ $:.unshift(::File.join(::File.dirname(__FILE__), "..", "lib"))
def stop
- exit(0)
+ exit(0)
end
trap("SIGINT") { stop() }
@@ -16,56 +16,56 @@ require "optparse"
parser = OptionParser.new
opts = {
- :recording_time => 52
+ :recording_time => 52
}
parser.banner = "Usage: #{$0} [options]"
parser.on("-s server") do |v|
- opts[:server_host] = v
+ opts[:server_host] = v
end
parser.on("-u user") do |v|
- opts[:username] = v
+ opts[:username] = v
end
parser.on("-p pass") do |v|
- opts[:password] = v
+ opts[:password] = v
end
parser.on("-o output") do |v|
- opts[:output] = v
+ opts[:output] = v
end
parser.on("-n number") do |v|
- opts[:called_number] = v
+ opts[:called_number] = v
end
parser.on("-c cid") do |v|
- opts[:caller_number] = v
+ opts[:caller_number] = v
end
parser.on("-l seconds") do |v|
- opts[:recording_time] = v.to_i
+ opts[:recording_time] = v.to_i
end
parser.on("-d") do |v|
- opts[:debugging] = true
+ opts[:debugging] = true
end
parser.on("-k keys") do |v|
- opts[:sendkeys] = v
+ opts[:sendkeys] = v
end
parser.on("-h") do
- $stderr.puts parser
- exit(1)
+ $stderr.puts parser
+ exit(1)
end
parser.parse!(ARGV)
if not (opts[:server_host] and opts[:username] and opts[:password] and opts[:c…
- $stderr.puts parser
- exit(1)
+ $stderr.puts parser
+ exit(1)
end
@@ -74,33 +74,33 @@ cli = WarVOX::Proto::IAX2::Client.new(opts)
reg = cli.create_call
r = reg.register
if not r
- $stderr.puts "ERROR: Unable to register with the IAX server"
- exit(0)
+ $stderr.puts "ERROR: Unable to register with the IAX server"
+ exit(0)
end
c = cli.create_call
r = c.dial( opts[:called_number] )
if not r
- $stderr.puts "ERROR: Unable to dial the requested number"
- exit(0)
+ $stderr.puts "ERROR: Unable to dial the requested number"
+ exit(0)
end
begin
::Timeout.timeout( opts[:recording_time] ) do
- while (c.state != :hangup)
- case c.state
- when :ringing
- when :answered
- when :hangup
- break
- end
- select(nil,nil,nil, 0.25)
- end
+ while (c.state != :hangup)
+ case c.state
+ when :ringing
+ when :answered
+ when :hangup
+ break
+ end
+ select(nil,nil,nil, 0.25)
+ end
end
rescue ::Timeout::Error
ensure
- c.hangup rescue nil
+ c.hangup rescue nil
end
cli.shutdown
@@ -108,8 +108,8 @@ cli.shutdown
cnt = 0
fd = ::File.open( opts[:output], "wb")
c.each_audio_frame do |frame|
- fd.write(frame)
- cnt += frame.length
+ fd.write(frame)
+ cnt += frame.length
end
fd.close
diff --git a/bin/identify_matches.rb b/bin/identify_matches.rb
@@ -6,7 +6,7 @@
#
base = __FILE__
while File.symlink?(base)
- base = File.expand_path(File.readlink(base), File.dirname(base))
+ base = File.expand_path(File.readlink(base), File.dirname(base))
end
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..', 'lib'))
@@ -19,8 +19,8 @@ require 'config/boot'
require 'config/environment'
def usage
- $stderr.puts "Usage: #{$0} [job|all] <fprint>"
- exit
+ $stderr.puts "Usage: #{$0} [job|all] <fprint>"
+ exit
end
#
@@ -31,49 +31,49 @@ job = ARGV.shift
fp = ARGV.shift
if(job and job == "-h")
- usage()
+ usage()
end
if(not job)
- $stderr.puts "Listing all available jobs"
- $stderr.puts "=========================="
- DialJob.find(:all).each do |j|
- puts "#{j.id}\t#{j.started_at} --> #{j.completed_at}"
- end
- exit
+ $stderr.puts "Listing all available jobs"
+ $stderr.puts "=========================="
+ DialJob.find(:all).each do |j|
+ puts "#{j.id}\t#{j.started_at} --> #{j.completed_at}"
+ end
+ exit
end
fp = $stdin.read.strip if fp == "-"
job = nil if job.downcase == "all"
if not fp
- usage()
+ usage()
end
begin
- res = nil
- job = DialJob.find(job.to_i) if job
- if job
- res = DialResult.find_by_sql "SELECT dial_results.*, " +
- " (( icount('#{fp}'::int[] & dial_results.fprint::int[…
- "FROM dial_results " +
- "WHERE " +
- " icount(dial_results.fprint) > 0 AND " +
- " dial_results.dial_job_id = '#{job.id}' " +
- "ORDER BY matchscore DESC"
- else
- res = DialResult.find_by_sql "SELECT dial_results.*, " +
- " (( icount('#{fp}'::int[] & dial_results.fprint::int[…
- "FROM dial_results " +
- "WHERE " +
- " icount(dial_results.fprint) > 0 " +
- "ORDER BY matchscore DESC"
- end
- res.each do |r|
- $stdout.puts "#{"%.2f" % r.matchscore}\t#{r.dial_job_id}\t#{r.…
- end
+ res = nil
+ job = DialJob.find(job.to_i) if job
+ if job
+ res = DialResult.find_by_sql "SELECT dial_results.*, " +
+ " (( icount('#{fp}'::int[] & dial_results.fprint::int[]) / icount('#{fp}…
+ "FROM dial_results " +
+ "WHERE " +
+ " icount(dial_results.fprint) > 0 AND " +
+ " dial_results.dial_job_id = '#{job.id}' " +
+ "ORDER BY matchscore DESC"
+ else
+ res = DialResult.find_by_sql "SELECT dial_results.*, " +
+ " (( icount('#{fp}'::int[] & dial_results.fprint::int[]) / icount('#{fp}…
+ "FROM dial_results " +
+ "WHERE " +
+ " icount(dial_results.fprint) > 0 " +
+ "ORDER BY matchscore DESC"
+ end
+ res.each do |r|
+ $stdout.puts "#{"%.2f" % r.matchscore}\t#{r.dial_job_id}\t#{r.number}"
+ end
rescue ActiveRecord::RecordNotFound
- $stderr.puts "Job not found"
- exit
+ $stderr.puts "Job not found"
+ exit
end
diff --git a/bin/import_audio.rb b/bin/import_audio.rb
@@ -6,7 +6,7 @@
#
base = __FILE__
while File.symlink?(base)
- base = File.expand_path(File.readlink(base), File.dirname(base))
+ base = File.expand_path(File.readlink(base), File.dirname(base))
end
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..', 'lib'))
@@ -19,8 +19,8 @@ ENV['RAILS_ENV'] ||= 'production'
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..'))
def usage
- $stderr.puts "Usage: #{$0} [Input Directory] <Project ID> <Provider ID…
- exit(1)
+ $stderr.puts "Usage: #{$0} [Input Directory] <Project ID> <Provider ID>"
+ exit(1)
end
#
@@ -29,7 +29,7 @@ end
dir = ARGV.shift() || usage()
if (dir and dir =="-h") or (! dir)
- usage()
+ usage()
end
require 'config/boot'
@@ -41,47 +41,47 @@ provider_id = ARGV.shift
todo = Dir["#{dir}/**/*.raw"].to_a
if todo.empty?
- $stderr.puts "Error: No raw audio files found within #{dir}"
- exit(1)
+ $stderr.puts "Error: No raw audio files found within #{dir}"
+ exit(1)
end
project = nil
provider = nil
if project_id
- project = Project.where(:id => project_id).first
- unless project
- $stderr.puts "Error: Specified Project ID not found"
- exit(1)
- end
+ project = Project.where(:id => project_id).first
+ unless project
+ $stderr.puts "Error: Specified Project ID not found"
+ exit(1)
+ end
end
if provider_id
- provider = Provider.where(:id => provider_id).first
- unless provider
- $stderr.puts "Error: Specified Provider ID not found"
- exit(1)
- end
+ provider = Provider.where(:id => provider_id).first
+ unless provider
+ $stderr.puts "Error: Specified Provider ID not found"
+ exit(1)
+ end
end
unless project
- project = Project.create(
- :name => "Import from #{dir} at #{Time.now.utc.to_s}",
- :created_by => "importer"
- )
+ project = Project.create(
+ :name => "Import from #{dir} at #{Time.now.utc.to_s}",
+ :created_by => "importer"
+ )
end
provider = Provider.first
unless provider
- provider = Provider.create(
- :name => 'Import Provider',
- :host => 'localhost',
- :port => 4369,
- :user => "null",
- :pass => "null",
- :lines => 1,
- :enabled => false
- )
+ provider = Provider.create(
+ :name => 'Import Provider',
+ :host => 'localhost',
+ :port => 4369,
+ :user => "null",
+ :pass => "null",
+ :lines => 1,
+ :enabled => false
+ )
end
@@ -100,32 +100,32 @@ pct = 0
cnt = 0
todo.each do |rfile|
- num, ext = File.basename(rfile).split(".", 2)
- dr = Call.new
- dr.number = num
- dr.job_id = job.id
- dr.project_id = project.id
- dr.provider_id = provider.id
- dr.answered = true
- dr.busy = false
- dr.audio_length = File.size(rfile) / 16000.0
- dr.ring_length = 0
- dr.caller_id = num
- dr.save
-
- mr = dr.media
- ::File.open(rfile, "rb") do |fd|
- mr.audio = fd.read(fd.stat.size)
- mr.save
- end
-
- cnt += 1
- pct = (cnt / todo.length.to_f) * 100.0
- if cnt % 10 == 0
- job.update_progress(pct)
- end
-
- $stdout.puts "[ %#{"%.3d" % pct.to_i} ] Imported #{num} into project '…
+ num, ext = File.basename(rfile).split(".", 2)
+ dr = Call.new
+ dr.number = num
+ dr.job_id = job.id
+ dr.project_id = project.id
+ dr.provider_id = provider.id
+ dr.answered = true
+ dr.busy = false
+ dr.audio_length = File.size(rfile) / 16000.0
+ dr.ring_length = 0
+ dr.caller_id = num
+ dr.save
+
+ mr = dr.media
+ ::File.open(rfile, "rb") do |fd|
+ mr.audio = fd.read(fd.stat.size)
+ mr.save
+ end
+
+ cnt += 1
+ pct = (cnt / todo.length.to_f) * 100.0
+ if cnt % 10 == 0
+ job.update_progress(pct)
+ end
+
+ $stdout.puts "[ %#{"%.3d" % pct.to_i} ] Imported #{num} into project '#{proj…
end
job.update_progress(100)
diff --git a/bin/resetpw b/bin/resetpw
@@ -20,31 +20,31 @@ uname = ARGV.shift
upass = ARGV.shift
def generate_password
- set = ( [*(0x21 .. 0x2f)] + [*(0x3a .. 0x3F)] + [*(0x5b .. 0x60)] + [*…
- set << "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
- str = ''
- cnt = 0
- while not (str.length >= 8 and str =~ /[A-Za-z]/ and str =~ /[0-9]/ an…
- if str.length > 12
- str = str[0,4]
- next
- end
- str << set[ rand(set.length), 1]
- cnt += 1
- end
- str
+ set = ( [*(0x21 .. 0x2f)] + [*(0x3a .. 0x3F)] + [*(0x5b .. 0x60)] + [*(0x7b …
+ set << "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+ str = ''
+ cnt = 0
+ while not (str.length >= 8 and str =~ /[A-Za-z]/ and str =~ /[0-9]/ and str …
+ if str.length > 12
+ str = str[0,4]
+ next
+ end
+ str << set[ rand(set.length), 1]
+ cnt += 1
+ end
+ str
end
user = uname ? User.find_by_login(uname) : User.first
if uname and not user
- $stderr.puts "[-] User #{uname} was not found"
- exit(1)
+ $stderr.puts "[-] User #{uname} was not found"
+ exit(1)
end
if not user
- $stderr.puts "[-] No user account has been created"
- exit(1)
+ $stderr.puts "[-] No user account has been created"
+ exit(1)
end
randpass = upass || generate_password()
@@ -69,9 +69,9 @@ $stdout.flush
inp = $stdin.readline
if inp.strip.downcase != 'yes'
- $stdout.puts "[*] Reset cancelled, hit enter to exit"
- $stdin.readline
- exit(0)
+ $stdout.puts "[*] Reset cancelled, hit enter to exit"
+ $stdin.readline
+ exit(0)
end
diff --git a/bin/verify_install.rb b/bin/verify_install.rb
@@ -6,7 +6,7 @@
#
base = __FILE__
while File.symlink?(base)
- base = File.expand_path(File.readlink(base), File.dirname(base))
+ base = File.expand_path(File.readlink(base), File.dirname(base))
end
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..', 'lib'))
require 'warvox'
@@ -24,34 +24,34 @@ puts(" ")
begin
- require 'rubygems'
- puts "[*] RubyGems have been installed"
+ require 'rubygems'
+ puts "[*] RubyGems have been installed"
rescue ::LoadError
- puts "[*] ERROR: The RubyGems package has not been installed:"
- puts " $ sudo apt-get install rubygems"
- exit
+ puts "[*] ERROR: The RubyGems package has not been installed:"
+ puts " $ sudo apt-get install rubygems"
+ exit
end
begin
- require 'bundler'
- puts "[*] The Bundler gem has been installed"
+ require 'bundler'
+ puts "[*] The Bundler gem has been installed"
rescue ::LoadError
- puts "[*] ERROR: The Bundler gem has not been installed:"
- puts " $ sudo gem install bundler"
- exit
+ puts "[*] ERROR: The Bundler gem has not been installed:"
+ puts " $ sudo gem install bundler"
+ exit
end
if(not WarVOX::Config.tool_path('gnuplot'))
- puts "[*] ERROR: The 'gnuplot' binary could not be installed"
- puts "[*] $ sudo apt-get install gnuplot"
- exit
+ puts "[*] ERROR: The 'gnuplot' binary could not be installed"
+ puts "[*] $ sudo apt-get install gnuplot"
+ exit
end
puts "[*] The GNUPlot binary appears to be available"
if(not WarVOX::Config.tool_path('lame'))
- puts "[*] ERROR: The 'lame' binary could not be installed"
- puts "[*] $ sudo apt-get install lame"
- exit
+ puts "[*] ERROR: The 'lame' binary could not be installed"
+ puts "[*] $ sudo apt-get install lame"
+ exit
end
puts "[*] The LAME binary appears to be available"
diff --git a/bin/warvox.rb b/bin/warvox.rb
@@ -9,7 +9,7 @@ require 'open3'
#
base = __FILE__
while File.symlink?(base)
- base = File.expand_path(File.readlink(base), File.dirname(base))
+ base = File.expand_path(File.readlink(base), File.dirname(base))
end
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..', 'lib'))
@@ -24,52 +24,52 @@ require 'warvox'
Dir.chdir(voxroot)
def stop
- $stderr.puts "[-] Interrupt received, shutting down workers and web se…
- Process.kill("TERM", @manager_pid) if @manager_pid
- exit(0)
+ $stderr.puts "[-] Interrupt received, shutting down workers and web server..…
+ Process.kill("TERM", @manager_pid) if @manager_pid
+ exit(0)
end
def usage
- $stderr.puts "#{$0} [--address IP] [--port PORT] --background"
- exit(0)
+ $stderr.puts "#{$0} [--address IP] [--port PORT] --background"
+ exit(0)
end
opts =
{
- 'ServerPort' => 7777,
- 'ServerHost' => '127.0.0.1',
- 'Background' => false,
+ 'ServerPort' => 7777,
+ 'ServerHost' => '127.0.0.1',
+ 'Background' => false,
}
args = GetoptLong.new(
- ["--address", "-a", GetoptLong::REQUIRED_ARGUMENT ],
- ["--port", "-p", GetoptLong::REQUIRED_ARGUMENT ],
- ["--daemon", "-d", GetoptLong::NO_ARGUMENT ],
- ["--help", "-h", GetoptLong::NO_ARGUMENT]
+ ["--address", "-a", GetoptLong::REQUIRED_ARGUMENT ],
+ ["--port", "-p", GetoptLong::REQUIRED_ARGUMENT ],
+ ["--daemon", "-d", GetoptLong::NO_ARGUMENT ],
+ ["--help", "-h", GetoptLong::NO_ARGUMENT]
)
args.each do |opt,arg|
- case opt
- when '--address'
- opts['ServerHost'] = arg
- when '--port'
- opts['ServerPort'] = arg
- when '--daemon'
- opts['Background'] = true
- when '--help'
- usage()
- end
+ case opt
+ when '--address'
+ opts['ServerHost'] = arg
+ when '--port'
+ opts['ServerPort'] = arg
+ when '--daemon'
+ opts['Background'] = true
+ when '--help'
+ usage()
+ end
end
args = [
- 'server',
- '-p', opts['ServerPort'].to_s,
- '-b', opts['ServerHost'],
- '-e', 'production',
+ 'server',
+ '-p', opts['ServerPort'].to_s,
+ '-b', opts['ServerHost'],
+ '-e', 'production',
]
if opts['Background']
- args.push("-d")
+ args.push("-d")
end
@@ -86,10 +86,10 @@ WarVOX::Log.info("WarVOX is starting up...")
@manager_pid = Process.fork()
if not @manager_pid
- while ARGV.shift do
- end
- load(manager)
- exit(0)
+ while ARGV.shift do
+ end
+ load(manager)
+ exit(0)
end
WarVOX::Log.info("Worker Manager has PID #{@manager_pid}")
diff --git a/bin/worker.rb b/bin/worker.rb
@@ -6,7 +6,7 @@
#
base = __FILE__
while File.symlink?(base)
- base = File.expand_path(File.readlink(base), File.dirname(base))
+ base = File.expand_path(File.readlink(base), File.dirname(base))
end
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..', 'lib'))
@@ -21,18 +21,18 @@ $:.unshift(File.join(File.expand_path(File.dirname(base)), …
@job = nil
def usage
- $stderr.puts "Usage: #{$0} [JID]"
- exit(1)
+ $stderr.puts "Usage: #{$0} [JID]"
+ exit(1)
end
def stop
- if @task
- @task.stop() rescue nil
- end
- if @job
- Job.where(id: @job_id).update_all({ status: 'stopped', complet…
- end
- exit(0)
+ if @task
+ @task.stop() rescue nil
+ end
+ if @job
+ Job.where(id: @job_id).update_all({ status: 'stopped', completed_at: Time.…
+ end
+ exit(0)
end
#
@@ -41,7 +41,7 @@ end
jid = ARGV.shift() || usage()
if (jid and jid =="-h") or (! jid)
- usage()
+ usage()
end
require 'config/boot'
@@ -54,9 +54,9 @@ jid = jid.to_i
@job = Job.where(id: jid).first
unless @job
- $stderr.puts "Error: Specified job not found"
- WarVOX::Log.warn("Worker rejected invalid Job #{jid}")
- exit(1)
+ $stderr.puts "Error: Specified job not found"
+ WarVOX::Log.warn("Worker rejected invalid Job #{jid}")
+ exit(1)
end
$0 = "warvox worker: #{jid} "
@@ -72,20 +72,20 @@ begin
case @job.task
when 'dialer'
- @task = WarVOX::Jobs::Dialer.new(@job.id, args)
- @task.start
+ @task = WarVOX::Jobs::Dialer.new(@job.id, args)
+ @task.start
when 'analysis'
- @task = WarVOX::Jobs::Analysis.new(@job.id, args)
- @task.start
+ @task = WarVOX::Jobs::Analysis.new(@job.id, args)
+ @task.start
else
- Job.where(id: @job.id).update_all({ error: 'unsupported', status: 'err…
+ Job.where(id: @job.id).update_all({ error: 'unsupported', status: 'error' })
end
@job.update_progress(100)
rescue ::SignalException, ::SystemExit
- raise $!
+ raise $!
rescue ::Exception => e
- WarVOX::Log.warn("Worker #{@job.id} #{@job.task} threw an exception: #…
- Job.where(id: @job.id).update_all({ error: "Exception: #{e.class} #{e}…
+ WarVOX::Log.warn("Worker #{@job.id} #{@job.task} threw an exception: #{e.cla…
+ Job.where(id: @job.id).update_all({ error: "Exception: #{e.class} #{e}", sta…
end
diff --git a/bin/worker_manager.rb b/bin/worker_manager.rb
@@ -6,7 +6,7 @@
#
base = __FILE__
while File.symlink?(base)
- base = File.expand_path(File.readlink(base), File.dirname(base))
+ base = File.expand_path(File.readlink(base), File.dirname(base))
end
$:.unshift(File.join(File.expand_path(File.dirname(base)), '..', 'lib'))
@@ -25,136 +25,136 @@ require 'config/environment'
@jobs = []
def stop
- WarVOX::Log.info("Worker Manager is terminating due to signal")
+ WarVOX::Log.info("Worker Manager is terminating due to signal")
- unless @jobs.length > 0
- exit(0)
- end
+ unless @jobs.length > 0
+ exit(0)
+ end
- # Update the database
- Job.update_all({ :status => "stopped", :completed_at => Time.now.utc},…
+ # Update the database
+ Job.update_all({ :status => "stopped", :completed_at => Time.now.utc}, { :id…
- # Signal running jobs to shut down
- @jobs.map{|j| Process.kill("TERM", j[:pid]) rescue nil }
+ # Signal running jobs to shut down
+ @jobs.map{|j| Process.kill("TERM", j[:pid]) rescue nil }
- # Sleep for five seconds
- sleep(5)
+ # Sleep for five seconds
+ sleep(5)
- # Forcibly kill any remaining job processes
- @jobs.map{|j| Process.kill("KILL", j[:pid]) rescue nil }
+ # Forcibly kill any remaining job processes
+ @jobs.map{|j| Process.kill("KILL", j[:pid]) rescue nil }
- exit(0)
+ exit(0)
end
def clear_zombies
- while ( r = Process.waitpid(-1, Process::WNOHANG) rescue nil ) do
- end
+ while ( r = Process.waitpid(-1, Process::WNOHANG) rescue nil ) do
+ end
end
def schedule_job(j)
- WarVOX::Log.debug("Worker Manager is launching job #{j.id}")
- @jobs << {
- :id => j.id,
- :pid => Process.fork { exec("#{@worker_path} #{j.id}") }
- }
+ WarVOX::Log.debug("Worker Manager is launching job #{j.id}")
+ @jobs << {
+ :id => j.id,
+ :pid => Process.fork { exec("#{@worker_path} #{j.id}") }
+ }
end
def stop_cancelled_jobs
- jids = []
- @jobs.each do |x|
- jids << x[:id]
- end
-
- return if jids.length == 0
- Job.where(:status => 'cancelled', :id => jids).find_each do |j|
- job = @jobs.select{ |o| o[:id] == j.id }.first
- next unless job and job[:pid]
- pid = job[:pid]
-
- WarVOX::Log.debug("Worker Manager is killing job #{j.id} with …
- Process.kill('TERM', pid)
- end
+ jids = []
+ @jobs.each do |x|
+ jids << x[:id]
+ end
+
+ return if jids.length == 0
+ Job.where(:status => 'cancelled', :id => jids).find_each do |j|
+ job = @jobs.select{ |o| o[:id] == j.id }.first
+ next unless job and job[:pid]
+ pid = job[:pid]
+
+ WarVOX::Log.debug("Worker Manager is killing job #{j.id} with PID #{pid}")
+ Process.kill('TERM', pid)
+ end
end
def clear_completed_jobs
- dead_pids = []
- dead_jids = []
+ dead_pids = []
+ dead_jids = []
- @jobs.each do |j|
- alive = Process.kill(0, j[:pid]) rescue nil
- next if alive
- dead_pids << j[:pid]
- dead_jids << j[:id]
- end
+ @jobs.each do |j|
+ alive = Process.kill(0, j[:pid]) rescue nil
+ next if alive
+ dead_pids << j[:pid]
+ dead_jids << j[:id]
+ end
- return unless dead_jids.length > 0
+ return unless dead_jids.length > 0
- WarVOX::Log.debug("Worker Manager is clearing #{dead_pids.length} comp…
+ WarVOX::Log.debug("Worker Manager is clearing #{dead_pids.length} completed …
- @jobs = @jobs.reject{|x| dead_pids.include?( x[:pid] ) }
+ @jobs = @jobs.reject{|x| dead_pids.include?( x[:pid] ) }
- # Mark failed/crashed jobs as completed
- Job.where(id: dead_jids, completed_at: nil).update_all({completed_at: …
+ # Mark failed/crashed jobs as completed
+ Job.where(id: dead_jids, completed_at: nil).update_all({completed_at: Time.n…
end
def clear_stale_jobs
- jids = @jobs.map{|x| x[:id] }
- stale = nil
-
- if jids.length > 0
- stale = Job.where("completed_at IS NULL AND locked_by LIKE ? A…
- else
- stale = Job.where("completed_at IS NULL AND locked_by LIKE ?",…
- end
-
- dead = []
- pids = {}
-
- # Extract the PID from the locked_by cookie for each job
- stale.each do |j|
- host, pid, uniq = j.locked_by.to_s.split("^", 3)
- next unless (pid and uniq)
- pids[pid] ||= []
- pids[pid] << j
- end
-
- # Identify dead processes (must be same user or root)
- pids.keys.each do |pid|
- alive = Process.kill(0, pid.to_i) rescue nil
- next if alive
- pids[pid].each do |j|
- dead << j.id
- end
- end
-
- # Mark these jobs as abandoned
- if dead.length > 0
- WarVOX::Log.debug("Worker Manager is marking #{dead.length} jo…
- Job.where(:id => dead).update_all({locked_by: nil, status: 'ab…
- end
+ jids = @jobs.map{|x| x[:id] }
+ stale = nil
+
+ if jids.length > 0
+ stale = Job.where("completed_at IS NULL AND locked_by LIKE ? AND id NOT IN…
+ else
+ stale = Job.where("completed_at IS NULL AND locked_by LIKE ?", Socket.geth…
+ end
+
+ dead = []
+ pids = {}
+
+ # Extract the PID from the locked_by cookie for each job
+ stale.each do |j|
+ host, pid, uniq = j.locked_by.to_s.split("^", 3)
+ next unless (pid and uniq)
+ pids[pid] ||= []
+ pids[pid] << j
+ end
+
+ # Identify dead processes (must be same user or root)
+ pids.keys.each do |pid|
+ alive = Process.kill(0, pid.to_i) rescue nil
+ next if alive
+ pids[pid].each do |j|
+ dead << j.id
+ end
+ end
+
+ # Mark these jobs as abandoned
+ if dead.length > 0
+ WarVOX::Log.debug("Worker Manager is marking #{dead.length} jobs as abando…
+ Job.where(:id => dead).update_all({locked_by: nil, status: 'abandoned'})
+ end
end
def schedule_submitted_jobs
- loop do
- # Look for a candidate job with no current owner
- j = Job.where(status: 'submitted', locked_by: nil).limit(1).f…
- return unless j
+ loop do
+ # Look for a candidate job with no current owner
+ j = Job.where(status: 'submitted', locked_by: nil).limit(1).first
+ return unless j
- # Try to get a lock on this job
- Job.where(id: j.id, locked_by: nil).update_all({locked_by: @co…
+ # Try to get a lock on this job
+ Job.where(id: j.id, locked_by: nil).update_all({locked_by: @cookie, locked…
- # See if we actually got the lock
- j = Job.where(id: j.id, status: 'scheduled', locked_by: @cook…
+ # See if we actually got the lock
+ j = Job.where(id: j.id, status: 'scheduled', locked_by: @cookie).limit(1)…
- # Try again if we lost the race,
- next unless j
+ # Try again if we lost the race,
+ next unless j
- # Hurray, we got a job, run it
- schedule_job(j)
+ # Hurray, we got a job, run it
+ schedule_job(j)
- return true
- end
+ return true
+ end
end
#
@@ -171,24 +171,24 @@ trap("SIGTERM") { stop() }
WarVOX::Log.info("Worker Manager initialized with cookie #{@cookie}")
loop do
- $0 = "warvox manager: #{@jobs.length} active jobs (cookie : #{@cookie}…
+ $0 = "warvox manager: #{@jobs.length} active jobs (cookie : #{@cookie})"
- # Clear any zombie processes
- clear_zombies()
+ # Clear any zombie processes
+ clear_zombies()
- # Clear any completed jobs
- clear_completed_jobs()
+ # Clear any completed jobs
+ clear_completed_jobs()
- # Stop any jobs cancelled by the user
- stop_cancelled_jobs()
+ # Stop any jobs cancelled by the user
+ stop_cancelled_jobs()
- # Clear locks on any stale jobs from this host
- clear_stale_jobs()
+ # Clear locks on any stale jobs from this host
+ clear_stale_jobs()
- while @jobs.length < @max_jobs
- break unless schedule_submitted_jobs
- end
+ while @jobs.length < @max_jobs
+ break unless schedule_submitted_jobs
+ end
- # Sleep between 3-8 seconds before re-entering the loop
- sleep(rand(5) + 3)
+ # Sleep between 3-8 seconds before re-entering the loop
+ sleep(rand(5) + 3)
end
diff --git a/config/classifiers/01.default.rb b/config/classifiers/01.default.rb
@@ -29,24 +29,24 @@ maxf = data[:maxf]
# Look for modems by detecting a 2100hz answer + 2250hz tone
#
if( (fcnt[2100] > 1.0 or fcnt[2230] > 1.0) and fcnt[2250] > 0.5)
- @line_type = 'modem'
- raise Completed
+ @line_type = 'modem'
+ raise Completed
end
#
# Look for modems by detecting a peak frequency of 2250hz
#
if(fcnt[2100] > 1.0 and (maxf > 2245.0 and maxf < 2255.0))
- @line_type = 'modem'
- raise Completed
+ @line_type = 'modem'
+ raise Completed
end
#
# Look for modems by detecting a peak frequency of 3000hz
#
if(fcnt[2100] > 1.0 and (maxf > 2995.0 and maxf < 3005.0))
- @line_type = 'modem'
- raise Completed
+ @line_type = 'modem'
+ raise Completed
end
#
@@ -54,22 +54,22 @@ end
#
fax_sum = 0
[
- fcnt[1625], fcnt[1660], fcnt[1825], fcnt[2100],
- fcnt[600], fcnt[1855], fcnt[1100], fcnt[2250],
- fcnt[2230], fcnt[2220], fcnt[1800], fcnt[2095],
- fcnt[2105]
+ fcnt[1625], fcnt[1660], fcnt[1825], fcnt[2100],
+ fcnt[600], fcnt[1855], fcnt[1100], fcnt[2250],
+ fcnt[2230], fcnt[2220], fcnt[1800], fcnt[2095],
+ fcnt[2105]
].map{|x| fax_sum += [x,1.0].min }
if(fax_sum >= 2.0)
- @line_type = 'fax'
- raise Completed
+ @line_type = 'fax'
+ raise Completed
end
#
# Dial tone detection (440hz + 350hz)
#
if(fcnt[440] > 1.0 and fcnt[350] > 1.0)
- @line_type = 'dialtone'
- raise Completed
+ @line_type = 'dialtone'
+ raise Completed
end
#
diff --git a/config/classifiers/99.default.rb b/config/classifiers/99.default.rb
@@ -15,16 +15,16 @@ maxf = data[:maxf]
# this signature can fail. For non-US numbers, the beep
# is often a different frequency entirely.
if(fcnt[1000] >= 1.0)
- @line_type = 'voicemail'
- raise Completed
+ @line_type = 'voicemail'
+ raise Completed
end
# Look for voicemail by detecting a peak frequency of
# 1000hz. Not as accurate, but thats why this is in
# the fallback script.
if(maxf > 995 and maxf < 1005)
- @line_type = 'voicemail'
- raise Completed
+ @line_type = 'voicemail'
+ raise Completed
end
diff --git a/db/migrate/20121228171549_initial_schema.rb b/db/migrate/201212281…
@@ -1,182 +1,182 @@
class InitialSchema < ActiveRecord::Migration
- def up
-
- # Require the intarray extension
- execute("CREATE EXTENSION IF NOT EXISTS intarray")
-
- create_table :settings do |t|
- t.string :var, :null => false
- t.text :value, :null => true
- t.integer :thing_id, :null => true
- t.string :thing_type, :limit => 30, :null => true
- t.timestamps
- end
-
- add_index :settings, [ :thing_type, :thing_id, :var ], :unique…
-
- create_table 'users' do |t|
- t.string :login, :null => false …
- t.string :email, :null => true …
- t.string :crypted_password, :null => false …
- t.string :password_salt, :null => false …
- t.string :persistence_token, :null => false …
- t.string :single_access_token, :null => false …
- t.string :perishable_token, :null => false …
-
- # Magic columns, just like ActiveRecord's created_at a…
- t.integer :login_count, :null => false, :def…
- t.integer :failed_login_count, :null => false, :def…
- t.datetime :last_request_at …
- t.datetime :current_login_at …
- t.datetime :last_login_at …
- t.string :current_login_ip …
- t.string :last_login_ip …
-
- t.timestamps
- t.boolean "enabled", :default => true
- t.boolean "admin", :default => true
- end
-
- create_table 'projects' do |t|
- t.timestamps
- t.text "name", :null => false
- t.text "description"
- t.text "included"
- t.text "excluded"
- t.string "created_by"
- end
-
- create_table "jobs" do |t|
- t.timestamps
- t.integer "project_id", :null => false
- t.string "locked_by"
- t.timestamp "locked_at"
- t.timestamp "started_at"
- t.timestamp "completed_at"
- t.string "created_by"
- t.string "task", :null => false
- t.binary "args"
- t.string "status"
- t.text "error"
- t.integer "progress", :default => 0
- end
-
- create_table "lines" do |t|
- t.timestamps
- t.text "number", :null => false
- t.integer "project_id", :null => false
- t.text "line_type"
- t.text "notes"
- end
-
- create_table "line_attributes" do |t|
- t.timestamps
- t.integer "line_id", :null => false
- t.integer "project_id", :null => false
- t.text "name", :null => false
- t.binary "value", :null => false
- t.string "content_type", :default => "t…
- end
-
- create_table "calls" do |t|
- # Created by the dialer job
- t.timestamps
- t.text "number", :null => false
- t.integer "project_id", :null => false
- t.integer "job_id", :null => false
- t.integer "provider_id", :null => false
- t.boolean "answered"
- t.boolean "busy"
- t.text "error"
- t.integer "audio_length"
- t.integer "ring_length"
- t.text "caller_id"
-
- # Generated by the analysis job
- t.integer "analysis_job_id"
- t.timestamp "analysis_started_at"
- t.timestamp "analysis_completed_at"
- t.float "peak_freq"
- t.text "peak_freq_data"
- t.text "line_type"
- t.integer "fprint", :array => true
- end
-
- create_table "call_media" do |t|
- t.integer "call_id", :null => false
- t.integer "project_id", :null => false
- t.binary "audio"
- t.binary "mp3"
- t.binary "png_big"
- t.binary "png_big_dots"
- t.binary "png_big_freq"
- t.binary "png_sig"
- t.binary "png_sig_freq"
- end
-
- create_table "signatures" do |t|
- t.timestamps
- t.text "name", :null => false
- t.string "source"
- t.text "description"
- t.string "category"
- t.string "line_type"
- t.integer "risk"
- end
-
- create_table "signature_fp" do |t|
- t.integer "signature_id", :null => false
- t.integer "fprint", :array => true
- end
-
- create_table "providers" do |t|
- t.timestamps
- t.text "name", :null => false
- t.text "host", :null => false
- t.integer "port", :null => false
- t.text "user"
- t.text "pass"
- t.integer "lines", :null => false, :def…
- t.boolean "enabled", :default => true
- end
-
- add_index :jobs, :project_id
- add_index :lines, :number
- add_index :lines, :project_id
- add_index :line_attributes, :line_id
- add_index :line_attributes, :project_id
- add_index :calls, :number
- add_index :calls, :job_id
- add_index :calls, :provider_id
- add_index :call_media, :call_id
- add_index :call_media, :project_id
- add_index :signature_fp, :signature_id
-
- end
-
- def down
- remove_index :jobs, :project_id
- remove_index :lines, :number
- remove_index :lines, :project_id
- remove_index :line_attributes, :line_id
- remove_index :line_attributes, :project_id
- remove_index :calls, :number
- remove_index :calls, :job_id
- remove_index :calls, :provider_id
- remove_index :call_media, :call_id
- remove_index :call_media, :project_id
- remove_index :signature_fp, :signature_id
-
- drop_table "providers"
- drop_table "signature_fp"
- drop_table "signatures"
- drop_table "call_media"
- drop_table "calls"
- drop_table "line_attributes"
- drop_table "lines"
- drop_table "jobs"
- drop_table "projects"
- drop_table "users"
- drop_table "settings"
- end
+ def up
+
+ # Require the intarray extension
+ execute("CREATE EXTENSION IF NOT EXISTS intarray")
+
+ create_table :settings do |t|
+ t.string :var, :null => false
+ t.text :value, :null => true
+ t.integer :thing_id, :null => true
+ t.string :thing_type, :limit => 30, :null => true
+ t.timestamps
+ end
+
+ add_index :settings, [ :thing_type, :thing_id, :var ], :unique => true
+
+ create_table 'users' do |t|
+ t.string :login, :null => false # option…
+ t.string :email, :null => true # option…
+ t.string :crypted_password, :null => false # option…
+ t.string :password_salt, :null => false # option…
+ t.string :persistence_token, :null => false # requir…
+ t.string :single_access_token, :null => false # option…
+ t.string :perishable_token, :null => false # option…
+
+ # Magic columns, just like ActiveRecord's created_at and updated_at. The…
+ t.integer :login_count, :null => false, :default => 0 # option…
+ t.integer :failed_login_count, :null => false, :default => 0 # option…
+ t.datetime :last_request_at # option…
+ t.datetime :current_login_at # option…
+ t.datetime :last_login_at # option…
+ t.string :current_login_ip # option…
+ t.string :last_login_ip # option…
+
+ t.timestamps
+ t.boolean "enabled", :default => true
+ t.boolean "admin", :default => true
+ end
+
+ create_table 'projects' do |t|
+ t.timestamps
+ t.text "name", :null => false
+ t.text "description"
+ t.text "included"
+ t.text "excluded"
+ t.string "created_by"
+ end
+
+ create_table "jobs" do |t|
+ t.timestamps
+ t.integer "project_id", :null => false
+ t.string "locked_by"
+ t.timestamp "locked_at"
+ t.timestamp "started_at"
+ t.timestamp "completed_at"
+ t.string "created_by"
+ t.string "task", :null => false
+ t.binary "args"
+ t.string "status"
+ t.text "error"
+ t.integer "progress", :default => 0
+ end
+
+ create_table "lines" do |t|
+ t.timestamps
+ t.text "number", :null => false
+ t.integer "project_id", :null => false
+ t.text "line_type"
+ t.text "notes"
+ end
+
+ create_table "line_attributes" do |t|
+ t.timestamps
+ t.integer "line_id", :null => false
+ t.integer "project_id", :null => false
+ t.text "name", :null => false
+ t.binary "value", :null => false
+ t.string "content_type", :default => "text"
+ end
+
+ create_table "calls" do |t|
+ # Created by the dialer job
+ t.timestamps
+ t.text "number", :null => false
+ t.integer "project_id", :null => false
+ t.integer "job_id", :null => false
+ t.integer "provider_id", :null => false
+ t.boolean "answered"
+ t.boolean "busy"
+ t.text "error"
+ t.integer "audio_length"
+ t.integer "ring_length"
+ t.text "caller_id"
+
+ # Generated by the analysis job
+ t.integer "analysis_job_id"
+ t.timestamp "analysis_started_at"
+ t.timestamp "analysis_completed_at"
+ t.float "peak_freq"
+ t.text "peak_freq_data"
+ t.text "line_type"
+ t.integer "fprint", :array => true
+ end
+
+ create_table "call_media" do |t|
+ t.integer "call_id", :null => false
+ t.integer "project_id", :null => false
+ t.binary "audio"
+ t.binary "mp3"
+ t.binary "png_big"
+ t.binary "png_big_dots"
+ t.binary "png_big_freq"
+ t.binary "png_sig"
+ t.binary "png_sig_freq"
+ end
+
+ create_table "signatures" do |t|
+ t.timestamps
+ t.text "name", :null => false
+ t.string "source"
+ t.text "description"
+ t.string "category"
+ t.string "line_type"
+ t.integer "risk"
+ end
+
+ create_table "signature_fp" do |t|
+ t.integer "signature_id", :null => false
+ t.integer "fprint", :array => true
+ end
+
+ create_table "providers" do |t|
+ t.timestamps
+ t.text "name", :null => false
+ t.text "host", :null => false
+ t.integer "port", :null => false
+ t.text "user"
+ t.text "pass"
+ t.integer "lines", :null => false, :default => 1
+ t.boolean "enabled", :default => true
+ end
+
+ add_index :jobs, :project_id
+ add_index :lines, :number
+ add_index :lines, :project_id
+ add_index :line_attributes, :line_id
+ add_index :line_attributes, :project_id
+ add_index :calls, :number
+ add_index :calls, :job_id
+ add_index :calls, :provider_id
+ add_index :call_media, :call_id
+ add_index :call_media, :project_id
+ add_index :signature_fp, :signature_id
+
+ end
+
+ def down
+ remove_index :jobs, :project_id
+ remove_index :lines, :number
+ remove_index :lines, :project_id
+ remove_index :line_attributes, :line_id
+ remove_index :line_attributes, :project_id
+ remove_index :calls, :number
+ remove_index :calls, :job_id
+ remove_index :calls, :provider_id
+ remove_index :call_media, :call_id
+ remove_index :call_media, :project_id
+ remove_index :signature_fp, :signature_id
+
+ drop_table "providers"
+ drop_table "signature_fp"
+ drop_table "signatures"
+ drop_table "call_media"
+ drop_table "calls"
+ drop_table "line_attributes"
+ drop_table "lines"
+ drop_table "jobs"
+ drop_table "projects"
+ drop_table "users"
+ drop_table "settings"
+ end
end
diff --git a/lib/warvox.rb b/lib/warvox.rb
@@ -11,10 +11,10 @@ require 'logger'
# Global configuration
module WarVOX
- VERSION = '2.0.0-dev'
- Base = File.expand_path(File.join(File.dirname(__FILE__), '..'))
- Conf = File.expand_path(File.join(Base, 'config', 'warvox.conf'))
- Log = Logger.new( WarVOX::Config.log_file )
- Log.level = WarVOX::Config.log_level
+ VERSION = '2.0.0-dev'
+ Base = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+ Conf = File.expand_path(File.join(Base, 'config', 'warvox.conf'))
+ Log = Logger.new( WarVOX::Config.log_file )
+ Log.level = WarVOX::Config.log_level
end
diff --git a/lib/warvox/audio/raw.rb b/lib/warvox/audio/raw.rb
@@ -2,329 +2,329 @@ module WarVOX
module Audio
class Raw
- @@kissfft_loaded = false
- begin
- require 'kissfft'
- @@kissfft_loaded = true
- rescue ::LoadError
- end
-
- require 'zlib'
-
- ##
- # RAW AUDIO - 8khz little-endian 16-bit signed
- ##
-
- ##
- # Static methods
- ##
-
- def self.from_str(str)
- self.class.new(str)
- end
-
- def self.from_file(path)
- if(not path)
- raise Error, "No audio path specified"
- end
-
- if(path == "-")
- return self.new($stdin.read)
- end
-
- if(not File.readable?(path))
- raise Error, "The specified audio file does not exist"
- end
-
- if(path =~ /\.gz$/)
- return self.new(Zlib::GzipReader.open(path).read)
- end
-
- self.new(File.read(path, File.size(path)))
- end
-
- ##
- # Class methods
- ##
-
- attr_accessor :samples
-
- def initialize(data)
- self.samples = data.unpack('v*').map do |s|
- (s > 0x7fff) ? (0x10000 - s) * -1 : s
- end
- end
-
- def to_raw
- self.samples.pack("v*")
- end
-
- def to_wav
- raw = self.to_raw
- wav =
- "RIFF" +
- [raw.length + 36].pack("V") +
- "WAVE" +
- "fmt " +
- [16, 1, 1, 8000, 16000, 2, 16 ].pack("VvvVVvv"…
- "data" +
- [ raw.length ].pack("V") +
- raw
- end
-
- def to_flow(opts={})
-
- lo_lim = (opts[:lo_lim] || 100).to_i
- lo_min = (opts[:lo_min] || 5).to_i
- hi_min = (opts[:hi_min] || 5).to_i
- lo_cnt = 0
- hi_cnt = 0
-
- data = self.samples.map {|c| c.abs}
-
- #
- # Granular hi/low state change list
- #
- fprint = []
- state = :lo
- idx = 0
- buff = []
-
- while (idx < data.length)
- case state
- when :lo
- while(idx < data.length and data[idx] <= lo_li…
- buff << data[idx]
- idx += 1
- end
-
- # Ignore any sequence that is too small
- fprint << [:lo, buff.length, buff - [0]] if bu…
- state = :hi
- buff = []
- next
- when :hi
- while(idx < data.length and data[idx] > lo_lim)
- buff << data[idx]
- idx += 1
- end
-
- # Ignore any sequence that is too small
- fprint << [:hi, buff.length, buff] if buff.len…
- state = :lo
- buff = []
- next
- end
- end
-
- #
- # Merge similar blocks
- #
- final = []
- prev = fprint[0]
- idx = 1
-
- while(idx < fprint.length)
-
- if(fprint[idx][0] == prev[0])
- prev[1] += fprint[idx][1]
- prev[2] += fprint[idx][2]
- else
- final << prev
- prev = fprint[idx]
- end
-
- idx += 1
- end
- final << prev
-
- #
- # Process results
- #
- sig = ""
-
- final.each do |f|
- sum = 0
- f[2].each {|i| sum += i }
- avg = (sum == 0) ? 0 : sum / f[2].length
- sig << "#{f[0].to_s.upcase[0,1]},#{f[1]},#{avg} "
- end
-
- # Return the results
- return sig
- end
-
- def to_freq(opts={})
-
- if(not @@kissfft_loaded)
- raise RuntimeError, "The KissFFT module is not availab…
- end
-
- freq_cnt = opts[:frequency_count] || 20
-
- # Perform a DFT on the samples
- ffts = KissFFT.fftr(8192, 8000, 1, self.samples)
-
- self.class.fft_to_freq_sig(ffts, freq_cnt)
- end
-
- def to_freq_sig(opts={})
- fcnt = opts[:frequency_count] || 5
-
- ffts = []
-
- # Obtain 20 DFTs for the sample, at 1/20th second offsets into…
- 0.upto(19) do |i|
- ffts[i] = KissFFT.fftr(8192, 8000, 1, self.samples[ i …
- end
-
- # Create a frequency table at 100hz boundaries
- f = [ *(0.step(4000, 100)) ]
-
- # Create a worker method to find the closest frequency
- barker = Proc.new do |t|
- t = t.to_i
- f.sort { |a,b|
- (a-t).abs <=> (b-t).abs
- }.first
- end
-
- # Purge any empty fft slices
- ffts.delete(nil)
-
- # Map each slice of the audio's FFT with each FFT chunk (8k sa…
- tops = ffts.map{|x| x.map{|y| y.map{|z|
-
- frq,pwr = z
-
- # Toss any signals with a strength under 100
- if pwr < 100.0
- frq,pwr = [0,0]
- # Map the signal to the closest offset of 100hz
- else
- frq = barker.call(frq)
- end
-
- # Make sure the strength is an integer
- pwr = pwr.to_i
-
- # Sort by signal strength and take the top fcnt items
- [frq, pwr]}.sort{|a,b|
- b[1] <=> a[1]
- }[0, fcnt].map{|w|
- # Grab just the frequency (drop the strength)
- w[0]
- # Remove any duplicates due to hz mapping
- }.uniq
-
- } }
-
- # Track the generated 4-second chunk signatures
- sigs = []
-
- # Expand the list of top frequencies per sample into a flat li…
- tops.each do |t|
- next if t.length < 4
- 0.upto(t.length - 4) { |i| t[i].each { |a| t[i+1].each…
- end
-
- # Dump any duplicate signatures
- sigs = sigs.uniq
-
- # Convert each signature into a single 32-bit integer
- # This is essentially [0-40, 0-40, 0-40, 0-40]
- sigs.map{|x| x.map{|y| y / 100}.pack("C4").unpack("N")[0] }
- end
-
- # Converts a signature to a postgresql integer array (text) format
- def to_freq_sig_txt(opts={})
- "{" + to_freq_sig(opts).sort.join(",") + "}"
- end
-
- def to_freq_sig_arr(opts={})
- to_freq_sig(opts)
- end
-
- def self.fft_to_freq_sig(ffts, freq_cnt)
- sig = []
- ffts.each do |s|
- res = []
- maxp = 0
- maxf = 0
- s.each do |f|
- if( f[1] > maxp )
- maxf,maxp = f
- end
-
- if(maxf > 0 and f[1] < maxp and (maxf + 4.5 < …
- res << [maxf, maxp]
- maxf,maxp = [0,0]
- end
- end
-
- sig << res.sort{ |a,b| # s…
- a[1] <=> b[1]
- }.reverse[0,freq_cnt].sort { |a,b| # t…
- a[0] <=> b[0]
- }.map {|a| [a[0].round, a[1].round ] } # r…
- end
-
- sig
- end
-
- # Find pattern inside of sample
- def self.compare_freq_sig(pat, zam, opts)
-
- fuzz_f = opts[:fuzz_f] || 7
- fuzz_p = opts[:fuzz_p] || 10
- final = []
-
- 0.upto(zam.length - 1) do |si|
- res = []
- sam = zam[si, zam.length]
-
- 0.upto(pat.length - 1) do |pi|
- diff = []
- next if not pat[pi]
- next if pat[pi].length == 0
- pat[pi].each do |x|
- next if not sam[pi]
- next if sam[pi].length == 0
- sam[pi].each do |y|
- if(
- (x[0] - fuzz_f) < y[0]…
- (x[0] + fuzz_f) > y[0]…
- (x[1] - fuzz_p) < y[1]…
- (x[1] + fuzz_p) > y[1]
- )
- diff << x
- break
- end
- end
- end
- res << diff
- end
- next if res.length == 0
-
- prev = 0
- rsum = 0
- ridx = 0
- res.each_index do |xi|
- len = res[xi].length
- if(xi == 0)
- rsum += (len < 2) ? -40 : +20
- else
- rsum += 20 if(prev > 11 and len > 11)
- rsum += len
- end
- prev = len
- end
-
- final << [ (rsum / res.length.to_f), res.map {|x| x.le…
- end
-
- final
- end
+ @@kissfft_loaded = false
+ begin
+ require 'kissfft'
+ @@kissfft_loaded = true
+ rescue ::LoadError
+ end
+
+ require 'zlib'
+
+ ##
+ # RAW AUDIO - 8khz little-endian 16-bit signed
+ ##
+
+ ##
+ # Static methods
+ ##
+
+ def self.from_str(str)
+ self.class.new(str)
+ end
+
+ def self.from_file(path)
+ if(not path)
+ raise Error, "No audio path specified"
+ end
+
+ if(path == "-")
+ return self.new($stdin.read)
+ end
+
+ if(not File.readable?(path))
+ raise Error, "The specified audio file does not exist"
+ end
+
+ if(path =~ /\.gz$/)
+ return self.new(Zlib::GzipReader.open(path).read)
+ end
+
+ self.new(File.read(path, File.size(path)))
+ end
+
+ ##
+ # Class methods
+ ##
+
+ attr_accessor :samples
+
+ def initialize(data)
+ self.samples = data.unpack('v*').map do |s|
+ (s > 0x7fff) ? (0x10000 - s) * -1 : s
+ end
+ end
+
+ def to_raw
+ self.samples.pack("v*")
+ end
+
+ def to_wav
+ raw = self.to_raw
+ wav =
+ "RIFF" +
+ [raw.length + 36].pack("V") +
+ "WAVE" +
+ "fmt " +
+ [16, 1, 1, 8000, 16000, 2, 16 ].pack("VvvVVvv") +
+ "data" +
+ [ raw.length ].pack("V") +
+ raw
+ end
+
+ def to_flow(opts={})
+
+ lo_lim = (opts[:lo_lim] || 100).to_i
+ lo_min = (opts[:lo_min] || 5).to_i
+ hi_min = (opts[:hi_min] || 5).to_i
+ lo_cnt = 0
+ hi_cnt = 0
+
+ data = self.samples.map {|c| c.abs}
+
+ #
+ # Granular hi/low state change list
+ #
+ fprint = []
+ state = :lo
+ idx = 0
+ buff = []
+
+ while (idx < data.length)
+ case state
+ when :lo
+ while(idx < data.length and data[idx] <= lo_lim)
+ buff << data[idx]
+ idx += 1
+ end
+
+ # Ignore any sequence that is too small
+ fprint << [:lo, buff.length, buff - [0]] if buff.length > lo_min
+ state = :hi
+ buff = []
+ next
+ when :hi
+ while(idx < data.length and data[idx] > lo_lim)
+ buff << data[idx]
+ idx += 1
+ end
+
+ # Ignore any sequence that is too small
+ fprint << [:hi, buff.length, buff] if buff.length > hi_min
+ state = :lo
+ buff = []
+ next
+ end
+ end
+
+ #
+ # Merge similar blocks
+ #
+ final = []
+ prev = fprint[0]
+ idx = 1
+
+ while(idx < fprint.length)
+
+ if(fprint[idx][0] == prev[0])
+ prev[1] += fprint[idx][1]
+ prev[2] += fprint[idx][2]
+ else
+ final << prev
+ prev = fprint[idx]
+ end
+
+ idx += 1
+ end
+ final << prev
+
+ #
+ # Process results
+ #
+ sig = ""
+
+ final.each do |f|
+ sum = 0
+ f[2].each {|i| sum += i }
+ avg = (sum == 0) ? 0 : sum / f[2].length
+ sig << "#{f[0].to_s.upcase[0,1]},#{f[1]},#{avg} "
+ end
+
+ # Return the results
+ return sig
+ end
+
+ def to_freq(opts={})
+
+ if(not @@kissfft_loaded)
+ raise RuntimeError, "The KissFFT module is not availabale, raw.to_freq()…
+ end
+
+ freq_cnt = opts[:frequency_count] || 20
+
+ # Perform a DFT on the samples
+ ffts = KissFFT.fftr(8192, 8000, 1, self.samples)
+
+ self.class.fft_to_freq_sig(ffts, freq_cnt)
+ end
+
+ def to_freq_sig(opts={})
+ fcnt = opts[:frequency_count] || 5
+
+ ffts = []
+
+ # Obtain 20 DFTs for the sample, at 1/20th second offsets into the stream
+ 0.upto(19) do |i|
+ ffts[i] = KissFFT.fftr(8192, 8000, 1, self.samples[ i * 400, self.sample…
+ end
+
+ # Create a frequency table at 100hz boundaries
+ f = [ *(0.step(4000, 100)) ]
+
+ # Create a worker method to find the closest frequency
+ barker = Proc.new do |t|
+ t = t.to_i
+ f.sort { |a,b|
+ (a-t).abs <=> (b-t).abs
+ }.first
+ end
+
+ # Purge any empty fft slices
+ ffts.delete(nil)
+
+ # Map each slice of the audio's FFT with each FFT chunk (8k samples) and t…
+ tops = ffts.map{|x| x.map{|y| y.map{|z|
+
+ frq,pwr = z
+
+ # Toss any signals with a strength under 100
+ if pwr < 100.0
+ frq,pwr = [0,0]
+ # Map the signal to the closest offset of 100hz
+ else
+ frq = barker.call(frq)
+ end
+
+ # Make sure the strength is an integer
+ pwr = pwr.to_i
+
+ # Sort by signal strength and take the top fcnt items
+ [frq, pwr]}.sort{|a,b|
+ b[1] <=> a[1]
+ }[0, fcnt].map{|w|
+ # Grab just the frequency (drop the strength)
+ w[0]
+ # Remove any duplicates due to hz mapping
+ }.uniq
+
+ } }
+
+ # Track the generated 4-second chunk signatures
+ sigs = []
+
+ # Expand the list of top frequencies per sample into a flat list of each p…
+ tops.each do |t|
+ next if t.length < 4
+ 0.upto(t.length - 4) { |i| t[i].each { |a| t[i+1].each { |b| t[i+2].each…
+ end
+
+ # Dump any duplicate signatures
+ sigs = sigs.uniq
+
+ # Convert each signature into a single 32-bit integer
+ # This is essentially [0-40, 0-40, 0-40, 0-40]
+ sigs.map{|x| x.map{|y| y / 100}.pack("C4").unpack("N")[0] }
+ end
+
+ # Converts a signature to a postgresql integer array (text) format
+ def to_freq_sig_txt(opts={})
+ "{" + to_freq_sig(opts).sort.join(",") + "}"
+ end
+
+ def to_freq_sig_arr(opts={})
+ to_freq_sig(opts)
+ end
+
+ def self.fft_to_freq_sig(ffts, freq_cnt)
+ sig = []
+ ffts.each do |s|
+ res = []
+ maxp = 0
+ maxf = 0
+ s.each do |f|
+ if( f[1] > maxp )
+ maxf,maxp = f
+ end
+
+ if(maxf > 0 and f[1] < maxp and (maxf + 4.5 < f[0]))
+ res << [maxf, maxp]
+ maxf,maxp = [0,0]
+ end
+ end
+
+ sig << res.sort{ |a,b| # sort by signal stre…
+ a[1] <=> b[1]
+ }.reverse[0,freq_cnt].sort { |a,b| # take the top 20 and…
+ a[0] <=> b[0]
+ }.map {|a| [a[0].round, a[1].round ] } # round to whole numb…
+ end
+
+ sig
+ end
+
+ # Find pattern inside of sample
+ def self.compare_freq_sig(pat, zam, opts)
+
+ fuzz_f = opts[:fuzz_f] || 7
+ fuzz_p = opts[:fuzz_p] || 10
+ final = []
+
+ 0.upto(zam.length - 1) do |si|
+ res = []
+ sam = zam[si, zam.length]
+
+ 0.upto(pat.length - 1) do |pi|
+ diff = []
+ next if not pat[pi]
+ next if pat[pi].length == 0
+ pat[pi].each do |x|
+ next if not sam[pi]
+ next if sam[pi].length == 0
+ sam[pi].each do |y|
+ if(
+ (x[0] - fuzz_f) < y[0] and
+ (x[0] + fuzz_f) > y[0] and
+ (x[1] - fuzz_p) < y[1] and
+ (x[1] + fuzz_p) > y[1]
+ )
+ diff << x
+ break
+ end
+ end
+ end
+ res << diff
+ end
+ next if res.length == 0
+
+ prev = 0
+ rsum = 0
+ ridx = 0
+ res.each_index do |xi|
+ len = res[xi].length
+ if(xi == 0)
+ rsum += (len < 2) ? -40 : +20
+ else
+ rsum += 20 if(prev > 11 and len > 11)
+ rsum += len
+ end
+ prev = len
+ end
+
+ final << [ (rsum / res.length.to_f), res.map {|x| x.length}]
+ end
+
+ final
+ end
end
diff --git a/lib/warvox/config.rb b/lib/warvox/config.rb
@@ -1,160 +1,160 @@
module WarVOX
module Config
- require 'yaml'
-
- def self.authentication_creds
- user = nil
- pass = nil
- info = YAML.load_file(WarVOX::Conf)
- if( info and
- info['authentication'] and
- info['authentication']['user'] and
- info['authentication']['pass']
- )
- user = info['authentication']['user']
- pass = info['authentication']['pass']
- end
- [user,pass]
- end
-
- def self.authenticate(user,pass)
- wuser,wpass = authentication_creds
- (wuser == user and wpass == pass) ? true : false
- end
-
- def self.tool_path(name)
- info = YAML.load_file(WarVOX::Conf)
- return nil if not info
- return nil if not info['tools']
- return nil if not info['tools'][name]
- find_full_path(
- info['tools'][name].gsub('%BASE%', WarVOX::Base)
- )
- end
-
- def self.analysis_threads
- core_count = File.read("/proc/cpuinfo").scan(/^processor\s+:/)…
-
- info = YAML.load_file(WarVOX::Conf)
- return core_count if not info
- return core_count if not info['analysis_threads']
- return core_count if info['analysis_threads'] == 0
- [ info['analysis_threads'].to_i, core_count ].min
- end
-
- def self.blacklist_path
- info = YAML.load_file(WarVOX::Conf)
- return nil if not info
- return nil if not info['blacklist']
- File.expand_path(info['blacklist'].gsub('%BASE%', WarVOX::Base…
- end
-
- def self.blacklist_load
- path = blacklist_path
- return if not path
- data = File.read(path, File.size(path))
- sigs = []
-
- File.open(path, 'r') do |fd|
- lno = 0
- fd.each_line do |line|
- lno += 1
- next if line =~ /^#/
- next if line =~ /^\s+$/
- line.strip!
- sigs << [lno, line]
- end
- sigs
- end
-
- end
-
- def self.signatures_path
- info = YAML.load_file(WarVOX::Conf)
- return nil if not info
- return nil if not info['signatures']
- File.expand_path(info['signatures'].gsub('%BASE%', WarVOX::Bas…
- end
-
- def self.classifiers_path
- info = YAML.load_file(WarVOX::Conf)
- return nil if not info
- return nil if not info['classifiers']
- File.expand_path(info['classifiers'].gsub('%BASE%', WarVOX::Ba…
- end
-
- def self.log_file
- STDOUT
- end
-
- def self.log_level
- Logger::DEBUG
- end
-
- def self.classifiers_load
- path = classifiers_path
- sigs = []
- return sigs if not path
-
- Dir.new(path).entries.sort{ |a,b|
- a.to_i <=> b.to_i
- }.map{ |ent|
- File.join(path, ent)
- }.each do |ent|
- sigs << ent if File.file?(ent)
- end
-
- sigs
- end
-
- # This method searches the PATH environment variable for
- # a fully qualified path to the supplied file name.
- # Stolen from Rex
- def self.find_full_path(file_name)
-
- # Return absolute paths unmodified
- if(file_name[0,1] == ::File::SEPARATOR)
- return file_name
- end
-
- path = ENV['PATH']
- if (path)
- path.split(::File::PATH_SEPARATOR).each { |base|
- begin
- path = base + ::File::SEPARATOR + file…
- if (::File::Stat.new(path))
- return path
- end
- rescue
- end
- }
- end
- return nil
- end
-
- # This method prevents two installations of WarVOX from using the same
- # rails session key. The first time this method is called, it generates
- # a new key and stores it in the rails directory, afterwards this key
- # will be used every time.
- def self.load_session_key
- kfile = File.join(WarVOX::Base, 'config', 'session.key')
- if(not File.exists?(kfile))
- # XXX: assume /dev/urandom exists
- kdata = File.read('/dev/urandom', 64).unpack("H*")[0]
-
- # Create the new session key file
- fd = File.new(kfile, 'w')
-
- # Make this file mode 0600
- File.chmod(0600, kfile)
-
- # Write it and close
- fd.write(kdata)
- fd.close
- return kdata
- end
- File.read(kfile)
- end
+ require 'yaml'
+
+ def self.authentication_creds
+ user = nil
+ pass = nil
+ info = YAML.load_file(WarVOX::Conf)
+ if( info and
+ info['authentication'] and
+ info['authentication']['user'] and
+ info['authentication']['pass']
+ )
+ user = info['authentication']['user']
+ pass = info['authentication']['pass']
+ end
+ [user,pass]
+ end
+
+ def self.authenticate(user,pass)
+ wuser,wpass = authentication_creds
+ (wuser == user and wpass == pass) ? true : false
+ end
+
+ def self.tool_path(name)
+ info = YAML.load_file(WarVOX::Conf)
+ return nil if not info
+ return nil if not info['tools']
+ return nil if not info['tools'][name]
+ find_full_path(
+ info['tools'][name].gsub('%BASE%', WarVOX::Base)
+ )
+ end
+
+ def self.analysis_threads
+ core_count = File.read("/proc/cpuinfo").scan(/^processor\s+:/).length resc…
+
+ info = YAML.load_file(WarVOX::Conf)
+ return core_count if not info
+ return core_count if not info['analysis_threads']
+ return core_count if info['analysis_threads'] == 0
+ [ info['analysis_threads'].to_i, core_count ].min
+ end
+
+ def self.blacklist_path
+ info = YAML.load_file(WarVOX::Conf)
+ return nil if not info
+ return nil if not info['blacklist']
+ File.expand_path(info['blacklist'].gsub('%BASE%', WarVOX::Base))
+ end
+
+ def self.blacklist_load
+ path = blacklist_path
+ return if not path
+ data = File.read(path, File.size(path))
+ sigs = []
+
+ File.open(path, 'r') do |fd|
+ lno = 0
+ fd.each_line do |line|
+ lno += 1
+ next if line =~ /^#/
+ next if line =~ /^\s+$/
+ line.strip!
+ sigs << [lno, line]
+ end
+ sigs
+ end
+
+ end
+
+ def self.signatures_path
+ info = YAML.load_file(WarVOX::Conf)
+ return nil if not info
+ return nil if not info['signatures']
+ File.expand_path(info['signatures'].gsub('%BASE%', WarVOX::Base))
+ end
+
+ def self.classifiers_path
+ info = YAML.load_file(WarVOX::Conf)
+ return nil if not info
+ return nil if not info['classifiers']
+ File.expand_path(info['classifiers'].gsub('%BASE%', WarVOX::Base))
+ end
+
+ def self.log_file
+ STDOUT
+ end
+
+ def self.log_level
+ Logger::DEBUG
+ end
+
+ def self.classifiers_load
+ path = classifiers_path
+ sigs = []
+ return sigs if not path
+
+ Dir.new(path).entries.sort{ |a,b|
+ a.to_i <=> b.to_i
+ }.map{ |ent|
+ File.join(path, ent)
+ }.each do |ent|
+ sigs << ent if File.file?(ent)
+ end
+
+ sigs
+ end
+
+ # This method searches the PATH environment variable for
+ # a fully qualified path to the supplied file name.
+ # Stolen from Rex
+ def self.find_full_path(file_name)
+
+ # Return absolute paths unmodified
+ if(file_name[0,1] == ::File::SEPARATOR)
+ return file_name
+ end
+
+ path = ENV['PATH']
+ if (path)
+ path.split(::File::PATH_SEPARATOR).each { |base|
+ begin
+ path = base + ::File::SEPARATOR + file_name
+ if (::File::Stat.new(path))
+ return path
+ end
+ rescue
+ end
+ }
+ end
+ return nil
+ end
+
+ # This method prevents two installations of WarVOX from using the same
+ # rails session key. The first time this method is called, it generates
+ # a new key and stores it in the rails directory, afterwards this key
+ # will be used every time.
+ def self.load_session_key
+ kfile = File.join(WarVOX::Base, 'config', 'session.key')
+ if(not File.exists?(kfile))
+ # XXX: assume /dev/urandom exists
+ kdata = File.read('/dev/urandom', 64).unpack("H*")[0]
+
+ # Create the new session key file
+ fd = File.new(kfile, 'w')
+
+ # Make this file mode 0600
+ File.chmod(0600, kfile)
+
+ # Write it and close
+ fd.write(kdata)
+ fd.close
+ return kdata
+ end
+ File.read(kfile)
+ end
end
diff --git a/lib/warvox/jobs.rb b/lib/warvox/jobs.rb
@@ -1,75 +1,75 @@
module WarVOX
class JobQueue
- attr_accessor :active_job, :active_thread, :queue, :queue_thread
+ attr_accessor :active_job, :active_thread, :queue, :queue_thread
- require "thread"
+ require "thread"
- def initialize
- @mutex = ::Mutex.new
- @queue = []
- @queue_thread = Thread.new{ manage_queue }
+ def initialize
+ @mutex = ::Mutex.new
+ @queue = []
+ @queue_thread = Thread.new{ manage_queue }
- super
- end
+ super
+ end
- def scheduled?(klass, job_id)
- @mutex.synchronize do
- [@active_job, *(@queue)].each do |c|
- next if not c
- return true if (c.class == klass and c.name ==…
- end
- end
- false
- end
+ def scheduled?(klass, job_id)
+ @mutex.synchronize do
+ [@active_job, *(@queue)].each do |c|
+ next if not c
+ return true if (c.class == klass and c.name == job_id)
+ end
+ end
+ false
+ end
- def schedule(klass, job_id)
- begin
- return false if scheduled?(klass, job_id)
- @queue.push(klass.new(job_id))
- rescue ::Exception => e
- $stderr.puts "ERROR!!!!!: #{e} #{e.backtrace}"
- false
- end
- end
+ def schedule(klass, job_id)
+ begin
+ return false if scheduled?(klass, job_id)
+ @queue.push(klass.new(job_id))
+ rescue ::Exception => e
+ $stderr.puts "ERROR!!!!!: #{e} #{e.backtrace}"
+ false
+ end
+ end
- def stop(job_id)
- @mutex.synchronize do
- [@active_job, *(@queue)].each do |c|
- next if not c
- if c.name == job_id
- # Actively running
- if @active_job == c
+ def stop(job_id)
+ @mutex.synchronize do
+ [@active_job, *(@queue)].each do |c|
+ next if not c
+ if c.name == job_id
+ # Actively running
+ if @active_job == c
- else
+ else
- end
- end
- end
- end
- end
+ end
+ end
+ end
+ end
+ end
- def manage_queue
- begin
- while(true)
- @mutex.synchronize do
- if(@active_job and @active_job.status == 'comp…
- @active_job = nil
- @active_thread = nil
- end
+ def manage_queue
+ begin
+ while(true)
+ @mutex.synchronize do
+ if(@active_job and @active_job.status == 'completed')
+ @active_job = nil
+ @active_thread = nil
+ end
- if(not @active_job and @queue.length > 0)
- @active_job = @queue.shift
- @active_thread = Thread.new { @active_…
- end
- end
+ if(not @active_job and @queue.length > 0)
+ @active_job = @queue.shift
+ @active_thread = Thread.new { @active_job.start }
+ end
+ end
- Kernel.select(nil, nil, nil, 1)
- end
- rescue ::Exception
- $stderr.puts "QUEUE MANAGER:#{$!.class} #{$!}"
- $stderr.flush
- end
- end
+ Kernel.select(nil, nil, nil, 1)
+ end
+ rescue ::Exception
+ $stderr.puts "QUEUE MANAGER:#{$!.class} #{$!}"
+ $stderr.flush
+ end
+ end
end
end
diff --git a/lib/warvox/jobs/analysis.rb b/lib/warvox/jobs/analysis.rb
@@ -2,420 +2,420 @@ module WarVOX
module Jobs
class Analysis < Base
- require 'fileutils'
- require 'tempfile'
- require 'open3'
-
- # This is required by the verify_install.rb script, so dont error
- # out if the gem is not yet available
- begin
- require 'kissfft'
- rescue ::LoadError
- end
-
- class Classifier
-
- class Completed < RuntimeError
- end
-
- attr_accessor :line_type
- attr_accessor :signatures
- attr_accessor :data
-
- def initialize
- @signatures = []
- @data = {}
- end
-
- def proc(str)
- begin
- eval(str)
- rescue Completed
- end
- end
- end
-
- def type
- 'analysis'
- end
-
- def initialize(job_id, conf)
- @job_id = job_id
- @conf = conf
- @tasks = []
- @calls = []
- end
-
- def stop
- @calls = []
- @tasks.each do |t|
- t.kill rescue nil
- end
- @tasks = []
- end
-
- def start
-
- @calls = []
-
- query = nil
-
- ::ActiveRecord::Base.connection_pool.with_connection {
-
- begin
-
- job = Job.find(@job_id)
- if not job
- raise RuntimeError, "The parent job no longer exists"
- end
-
- case @conf[:scope]
- when 'calls'
- if @conf[:force]
- query = {:id => @conf[:target_ids], :answered …
- else
- query = {:id => @conf[:target_ids], :answered …
- end
- when 'job'
- if @conf[:force]
- query = {:job_id => @conf[:target_id], :answer…
- else
- query = {:job_id => @conf[:target_id], :answer…
- end
- when 'project'
- if @conf[:force]
- query = {:project_id => @conf[:target_id], :an…
- else
- query = {:project_id => @conf[:target_id], :an…
- end
- when 'global'
- if @conf[:force]
- query = {:answered => true, :busy => false}
- else
- query = {:answered => true, :busy => false, :a…
- end
- else
- # Bail if we don't have a valid scope
- return
- end
-
- # Build a list of call IDs, as find_each() gets confused if th…
- calls = Call.where(query).map{|c| c.id }
-
- @total_calls = calls.length
- @completed_calls = 0
-
- max_threads = WarVOX::Config.analysis_threads
- last_update = Time.now
-
- while(calls.length > 0)
- if @tasks.length < max_threads
- @tasks << Thread.new(calls.shift, job.id) { |c…
- else
- clear_stale_tasks
-
- # Update progress every 10 seconds or so
- if Time.now.to_f - last_update.to_f > 10
- update_progress((@completed_calls / @t…
- last_update = Time.now
- end
-
- clear_zombies
- end
- end
-
- @tasks.map {|t| t.join }
- clear_stale_tasks
- clear_zombies
-
- rescue ::Exception => e
- WarVOX::Log.error("Exception: #{e.class} #{e} #{e.back…
- end
-
- }
- end
-
- def clear_stale_tasks
- @tasks = @tasks.select{ |x| x.status }
- IO.select(nil, nil, nil, 0.25)
- end
-
- def update_progress(pct)
- ::ActiveRecord::Base.connection_pool.with_connection {
- Job.where(id: @job_id).update_all(progress: pct)
- }
- end
-
- def run_analyze_call(cid, jid)
-
- dr = Call.includes(:job).where(id: cid).first
- dr.analysis_started_at = Time.now
- dr.analysis_job_id = jid
- dr.save!
-
- WarVOX::Log.debug("Worker processing audio for #{dr.number}...…
-
- bin = File.join(WarVOX::Base, 'bin', 'analyze_result.rb')
- tmp = Tempfile.new("Analysis")
- begin
-
- mr = dr.media
- ::File.open(tmp.path, "wb") do |fd|
- fd.write(mr.audio)
- end
-
- pfd = IO.popen("nice #{bin} '#{tmp.path}' '#{ dr.number.gsub(/…
- out = Marshal.load(pfd.read) rescue nil
- pfd.close
-
- return if not out
-
- mf = dr.media_fields
- out.each_key do |k|
- if mf.include?(k.to_s)
- mr[k] = out[k]
- else
- dr[k] = out[k]
- end
- end
-
- dr.analysis_completed_at = Time.now
-
- rescue ::Interrupt
- ensure
- tmp.close
- tmp.unlink
- end
-
- mr.save
- dr.save
-
- @completed_calls += 1
- end
-
- # Takes the raw file path as an argument, returns a hash
- def self.analyze_call(input, num=nil)
-
- return if not input
- return if not File.exist?(input)
-
- bname = File.expand_path(File.dirname(input))
- num ||= File.basename(input)
- res = {}
-
- #
- # Create the signature database
- #
- raw = WarVOX::Audio::Raw.from_file(input)
- fft = KissFFT.fftr(8192, 8000, 1, raw.samples) || []
-
- freq = raw.to_freq_sig_arr()
-
- # Save the signature data
- res[:fprint] = freq
-
- #
- # Create a raw decompressed file
- #
-
- # Decompress the audio file
- rawfile = Tempfile.new("rawfile")
- datfile = Tempfile.new("datfile")
-
- # Data files for audio processing and signal graph
- cnt = 0
- rawfile.write(raw.samples.pack('v*'))
- datfile.write(raw.samples.map{|val| cnt +=1; "#{cnt/8000.0} #{…
- rawfile.flush
- datfile.flush
-
- # Data files for spectrum plotting
- frefile = Tempfile.new("frefile")
-
- # Calculate the peak frequencies for the sample
- maxf = 0
- maxp = 0
- tones = {}
- fft.each do |x|
- rank = x.sort{|a,b| a[1].to_i <=> b[1].to_i }.reverse
- rank[0..10].each do |t|
- f = t[0].round
- p = t[1].round
- next if f == 0
- next if p < 1
- tones[ f ] ||= []
- tones[ f ] << t
- if(t[1] > maxp)
- maxf = t[0]
- maxp = t[1]
- end
- end
- end
-
- # Save the peak frequency
- res[:peak_freq] = maxf
-
- # Calculate average frequency and peaks over time
- avg = {}
- pks = []
- pkz = []
- fft.each do |slot|
- pks << slot.sort{|a,b| a[1] <=> b[1] }.reverse[0]
- pkz << slot.sort{|a,b| a[1] <=> b[1] }.reverse[0..9]
- slot.each do |f|
- avg[ f[0] ] ||= 0
- avg[ f[0] ] += f[1]
- end
- end
-
- # Save the peak frequencies over time
- res[:peak_freq_data] = pks.map{|f| "#{f[0]}-#{f[1]}" }.join(" …
-
- # Generate the frequency file
- avg.keys.sort.each do |k|
- avg[k] = avg[k] / fft.length
- frefile.write("#{k} #{avg[k]}\n")
- end
- frefile.flush
-
- # Count significant frequencies across the sample
- fcnt = {}
- 0.step(4000, 5) {|f| fcnt[f] = 0 }
- pkz.each do |fb|
- fb.each do |f|
- fdx = ((f[0] / 5.0).round * 5.0).to_i
- fcnt[fdx] += 0.1
- end
- end
-
- #
- # Classifier processing
- #
-
- sproc = Classifier.new
- sproc.data =
- {
- :raw => raw,
- :freq => freq,
- :fcnt => fcnt,
- :fft => fft,
- :pks => pks,
- :pkz => pkz,
- :maxf => maxf,
- :maxp => maxp
- }
-
- WarVOX::Config.classifiers_load.each do |sigfile|
- begin
- str = File.read(sigfile, File.size(sigfile))
- sproc.proc(str)
- rescue ::Exception => e
- $stderr.puts "DEBUG: Caught exception in #{sig…
- end
- break if sproc.line_type
- end
-
- # Save the guessed line type
- res[:line_type] = sproc.line_type
-
- png_big = Tempfile.new("big")
- png_big_dots = Tempfile.new("bigdots")
- png_big_freq = Tempfile.new("bigfreq")
- png_sig = Tempfile.new("signal")
- png_sig_freq = Tempfile.new("sigfreq")
-
- # Plot samples to a graph
- plotter = Tempfile.new("gnuplot")
-
-
- plotter.puts("set autoscale")
- plotter.puts("set yrange [-15000:15000]")
- plotter.puts("set ylabel \"Signal\"")
- plotter.puts("set xlabel \"Seconds\"")
- plotter.puts("set terminal png medium size 640,480 transparent…
- plotter.puts("set output \"#{png_big.path}\"")
- plotter.puts("plot \"#{datfile.path}\" using 1:2 title \"#{num…
- plotter.puts("set output \"#{png_big_dots.path}\"")
- plotter.puts("plot \"#{datfile.path}\" using 1:2 title \"#{num…
-
-
- plotter.puts("unset yrange")
- plotter.puts("set autoscale")
- plotter.puts("set xrange [0:4000]")
- plotter.puts("set terminal png medium size 640,480 transparent…
- plotter.puts("set ylabel \"Power\"")
- plotter.puts("set xlabel \"Frequency\"")
- plotter.puts("set output \"#{png_big_freq.path}\"")
- plotter.puts("plot \"#{frefile.path}\" using 1:2 title \"#{num…
-
-
- plotter.puts("unset xrange")
- plotter.puts("set autoscale")
- plotter.puts("set yrange [-15000:15000]")
- plotter.puts("unset border")
- plotter.puts("unset xtics")
- plotter.puts("unset ytics")
- plotter.puts("set ylabel \"\"")
- plotter.puts("set xlabel \"\"")
- plotter.puts("set terminal png small size 80,60 transparent")
- plotter.puts("set format x ''")
- plotter.puts("set format y ''")
- plotter.puts("set output \"#{png_sig.path}\"")
- plotter.puts("plot \"#{datfile.path}\" using 1:2 notitle with …
-
- plotter.puts("unset yrange")
- plotter.puts("set autoscale")
- plotter.puts("set xrange [0:4000]")
- plotter.puts("unset border")
- plotter.puts("unset xtics")
- plotter.puts("unset ytics")
- plotter.puts("set ylabel \"\"")
- plotter.puts("set xlabel \"\"")
- plotter.puts("set terminal png small size 80,60 transparent")
- plotter.puts("set format x ''")
- plotter.puts("set format y ''")
- plotter.puts("set output \"#{png_sig_freq.path}\"")
- plotter.puts("plot \"#{frefile.path}\" using 1:2 notitle with …
- plotter.flush
-
- system("#{WarVOX::Config.tool_path('gnuplot')} #{plotter.path}…
- File.unlink(plotter.path)
- File.unlink(datfile.path)
- File.unlink(frefile.path)
- plotter.close
- datfile.close
- frefile.path
-
- ::File.open(png_big.path, 'rb') { |fd| res[:png_big] …
- ::File.open(png_big_dots.path, 'rb') { |fd| res[:png_big_dots]…
- ::File.open(png_big_freq.path, 'rb') { |fd| res[:png_big_freq]…
- ::File.open(png_sig.path, 'rb') { |fd| res[:png_sig] …
- ::File.open(png_sig_freq.path, 'rb') { |fd| res[:png_sig_freq]…
-
- [png_big, png_big_dots, png_big_freq, png_sig, png_sig_freq ].…
-
- tmp_wav = Tempfile.new("wav")
- tmp_mp3 = Tempfile.new("mp3")
-
- # Generate a WAV file from raw linear PCM
- ::File.open(tmp_wav.path, "wb") do |fd|
- fd.write(raw.to_wav)
- end
-
- # Default samples at 8k, bump it to 32k to get better quality
- system("#{WarVOX::Config.tool_path('lame')} -b 32 #{tmp_wav.pa…
-
- File.unlink(rawfile.path)
- rawfile.close
-
- ::File.open(tmp_mp3.path, "rb") { |fd| res[:mp3] = fd.read }
-
- [tmp_wav, tmp_mp3].map {|x| x.unlink; x.close }
-
- clear_zombies()
-
- res
- end
+ require 'fileutils'
+ require 'tempfile'
+ require 'open3'
+
+ # This is required by the verify_install.rb script, so dont error
+ # out if the gem is not yet available
+ begin
+ require 'kissfft'
+ rescue ::LoadError
+ end
+
+ class Classifier
+
+ class Completed < RuntimeError
+ end
+
+ attr_accessor :line_type
+ attr_accessor :signatures
+ attr_accessor :data
+
+ def initialize
+ @signatures = []
+ @data = {}
+ end
+
+ def proc(str)
+ begin
+ eval(str)
+ rescue Completed
+ end
+ end
+ end
+
+ def type
+ 'analysis'
+ end
+
+ def initialize(job_id, conf)
+ @job_id = job_id
+ @conf = conf
+ @tasks = []
+ @calls = []
+ end
+
+ def stop
+ @calls = []
+ @tasks.each do |t|
+ t.kill rescue nil
+ end
+ @tasks = []
+ end
+
+ def start
+
+ @calls = []
+
+ query = nil
+
+ ::ActiveRecord::Base.connection_pool.with_connection {
+
+ begin
+
+ job = Job.find(@job_id)
+ if not job
+ raise RuntimeError, "The parent job no longer exists"
+ end
+
+ case @conf[:scope]
+ when 'calls'
+ if @conf[:force]
+ query = {:id => @conf[:target_ids], :answered => true, :busy => false}
+ else
+ query = {:id => @conf[:target_ids], :answered => true, :busy => false,…
+ end
+ when 'job'
+ if @conf[:force]
+ query = {:job_id => @conf[:target_id], :answered => true, :busy => fal…
+ else
+ query = {:job_id => @conf[:target_id], :answered => true, :busy => fal…
+ end
+ when 'project'
+ if @conf[:force]
+ query = {:project_id => @conf[:target_id], :answered => true, :busy =>…
+ else
+ query = {:project_id => @conf[:target_id], :answered => true, :busy =>…
+ end
+ when 'global'
+ if @conf[:force]
+ query = {:answered => true, :busy => false}
+ else
+ query = {:answered => true, :busy => false, :analysis_started_at => ni…
+ end
+ else
+ # Bail if we don't have a valid scope
+ return
+ end
+
+ # Build a list of call IDs, as find_each() gets confused if the DB changes…
+ calls = Call.where(query).map{|c| c.id }
+
+ @total_calls = calls.length
+ @completed_calls = 0
+
+ max_threads = WarVOX::Config.analysis_threads
+ last_update = Time.now
+
+ while(calls.length > 0)
+ if @tasks.length < max_threads
+ @tasks << Thread.new(calls.shift, job.id) { |c,j| ::ActiveRecord::Base…
+ else
+ clear_stale_tasks
+
+ # Update progress every 10 seconds or so
+ if Time.now.to_f - last_update.to_f > 10
+ update_progress((@completed_calls / @total_calls.to_f) * 100)
+ last_update = Time.now
+ end
+
+ clear_zombies
+ end
+ end
+
+ @tasks.map {|t| t.join }
+ clear_stale_tasks
+ clear_zombies
+
+ rescue ::Exception => e
+ WarVOX::Log.error("Exception: #{e.class} #{e} #{e.backtrace}")
+ end
+
+ }
+ end
+
+ def clear_stale_tasks
+ @tasks = @tasks.select{ |x| x.status }
+ IO.select(nil, nil, nil, 0.25)
+ end
+
+ def update_progress(pct)
+ ::ActiveRecord::Base.connection_pool.with_connection {
+ Job.where(id: @job_id).update_all(progress: pct)
+ }
+ end
+
+ def run_analyze_call(cid, jid)
+
+ dr = Call.includes(:job).where(id: cid).first
+ dr.analysis_started_at = Time.now
+ dr.analysis_job_id = jid
+ dr.save!
+
+ WarVOX::Log.debug("Worker processing audio for #{dr.number}...")
+
+ bin = File.join(WarVOX::Base, 'bin', 'analyze_result.rb')
+ tmp = Tempfile.new("Analysis")
+ begin
+
+ mr = dr.media
+ ::File.open(tmp.path, "wb") do |fd|
+ fd.write(mr.audio)
+ end
+
+ pfd = IO.popen("nice #{bin} '#{tmp.path}' '#{ dr.number.gsub(/[^0-9a-zA-Z\…
+ out = Marshal.load(pfd.read) rescue nil
+ pfd.close
+
+ return if not out
+
+ mf = dr.media_fields
+ out.each_key do |k|
+ if mf.include?(k.to_s)
+ mr[k] = out[k]
+ else
+ dr[k] = out[k]
+ end
+ end
+
+ dr.analysis_completed_at = Time.now
+
+ rescue ::Interrupt
+ ensure
+ tmp.close
+ tmp.unlink
+ end
+
+ mr.save
+ dr.save
+
+ @completed_calls += 1
+ end
+
+ # Takes the raw file path as an argument, returns a hash
+ def self.analyze_call(input, num=nil)
+
+ return if not input
+ return if not File.exist?(input)
+
+ bname = File.expand_path(File.dirname(input))
+ num ||= File.basename(input)
+ res = {}
+
+ #
+ # Create the signature database
+ #
+ raw = WarVOX::Audio::Raw.from_file(input)
+ fft = KissFFT.fftr(8192, 8000, 1, raw.samples) || []
+
+ freq = raw.to_freq_sig_arr()
+
+ # Save the signature data
+ res[:fprint] = freq
+
+ #
+ # Create a raw decompressed file
+ #
+
+ # Decompress the audio file
+ rawfile = Tempfile.new("rawfile")
+ datfile = Tempfile.new("datfile")
+
+ # Data files for audio processing and signal graph
+ cnt = 0
+ rawfile.write(raw.samples.pack('v*'))
+ datfile.write(raw.samples.map{|val| cnt +=1; "#{cnt/8000.0} #{val}"}.join(…
+ rawfile.flush
+ datfile.flush
+
+ # Data files for spectrum plotting
+ frefile = Tempfile.new("frefile")
+
+ # Calculate the peak frequencies for the sample
+ maxf = 0
+ maxp = 0
+ tones = {}
+ fft.each do |x|
+ rank = x.sort{|a,b| a[1].to_i <=> b[1].to_i }.reverse
+ rank[0..10].each do |t|
+ f = t[0].round
+ p = t[1].round
+ next if f == 0
+ next if p < 1
+ tones[ f ] ||= []
+ tones[ f ] << t
+ if(t[1] > maxp)
+ maxf = t[0]
+ maxp = t[1]
+ end
+ end
+ end
+
+ # Save the peak frequency
+ res[:peak_freq] = maxf
+
+ # Calculate average frequency and peaks over time
+ avg = {}
+ pks = []
+ pkz = []
+ fft.each do |slot|
+ pks << slot.sort{|a,b| a[1] <=> b[1] }.reverse[0]
+ pkz << slot.sort{|a,b| a[1] <=> b[1] }.reverse[0..9]
+ slot.each do |f|
+ avg[ f[0] ] ||= 0
+ avg[ f[0] ] += f[1]
+ end
+ end
+
+ # Save the peak frequencies over time
+ res[:peak_freq_data] = pks.map{|f| "#{f[0]}-#{f[1]}" }.join(" ")
+
+ # Generate the frequency file
+ avg.keys.sort.each do |k|
+ avg[k] = avg[k] / fft.length
+ frefile.write("#{k} #{avg[k]}\n")
+ end
+ frefile.flush
+
+ # Count significant frequencies across the sample
+ fcnt = {}
+ 0.step(4000, 5) {|f| fcnt[f] = 0 }
+ pkz.each do |fb|
+ fb.each do |f|
+ fdx = ((f[0] / 5.0).round * 5.0).to_i
+ fcnt[fdx] += 0.1
+ end
+ end
+
+ #
+ # Classifier processing
+ #
+
+ sproc = Classifier.new
+ sproc.data =
+ {
+ :raw => raw,
+ :freq => freq,
+ :fcnt => fcnt,
+ :fft => fft,
+ :pks => pks,
+ :pkz => pkz,
+ :maxf => maxf,
+ :maxp => maxp
+ }
+
+ WarVOX::Config.classifiers_load.each do |sigfile|
+ begin
+ str = File.read(sigfile, File.size(sigfile))
+ sproc.proc(str)
+ rescue ::Exception => e
+ $stderr.puts "DEBUG: Caught exception in #{sigfile}: #{e} #{e.backtrac…
+ end
+ break if sproc.line_type
+ end
+
+ # Save the guessed line type
+ res[:line_type] = sproc.line_type
+
+ png_big = Tempfile.new("big")
+ png_big_dots = Tempfile.new("bigdots")
+ png_big_freq = Tempfile.new("bigfreq")
+ png_sig = Tempfile.new("signal")
+ png_sig_freq = Tempfile.new("sigfreq")
+
+ # Plot samples to a graph
+ plotter = Tempfile.new("gnuplot")
+
+
+ plotter.puts("set autoscale")
+ plotter.puts("set yrange [-15000:15000]")
+ plotter.puts("set ylabel \"Signal\"")
+ plotter.puts("set xlabel \"Seconds\"")
+ plotter.puts("set terminal png medium size 640,480 transparent")
+ plotter.puts("set output \"#{png_big.path}\"")
+ plotter.puts("plot \"#{datfile.path}\" using 1:2 title \"#{num}\" with lin…
+ plotter.puts("set output \"#{png_big_dots.path}\"")
+ plotter.puts("plot \"#{datfile.path}\" using 1:2 title \"#{num}\" with dot…
+
+
+ plotter.puts("unset yrange")
+ plotter.puts("set autoscale")
+ plotter.puts("set xrange [0:4000]")
+ plotter.puts("set terminal png medium size 640,480 transparent")
+ plotter.puts("set ylabel \"Power\"")
+ plotter.puts("set xlabel \"Frequency\"")
+ plotter.puts("set output \"#{png_big_freq.path}\"")
+ plotter.puts("plot \"#{frefile.path}\" using 1:2 title \"#{num} - Peak #{m…
+
+
+ plotter.puts("unset xrange")
+ plotter.puts("set autoscale")
+ plotter.puts("set yrange [-15000:15000]")
+ plotter.puts("unset border")
+ plotter.puts("unset xtics")
+ plotter.puts("unset ytics")
+ plotter.puts("set ylabel \"\"")
+ plotter.puts("set xlabel \"\"")
+ plotter.puts("set terminal png small size 80,60 transparent")
+ plotter.puts("set format x ''")
+ plotter.puts("set format y ''")
+ plotter.puts("set output \"#{png_sig.path}\"")
+ plotter.puts("plot \"#{datfile.path}\" using 1:2 notitle with lines")
+
+ plotter.puts("unset yrange")
+ plotter.puts("set autoscale")
+ plotter.puts("set xrange [0:4000]")
+ plotter.puts("unset border")
+ plotter.puts("unset xtics")
+ plotter.puts("unset ytics")
+ plotter.puts("set ylabel \"\"")
+ plotter.puts("set xlabel \"\"")
+ plotter.puts("set terminal png small size 80,60 transparent")
+ plotter.puts("set format x ''")
+ plotter.puts("set format y ''")
+ plotter.puts("set output \"#{png_sig_freq.path}\"")
+ plotter.puts("plot \"#{frefile.path}\" using 1:2 notitle with lines")
+ plotter.flush
+
+ system("#{WarVOX::Config.tool_path('gnuplot')} #{plotter.path}")
+ File.unlink(plotter.path)
+ File.unlink(datfile.path)
+ File.unlink(frefile.path)
+ plotter.close
+ datfile.close
+ frefile.path
+
+ ::File.open(png_big.path, 'rb') { |fd| res[:png_big] = fd.read }
+ ::File.open(png_big_dots.path, 'rb') { |fd| res[:png_big_dots] = fd.read }
+ ::File.open(png_big_freq.path, 'rb') { |fd| res[:png_big_freq] = fd.read }
+ ::File.open(png_sig.path, 'rb') { |fd| res[:png_sig] = fd.read }
+ ::File.open(png_sig_freq.path, 'rb') { |fd| res[:png_sig_freq] = fd.read }
+
+ [png_big, png_big_dots, png_big_freq, png_sig, png_sig_freq ].map {|x| x.u…
+
+ tmp_wav = Tempfile.new("wav")
+ tmp_mp3 = Tempfile.new("mp3")
+
+ # Generate a WAV file from raw linear PCM
+ ::File.open(tmp_wav.path, "wb") do |fd|
+ fd.write(raw.to_wav)
+ end
+
+ # Default samples at 8k, bump it to 32k to get better quality
+ system("#{WarVOX::Config.tool_path('lame')} -b 32 #{tmp_wav.path} #{tmp_mp…
+
+ File.unlink(rawfile.path)
+ rawfile.close
+
+ ::File.open(tmp_mp3.path, "rb") { |fd| res[:mp3] = fd.read }
+
+ [tmp_wav, tmp_mp3].map {|x| x.unlink; x.close }
+
+ clear_zombies()
+
+ res
+ end
end
diff --git a/lib/warvox/jobs/base.rb b/lib/warvox/jobs/base.rb
@@ -1,38 +1,38 @@
module WarVOX
module Jobs
class Base
- attr_accessor :name, :status
+ attr_accessor :name, :status
- def type
- 'base'
- end
+ def type
+ 'base'
+ end
- def stop
- @status = 'active'
- end
+ def stop
+ @status = 'active'
+ end
- def start
- @status = 'completed'
- end
+ def start
+ @status = 'completed'
+ end
- def db_save(obj)
- max_tries = 100
- cur_tries = 0
- obj.save!
- end
+ def db_save(obj)
+ max_tries = 100
+ cur_tries = 0
+ obj.save!
+ end
- def clear_zombies
- self.class.clear_zombies
- end
+ def clear_zombies
+ self.class.clear_zombies
+ end
- def self.clear_zombies
- begin
- # Clear zombies just in case...
- while(Process.waitpid(-1, Process::WNOHANG))
- end
- rescue ::Exception
- end
- end
+ def self.clear_zombies
+ begin
+ # Clear zombies just in case...
+ while(Process.waitpid(-1, Process::WNOHANG))
+ end
+ rescue ::Exception
+ end
+ end
end
end
end
diff --git a/lib/warvox/jobs/dialer.rb b/lib/warvox/jobs/dialer.rb
@@ -2,225 +2,225 @@ module WarVOX
module Jobs
class Dialer < Base
- require 'fileutils'
-
- def type
- 'dialer'
- end
-
- def initialize(job_id, conf)
- @job_id = job_id
- @conf = conf
- @range = @conf[:range]
- @seconds = @conf[:seconds]
- @lines = @conf[:lines]
- @nums = shuffle_a(WarVOX::Phone.crack_mask(@range))
-
- @tasks = []
- @provs = get_providers
-
- # CallerID modes (SELF or a mask)
- @cid_self = @conf[:cid_mask] == 'SELF'
- if(not @cid_self)
- @cid_range = WarVOX::Phone.crack_mask(@conf[:cid_mask])
- end
- end
-
- #
- # Performs a Fisher-Yates shuffle on an array
- #
- def shuffle_a(arr)
- len = arr.length
- max = len - 1
- cyc = [* (0..max) ]
- for d in cyc
- e = rand(d+1)
- next if e == d
- f = arr[d];
- g = arr[e];
- arr[d] = g;
- arr[e] = f;
- end
- return arr
- end
-
- def get_providers
- res = []
-
- ::ActiveRecord::Base.connection_pool.with_connection {
- ::Provider.where(:enabled => true).all.each do |prov|
- info = {
- :name => prov.name,
- :id => prov.id,
- :port => prov.port,
- :host => prov.host,
- :user => prov.user,
- :pass => prov.pass,
- :lines => prov.lines
- }
- 1.upto(prov.lines) {|i| res.push(info) }
- end
- }
-
- shuffle_a(res)
- end
-
-
- def stop
- @nums = []
- @tasks.each do |t|
- t.kill rescue nil
- end
- @tasks = []
- end
-
- def start
- # Scrub all numbers matching the blacklist
- list = WarVOX::Config.blacklist_load
- list.each do |b|
- lno,reg = b
- @nums.each do |num|
- if(num =~ /#{reg}/)
- $stderr.puts "DEBUG: Skipping #{num} d…
- @nums.delete(num)
- end
- end
- end
-
- last_update = Time.now
- @nums_total = @nums.length
-
- max_tasks = [@provs.length, @lines].min
-
- while(@nums.length > 0)
- while( @tasks.length < max_tasks ) do
- tnum = @nums.shift
- break unless tnum
-
- tprov = allocate_provider
-
- @tasks << Thread.new(tnum,tprov) do |num,prov|
-
- out_fd = Tempfile.new("rawfile")
- out = out_fd.path
-
- begin
- # Execute and read the output
- busy = 0
- ring = 0
- fail = 1
- byte = 0
- path = ''
- cid = @cid_self ? num : @cid_range[ r…
-
- IO.popen(
- [
- WarVOX::Config.tool_pa…
- "-s",
- prov[:host],
- "-u",
- prov[:user],
- "-p",
- prov[:pass],
- "-c",
- cid,
- "-o",
- out,
- "-n",
- num,
- "-l",
- @seconds
- ].map{|i|
- "'" + i.to_s.gsub("'",…
- }.join(" ")).each_line do |line|
- $stderr.puts "DEBUG: #{line.st…
- if(line =~ /^COMPLETED/)
- line.split(/\s+/).map{…
- busy = info[1]…
- fail = info[1]…
- ring = info[1]…
- byte = info[1]…
- path = info[1]…
- end
- end
- end
-
- ::ActiveRecord::Base.connection_pool.w…
- job = Job.find(@job_id)
- if not job
- raise RuntimeError, "T…
- end
-
- res = ::Call.new
- res.number = num
- res.job_id = job.id
- res.project_id = job.projec…
- res.provider_id = prov[:id]
- res.answered = (fail == 0…
- res.busy = (busy == 1…
- res.audio_length = (byte / 160…
- res.ring_length = ring
- res.caller_id = cid
-
- res.save
-
- if(File.exists?(out))
- File.open(out, "rb") d…
- med = res.media
- med.audio = fd…
- med.save
- end
- end
-
- out_fd.close
- ::FileUtils.rm_f(out)
- end
-
- rescue ::Exception => e
- $stderr.puts "ERROR: #{e.class…
- end
- end
-
- # END NEW THREAD
- end
- # END SPAWN THREADS
-
- clear_stale_tasks
-
- # Update progress every 10 seconds or so
- if Time.now.to_f - last_update.to_f > 10
- update_progress(((@nums_total - @nums.length) …
- last_update = Time.now.to_f
- end
-
- clear_zombies()
- end
-
- while @tasks.length > 0
- clear_stale_tasks
- end
-
- # ALL DONE
- end
-
- def clear_stale_tasks
- # Remove dead threads from the task list
- @tasks = @tasks.select{ |x| x.status }
- IO.select(nil, nil, nil, 0.25)
- end
-
- def update_progress(pct)
- ::ActiveRecord::Base.connection_pool.with_connection {
- Job.where(id: @job_id).update_all(progress: pct)
- }
- end
-
- def allocate_provider
- @prov_idx ||= 0
- prov = @provs[ @prov_idx % @provs.length ]
- @prov_idx += 1
- prov
- end
+ require 'fileutils'
+
+ def type
+ 'dialer'
+ end
+
+ def initialize(job_id, conf)
+ @job_id = job_id
+ @conf = conf
+ @range = @conf[:range]
+ @seconds = @conf[:seconds]
+ @lines = @conf[:lines]
+ @nums = shuffle_a(WarVOX::Phone.crack_mask(@range))
+
+ @tasks = []
+ @provs = get_providers
+
+ # CallerID modes (SELF or a mask)
+ @cid_self = @conf[:cid_mask] == 'SELF'
+ if(not @cid_self)
+ @cid_range = WarVOX::Phone.crack_mask(@conf[:cid_mask])
+ end
+ end
+
+ #
+ # Performs a Fisher-Yates shuffle on an array
+ #
+ def shuffle_a(arr)
+ len = arr.length
+ max = len - 1
+ cyc = [* (0..max) ]
+ for d in cyc
+ e = rand(d+1)
+ next if e == d
+ f = arr[d];
+ g = arr[e];
+ arr[d] = g;
+ arr[e] = f;
+ end
+ return arr
+ end
+
+ def get_providers
+ res = []
+
+ ::ActiveRecord::Base.connection_pool.with_connection {
+ ::Provider.where(:enabled => true).all.each do |prov|
+ info = {
+ :name => prov.name,
+ :id => prov.id,
+ :port => prov.port,
+ :host => prov.host,
+ :user => prov.user,
+ :pass => prov.pass,
+ :lines => prov.lines
+ }
+ 1.upto(prov.lines) {|i| res.push(info) }
+ end
+ }
+
+ shuffle_a(res)
+ end
+
+
+ def stop
+ @nums = []
+ @tasks.each do |t|
+ t.kill rescue nil
+ end
+ @tasks = []
+ end
+
+ def start
+ # Scrub all numbers matching the blacklist
+ list = WarVOX::Config.blacklist_load
+ list.each do |b|
+ lno,reg = b
+ @nums.each do |num|
+ if(num =~ /#{reg}/)
+ $stderr.puts "DEBUG: Skipping #{num} due to blacklist (line: #{lno})"
+ @nums.delete(num)
+ end
+ end
+ end
+
+ last_update = Time.now
+ @nums_total = @nums.length
+
+ max_tasks = [@provs.length, @lines].min
+
+ while(@nums.length > 0)
+ while( @tasks.length < max_tasks ) do
+ tnum = @nums.shift
+ break unless tnum
+
+ tprov = allocate_provider
+
+ @tasks << Thread.new(tnum,tprov) do |num,prov|
+
+ out_fd = Tempfile.new("rawfile")
+ out = out_fd.path
+
+ begin
+ # Execute and read the output
+ busy = 0
+ ring = 0
+ fail = 1
+ byte = 0
+ path = ''
+ cid = @cid_self ? num : @cid_range[ rand(@cid_range.length) ]
+
+ IO.popen(
+ [
+ WarVOX::Config.tool_path('iaxrecord'),
+ "-s",
+ prov[:host],
+ "-u",
+ prov[:user],
+ "-p",
+ prov[:pass],
+ "-c",
+ cid,
+ "-o",
+ out,
+ "-n",
+ num,
+ "-l",
+ @seconds
+ ].map{|i|
+ "'" + i.to_s.gsub("'",'') +"'"
+ }.join(" ")).each_line do |line|
+ $stderr.puts "DEBUG: #{line.strip}"
+ if(line =~ /^COMPLETED/)
+ line.split(/\s+/).map{|b| b.split('=', 2) }.each do |info|
+ busy = info[1].to_i if info[0] == 'BUSY'
+ fail = info[1].to_i if info[0] == 'FAIL'
+ ring = info[1].to_i if info[0] == 'RINGTIME'
+ byte = info[1].to_i if info[0] == 'BYTES'
+ path = info[1] if info[0] == 'FILE'
+ end
+ end
+ end
+
+ ::ActiveRecord::Base.connection_pool.with_connection do
+ job = Job.find(@job_id)
+ if not job
+ raise RuntimeError, "The parent job is not available"
+ end
+
+ res = ::Call.new
+ res.number = num
+ res.job_id = job.id
+ res.project_id = job.project_id
+ res.provider_id = prov[:id]
+ res.answered = (fail == 0) ? true : false
+ res.busy = (busy == 1) ? true : false
+ res.audio_length = (byte / 16000) # 8khz @ 16-bit
+ res.ring_length = ring
+ res.caller_id = cid
+
+ res.save
+
+ if(File.exists?(out))
+ File.open(out, "rb") do |fd|
+ med = res.media
+ med.audio = fd.read(fd.stat.size)
+ med.save
+ end
+ end
+
+ out_fd.close
+ ::FileUtils.rm_f(out)
+ end
+
+ rescue ::Exception => e
+ $stderr.puts "ERROR: #{e.class} #{e} #{e.backtrace} #{num} #{prov.…
+ end
+ end
+
+ # END NEW THREAD
+ end
+ # END SPAWN THREADS
+
+ clear_stale_tasks
+
+ # Update progress every 10 seconds or so
+ if Time.now.to_f - last_update.to_f > 10
+ update_progress(((@nums_total - @nums.length) / @nums_total.to_f) * 10…
+ last_update = Time.now.to_f
+ end
+
+ clear_zombies()
+ end
+
+ while @tasks.length > 0
+ clear_stale_tasks
+ end
+
+ # ALL DONE
+ end
+
+ def clear_stale_tasks
+ # Remove dead threads from the task list
+ @tasks = @tasks.select{ |x| x.status }
+ IO.select(nil, nil, nil, 0.25)
+ end
+
+ def update_progress(pct)
+ ::ActiveRecord::Base.connection_pool.with_connection {
+ Job.where(id: @job_id).update_all(progress: pct)
+ }
+ end
+
+ def allocate_provider
+ @prov_idx ||= 0
+ prov = @provs[ @prov_idx % @provs.length ]
+ @prov_idx += 1
+ prov
+ end
end
end
diff --git a/lib/warvox/phone.rb b/lib/warvox/phone.rb
@@ -1,58 +1,58 @@
module WarVOX
class Phone
- # Convert 123456XXXX to an array of expanded numbers
- def self.crack_mask(mask)
- masks = mask.split(/[\s,]+/) || [ ]
- masks.delete(nil)
- self.crack_masks(masks)
- end
-
- def self.crack_masks(masks)
- res = {}
- masks.each do |mask|
- mask = mask.strip
-
- if(mask.index(':'))
- next if mask.index('X')
+ # Convert 123456XXXX to an array of expanded numbers
+ def self.crack_mask(mask)
+ masks = mask.split(/[\s,]+/) || [ ]
+ masks.delete(nil)
+ self.crack_masks(masks)
+ end
+
+ def self.crack_masks(masks)
+ res = {}
+ masks.each do |mask|
+ mask = mask.strip
+
+ if(mask.index(':'))
+ next if mask.index('X')
- # Quick hack to fix leading 0s
- prefix = ""
- if mask =~ /^(0+)/
- prefix = $1
+ # Quick hack to fix leading 0s
+ prefix = ""
+ if mask =~ /^(0+)/
+ prefix = $1
end
- rbeg,rend = mask.split(':').map{|c| c.gsub(/[^…
- rbeg.upto(rend) do |n|
- res[prefix + n.to_s] = {}
- end
- next
- end
-
- incdigits = 0
- mask.each_char do |c|
- incdigits += 1 if c =~ /^[X#]$/i
- end
-
- max = (10**incdigits)-1
-
- (0..max).each do |num|
- number = mask.dup # copy the mask
- numstr = sprintf("%0#{incdigits}d", num) # str…
- j = 0 # index for numstr
- for i in 0..number.length-1 do # step through …
- if number[i].chr =~ /^[X#]$/i
- number[i] = numstr[j] # replac…
- j += 1
- end
- end
- res[number] = {}
- end
-
- end
+ rbeg,rend = mask.split(':').map{|c| c.gsub(/[^\d]/, '').to_i }
+ rbeg.upto(rend) do |n|
+ res[prefix + n.to_s] = {}
+ end
+ next
+ end
+
+ incdigits = 0
+ mask.each_char do |c|
+ incdigits += 1 if c =~ /^[X#]$/i
+ end
+
+ max = (10**incdigits)-1
+
+ (0..max).each do |num|
+ number = mask.dup # copy the mask
+ numstr = sprintf("%0#{incdigits}d", num) # stringify our incrementing …
+ j = 0 # index for numstr
+ for i in 0..number.length-1 do # step through the number (mask)
+ if number[i].chr =~ /^[X#]$/i
+ number[i] = numstr[j] # replaced masked indexes with digits from i…
+ j += 1
+ end
+ end
+ res[number] = {}
+ end
+
+ end
- return res.keys.sort
- end
+ return res.keys.sort
+ end
end
end
diff --git a/lib/warvox/proto/iax2/client.rb b/lib/warvox/proto/iax2/client.rb
@@ -162,27 +162,27 @@ class Client
end
def send_ack(call)
- data = [ IAX_SUBTYPE_ACK ].pack('C')
+ data = [ IAX_SUBTYPE_ACK ].pack('C')
send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.…
end
def send_pong(call, stamp)
- data = [ IAX_SUBTYPE_PONG ].pack('C')
+ data = [ IAX_SUBTYPE_PONG ].pack('C')
send_data( call, create_pkt( call.scall, call.dcall, stamp, call.oseq, cal…
end
def send_lagrp(call, stamp)
- data = [ IAX_SUBTYPE_LAGRP ].pack('C')
+ data = [ IAX_SUBTYPE_LAGRP ].pack('C')
send_data( call, create_pkt( call.scall, call.dcall, stamp, call.oseq, cal…
end
def send_invalid(call)
- data = [ IAX_SUBTYPE_INVAL ].pack('C')
+ data = [ IAX_SUBTYPE_INVAL ].pack('C')
send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.…
end
def send_hangup(call)
- data = [ IAX_SUBTYPE_HANGUP ].pack('C')
+ data = [ IAX_SUBTYPE_HANGUP ].pack('C')
send_data( call, create_pkt( call.scall, call.dcall, call.timestamp, call.…
end
diff --git a/spec/factories/call_media.rb b/spec/factories/call_media.rb
@@ -15,9 +15,9 @@
#
FactoryGirl.define do
- factory :call_medium do
- call
- project
- end
+ factory :call_medium do
+ call
+ project
+ end
end
diff --git a/spec/factories/calls.rb b/spec/factories/calls.rb
@@ -25,11 +25,11 @@
#
FactoryGirl.define do
- factory :call do
- project
- job
- provider
- number { Faker::PhoneNumber.phone_number }
- end
+ factory :call do
+ project
+ job
+ provider
+ number { Faker::PhoneNumber.phone_number }
+ end
end
diff --git a/spec/factories/jobs.rb b/spec/factories/jobs.rb
@@ -19,16 +19,16 @@
#
FactoryGirl.define do
- factory :job do
- project
- task 'dialer'
- args "\x04\b{\t:\nrangeI\"\x0F7632458942\x06:\x06ET:\nlinesi\x…
- status 'submitted'
- error nil
- range { Faker::PhoneNumber.phone_number }
- cid_mask { Faker::PhoneNumber.phone_number }
- seconds { Faker::Number.between(1, 299) }
- lines { Faker::Number.between(1, 10000) }
- end
+ factory :job do
+ project
+ task 'dialer'
+ args "\x04\b{\t:\nrangeI\"\x0F7632458942\x06:\x06ET:\nlinesi\x0F:\fseconds…
+ status 'submitted'
+ error nil
+ range { Faker::PhoneNumber.phone_number }
+ cid_mask { Faker::PhoneNumber.phone_number }
+ seconds { Faker::Number.between(1, 299) }
+ lines { Faker::Number.between(1, 10000) }
+ end
end
diff --git a/spec/factories/lines.rb b/spec/factories/lines.rb
@@ -12,9 +12,9 @@
#
FactoryGirl.define do
- factory :line do
- project
- number { Faker::PhoneNumber.phone_number }
- end
+ factory :line do
+ project
+ number { Faker::PhoneNumber.phone_number }
+ end
end
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
@@ -13,9 +13,9 @@
#
FactoryGirl.define do
- factory :project do
- name { Faker::Lorem.sentence }
- description { Faker::Lorem.sentence }
- end
+ factory :project do
+ name { Faker::Lorem.sentence }
+ description { Faker::Lorem.sentence }
+ end
end
diff --git a/spec/factories/providers.rb b/spec/factories/providers.rb
@@ -15,14 +15,14 @@
#
FactoryGirl.define do
- factory :provider do
- name { Faker::Company.name }
- host { Faker::Internet.ip_v4_address }
- port { Faker::Number.between(1, 65535) }
- user { Faker::Internet.user_name }
- pass { Faker::Internet.password(10, 20) }
- lines { Faker::Number.between(1, 254) }
- enabled true
- end
+ factory :provider do
+ name { Faker::Company.name }
+ host { Faker::Internet.ip_v4_address }
+ port { Faker::Number.between(1, 65535) }
+ user { Faker::Internet.user_name }
+ pass { Faker::Internet.password(10, 20) }
+ lines { Faker::Number.between(1, 254) }
+ enabled true
+ end
end
diff --git a/spec/factories/settings.rb b/spec/factories/settings.rb
@@ -12,8 +12,8 @@
#
FactoryGirl.define do
- factory :setting, :class => 'Settings' do
- var "CachedStuff"
- end
+ factory :setting, :class => 'Settings' do
+ var "CachedStuff"
+ end
end
diff --git a/spec/factories/signature_fps.rb b/spec/factories/signature_fps.rb
@@ -1,6 +1,6 @@
FactoryGirl.define do
- factory :signature_fp do
-
- end
+ factory :signature_fp do
+
+ end
end
diff --git a/spec/factories/signatures.rb b/spec/factories/signatures.rb
@@ -14,13 +14,13 @@
#
FactoryGirl.define do
- factory :signature do
- name { Faker::Commerce.product_name }
- source { Faker::PhoneNumber.cell_phone }
- description { Faker::Lorem.sentence }
- category { Faker::Lorem.word }
- line_type { Faker::Lorem.word }
- risk { Faker::Lorem.word }
- end
+ factory :signature do
+ name { Faker::Commerce.product_name }
+ source { Faker::PhoneNumber.cell_phone }
+ description { Faker::Lorem.sentence }
+ category { Faker::Lorem.word }
+ line_type { Faker::Lorem.word }
+ risk { Faker::Lorem.word }
+ end
end
diff --git a/spec/factories/users.rb b/spec/factories/users.rb
@@ -24,12 +24,12 @@
#
FactoryGirl.define do
- factory :user do
- login { Faker::Internet.user_name }
- password 'RandomPass'
- password_confirmation 'RandomPass'
- enabled true
- admin true
- end
+ factory :user do
+ login { Faker::Internet.user_name }
+ password 'RandomPass'
+ password_confirmation 'RandomPass'
+ enabled true
+ admin true
+ end
end
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
@@ -2,24 +2,24 @@ require 'rails_helper'
RSpec.feature "Projects", type: :feature do
- before(:each) do
- @user = create(:user)
- create_user_session(@user)
- end
+ before(:each) do
+ @user = create(:user)
+ create_user_session(@user)
+ end
- it "list all existing projects" do
- project = create(:project)
- visit projects_path
- expect(page).to have_content "WarVOX Projects"
- within "#projects-table" do
- expect(page).to have_content "Name"
- expect(page).to have_content "Description"
- expect(page).to have_content "Jobs"
- expect(page).to have_content "Calls"
- expect(page).to have_content "Analyzed"
- expect(page).to have_content "Created"
- expect(page).to have_content "Actions"
- expect(page).to have_content project.name
- end
- end
+ it "list all existing projects" do
+ project = create(:project)
+ visit projects_path
+ expect(page).to have_content "WarVOX Projects"
+ within "#projects-table" do
+ expect(page).to have_content "Name"
+ expect(page).to have_content "Description"
+ expect(page).to have_content "Jobs"
+ expect(page).to have_content "Calls"
+ expect(page).to have_content "Analyzed"
+ expect(page).to have_content "Created"
+ expect(page).to have_content "Actions"
+ expect(page).to have_content project.name
+ end
+ end
end
diff --git a/spec/features/visitor/logins_spec.rb b/spec/features/visitor/login…
@@ -1,58 +1,58 @@
require 'rails_helper'
RSpec.feature "Logins", type: :feature do
- it "login with valid credentials" do
- user = create(:user)
- visit login_path
- within "#new_user_session" do
- expect(page).to have_content "Username"
- expect(page).to have_content "Password"
- fill_in "user_session_login", with: user.login
- fill_in "user_session_password", with: 'RandomPass'
- click_button "Sign in"
- end
- within "div.content" do
- expect(page).to have_content "WarVOX Projects"
- end
- end
+ it "login with valid credentials" do
+ user = create(:user)
+ visit login_path
+ within "#new_user_session" do
+ expect(page).to have_content "Username"
+ expect(page).to have_content "Password"
+ fill_in "user_session_login", with: user.login
+ fill_in "user_session_password", with: 'RandomPass'
+ click_button "Sign in"
+ end
+ within "div.content" do
+ expect(page).to have_content "WarVOX Projects"
+ end
+ end
- it "failed login with invalid password valid username" do
- user = create(:user)
- visit login_path
- within "#new_user_session" do
- fill_in "user_session_login", with: user.login
- fill_in "user_session_password", with: 'WrongPassword'
- click_button "Sign in"
- end
- expect(page).to have_content "Password is not valid"
- end
+ it "failed login with invalid password valid username" do
+ user = create(:user)
+ visit login_path
+ within "#new_user_session" do
+ fill_in "user_session_login", with: user.login
+ fill_in "user_session_password", with: 'WrongPassword'
+ click_button "Sign in"
+ end
+ expect(page).to have_content "Password is not valid"
+ end
- it "failed login with invalid username valid password" do
- user = create(:user)
- visit login_path
- within "#new_user_session" do
- fill_in "user_session_login", with: user.login + "Wron…
- fill_in "user_session_password", with: 'RandomPass'
- click_button "Sign in"
- end
- expect(page).to have_content "Login is not valid"
- end
+ it "failed login with invalid username valid password" do
+ user = create(:user)
+ visit login_path
+ within "#new_user_session" do
+ fill_in "user_session_login", with: user.login + "Wrong"
+ fill_in "user_session_password", with: 'RandomPass'
+ click_button "Sign in"
+ end
+ expect(page).to have_content "Login is not valid"
+ end
- it "failed login with no input entered" do
- visit login_path
- within "#new_user_session" do
- click_button "Sign in"
- end
- expect(page).to have_content "You did not provide any details …
- end
+ it "failed login with no input entered" do
+ visit login_path
+ within "#new_user_session" do
+ click_button "Sign in"
+ end
+ expect(page).to have_content "You did not provide any details for authenti…
+ end
- it "failed login with no password entered" do
- user = create(:user)
- visit login_path
- within "#new_user_session" do
- fill_in "user_session_login", with: user.login
- click_button "Sign in"
- end
- expect(page).to have_content "Password cannot be blank"
- end
+ it "failed login with no password entered" do
+ user = create(:user)
+ visit login_path
+ within "#new_user_session" do
+ fill_in "user_session_login", with: user.login
+ click_button "Sign in"
+ end
+ expect(page).to have_content "Password cannot be blank"
+ end
end
diff --git a/spec/models/call_medium_spec.rb b/spec/models/call_medium_spec.rb
@@ -17,10 +17,10 @@
require 'rails_helper'
RSpec.describe CallMedium, type: :model do
- it { should belong_to(:call) }
- it { should belong_to(:project) }
+ it { should belong_to(:call) }
+ it { should belong_to(:project) }
- it "valid record" do
- expect(build(:call_medium)).to be_valid
- end
+ it "valid record" do
+ expect(build(:call_medium)).to be_valid
+ end
end
diff --git a/spec/models/call_spec.rb b/spec/models/call_spec.rb
@@ -27,12 +27,12 @@
require 'rails_helper'
RSpec.describe Call, type: :model do
- it { should belong_to(:project) }
- it { should belong_to(:provider) }
- it { should belong_to(:job) }
- it { should have_one(:call_medium).dependent(:delete) }
+ it { should belong_to(:project) }
+ it { should belong_to(:provider) }
+ it { should belong_to(:job) }
+ it { should have_one(:call_medium).dependent(:delete) }
- it "valid record" do
- expect(build(:call)).to be_valid
- end
+ it "valid record" do
+ expect(build(:call)).to be_valid
+ end
end
diff --git a/spec/models/job_spec.rb b/spec/models/job_spec.rb
@@ -21,12 +21,12 @@
require 'rails_helper'
RSpec.describe Job, type: :model do
- it { should belong_to(:project) }
- it { should have_many(:calls) }
+ it { should belong_to(:project) }
+ it { should have_many(:calls) }
- it { should validate_presence_of(:project_id) }
+ it { should validate_presence_of(:project_id) }
- it "valid record" do
- expect(build(:job)).to be_valid
- end
+ it "valid record" do
+ expect(build(:job)).to be_valid
+ end
end
diff --git a/spec/models/line_spec.rb b/spec/models/line_spec.rb
@@ -14,10 +14,10 @@
require 'rails_helper'
RSpec.describe Line, type: :model do
- it { should belong_to(:project) }
- it { should have_many(:line_attributes).dependent(:delete_all) }
+ it { should belong_to(:project) }
+ it { should have_many(:line_attributes).dependent(:delete_all) }
- it "valid record" do
- expect(build(:line)).to be_valid
- end
+ it "valid record" do
+ expect(build(:line)).to be_valid
+ end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
@@ -15,16 +15,16 @@
require 'rails_helper'
RSpec.describe Project, type: :model do
- it { should have_many(:lines).dependent(:delete_all) }
- it { should have_many(:line_attributes).dependent(:delete_all) }
- it { should have_many(:calls).dependent(:delete_all) }
- it { should have_many(:call_media).dependent(:delete_all) }
- it { should have_many(:jobs).dependent(:delete_all) }
+ it { should have_many(:lines).dependent(:delete_all) }
+ it { should have_many(:line_attributes).dependent(:delete_all) }
+ it { should have_many(:calls).dependent(:delete_all) }
+ it { should have_many(:call_media).dependent(:delete_all) }
+ it { should have_many(:jobs).dependent(:delete_all) }
- it { should validate_presence_of(:name) }
- it { should validate_uniqueness_of(:name) }
+ it { should validate_presence_of(:name) }
+ it { should validate_uniqueness_of(:name) }
- it "valid record" do
- expect(build(:project)).to be_valid
- end
+ it "valid record" do
+ expect(build(:project)).to be_valid
+ end
end
diff --git a/spec/models/provider_spec.rb b/spec/models/provider_spec.rb
@@ -17,20 +17,20 @@
require 'rails_helper'
RSpec.describe Provider, type: :model do
- ## TODO determine if association is unecessary
- # the DialResult model does not exist
- #it { should have_many(:dial_results) }
+ ## TODO determine if association is unecessary
+ # the DialResult model does not exist
+ #it { should have_many(:dial_results) }
- it { should validate_presence_of(:name) }
- it { should validate_presence_of(:host) }
- it { should validate_presence_of(:port) }
- it { should validate_presence_of(:user) }
- it { should validate_presence_of(:pass) }
- it { should validate_presence_of(:lines) }
- it { should validate_numericality_of(:port).is_less_than(65536).is_gre…
- it { should validate_numericality_of(:lines).is_less_than(255).is_grea…
+ it { should validate_presence_of(:name) }
+ it { should validate_presence_of(:host) }
+ it { should validate_presence_of(:port) }
+ it { should validate_presence_of(:user) }
+ it { should validate_presence_of(:pass) }
+ it { should validate_presence_of(:lines) }
+ it { should validate_numericality_of(:port).is_less_than(65536).is_greater_t…
+ it { should validate_numericality_of(:lines).is_less_than(255).is_greater_th…
- it "valid record" do
- expect(build(:provider)).to be_valid
- end
+ it "valid record" do
+ expect(build(:provider)).to be_valid
+ end
end
diff --git a/spec/models/settings_spec.rb b/spec/models/settings_spec.rb
@@ -14,7 +14,7 @@
require 'rails_helper'
RSpec.describe Settings, type: :model do
- it "valid record" do
- expect(build(:setting)).to be_valid
- end
+ it "valid record" do
+ expect(build(:setting)).to be_valid
+ end
end
diff --git a/spec/models/signature_spec.rb b/spec/models/signature_spec.rb
@@ -16,11 +16,11 @@
require 'rails_helper'
RSpec.describe Signature, type: :model do
- ## TODO association may not be needed
- # causes crash: PG::UndefinedTable: ERROR: relation "signature_fps" …
- #it { should have_many(:signature_fps) }
+ ## TODO association may not be needed
+ # causes crash: PG::UndefinedTable: ERROR: relation "signature_fps" does n…
+ #it { should have_many(:signature_fps) }
- it "valid record" do
- expect(build(:signature)).to be_valid
- end
+ it "valid record" do
+ expect(build(:signature)).to be_valid
+ end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
@@ -26,10 +26,10 @@
require 'rails_helper'
RSpec.describe User, type: :model do
- it { should validate_length_of(:password).is_at_least(8) }
- it { should validate_length_of(:password_confirmation).is_at_least(8) }
+ it { should validate_length_of(:password).is_at_least(8) }
+ it { should validate_length_of(:password_confirmation).is_at_least(8) }
- it 'valid record' do
- expect(build(:user)).to be_valid
- end
+ it 'valid record' do
+ expect(build(:user)).to be_valid
+ end
end
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
@@ -27,29 +27,29 @@ Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| req…
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
- # FactoryGirl Syntax
- config.include FactoryGirl::Syntax::Methods
+ # FactoryGirl Syntax
+ config.include FactoryGirl::Syntax::Methods
- # Remove this line if you're not using ActiveRecord or ActiveRecord fi…
- config.fixture_path = "#{::Rails.root}/spec/fixtures"
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
- # If you're not using ActiveRecord, or you'd prefer not to run each of…
- # examples within a transaction, remove the following line or assign f…
- # instead of true.
- config.use_transactional_fixtures = true
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
+ # examples within a transaction, remove the following line or assign false
+ # instead of true.
+ config.use_transactional_fixtures = true
- # RSpec Rails can automatically mix in different behaviours to your te…
- # based on their file location, for example enabling you to call `get`…
- # `post` in specs under `spec/controllers`.
- #
- # You can disable this behaviour by removing the line below, and inste…
- # explicitly tag your specs with their type, e.g.:
- #
- # RSpec.describe UsersController, :type => :controller do
- # # ...
- # end
- #
- # The different available types are documented in the features, such a…
- # https://relishapp.com/rspec/rspec-rails/docs
- config.infer_spec_type_from_file_location!
+ # RSpec Rails can automatically mix in different behaviours to your tests
+ # based on their file location, for example enabling you to call `get` and
+ # `post` in specs under `spec/controllers`.
+ #
+ # You can disable this behaviour by removing the line below, and instead
+ # explicitly tag your specs with their type, e.g.:
+ #
+ # RSpec.describe UsersController, :type => :controller do
+ # # ...
+ # end
+ #
+ # The different available types are documented in the features, such as in
+ # https://relishapp.com/rspec/rspec-rails/docs
+ config.infer_spec_type_from_file_location!
end
diff --git a/spec/support/auth_logic_helpers.rb b/spec/support/auth_logic_helpe…
@@ -1,20 +1,20 @@
module Authlogic
- module TestHelper
- def create_user_session(user)
- visit login_path
- within "#new_user_session" do
- expect(page).to have_content "Username"
- expect(page).to have_content "Password"
- fill_in "user_session_login", with: user.login
- fill_in "user_session_password", with: user.pa…
- click_button "Sign in"
- end
- end
- end
+ module TestHelper
+ def create_user_session(user)
+ visit login_path
+ within "#new_user_session" do
+ expect(page).to have_content "Username"
+ expect(page).to have_content "Password"
+ fill_in "user_session_login", with: user.login
+ fill_in "user_session_password", with: user.password
+ click_button "Sign in"
+ end
+ end
+ end
end
# Make this available to just the request and feature specs
RSpec.configure do |config|
- config.include Authlogic::TestHelper, type: :request
- config.include Authlogic::TestHelper, type: :feature
+ config.include Authlogic::TestHelper, type: :request
+ config.include Authlogic::TestHelper, type: :feature
end
\ No newline at end of file
You are viewing proxied material from jay.scot. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.