electric_slide 0.0.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/Gemfile +1 -1
- data/Guardfile +9 -0
- data/README.markdown +151 -1
- data/Rakefile +2 -3
- data/electric_slide.gemspec +6 -2
- data/lib/electric_slide.rb +45 -42
- data/lib/electric_slide/agent.rb +48 -0
- data/lib/electric_slide/agent_strategy/fixed_priority.rb +55 -0
- data/lib/electric_slide/agent_strategy/longest_idle.rb +39 -0
- data/lib/electric_slide/call_queue.rb +335 -0
- data/lib/electric_slide/plugin.rb +10 -0
- data/lib/electric_slide/version.rb +4 -0
- data/spec/electric_slide/agent_spec.rb +23 -0
- data/spec/electric_slide/agent_strategy/fixed_priority_spec.rb +43 -0
- data/spec/electric_slide/call_queue_spec.rb +42 -0
- data/spec/electric_slide_spec.rb +40 -0
- data/spec/spec_helper.rb +4 -11
- metadata +51 -34
- data/lib/electric_slide/queue_strategy.rb +0 -18
- data/lib/electric_slide/queued_call.rb +0 -24
- data/lib/electric_slide/round_robin.rb +0 -46
- data/lib/electric_slide/round_robin_meetme.rb +0 -34
- data/spec/electric_slide/queue_strategy_spec.rb +0 -16
- data/spec/electric_slide/queued_call_spec.rb +0 -42
- data/spec/electric_slide/round_robin_spec.rb +0 -87
data/spec/electric_slide_spec.rb
CHANGED
@@ -1 +1,41 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ElectricSlide do
|
4
|
+
context "creating a queue" do
|
5
|
+
after :each do
|
6
|
+
ElectricSlide.shutdown_queue :fake
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:queue_class) { double :fake_queue_class }
|
10
|
+
let(:queue_inst) { double :fake_queue_instance }
|
11
|
+
|
12
|
+
it "should default to an ElectricSlide::CallQueue if one is not specified" do
|
13
|
+
ElectricSlide.create :fake
|
14
|
+
expect { ElectricSlide.get_queue :fake }.to_not raise_error
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should start the queue upon registration" do
|
18
|
+
expect(queue_class).to receive(:work).once.and_return queue_inst
|
19
|
+
expect(queue_inst).to receive(:terminate).once
|
20
|
+
ElectricSlide.create :fake, queue_class
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should preserve additional queue arguments" do
|
24
|
+
queue = double(:fake_queue)
|
25
|
+
expect(queue_class).to receive(:work).with(:foo, :bar, :baz).once.and_return queue_inst
|
26
|
+
expect(queue_inst).to receive(:terminate).once
|
27
|
+
ElectricSlide.create :fake, queue_class, :foo, :bar, :baz
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should not allow a second queue to be created with the same name" do
|
31
|
+
ElectricSlide.create :fake
|
32
|
+
expect { ElectricSlide.create :fake }.to raise_error
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should raise if attempting to work with a queue that doesn't exist" do
|
37
|
+
expect { ElectricSlide.get_queue!("does not exist!") }.to raise_error
|
38
|
+
expect { ElectricSlide.shutdown_queue("does not exist!") }.to raise_error
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,25 +1,18 @@
|
|
1
1
|
$:.push File.join(File.dirname(__FILE__), '..', 'lib')
|
2
2
|
Thread.abort_on_exception = true
|
3
3
|
|
4
|
-
%w
|
4
|
+
%w(
|
5
5
|
adhearsion
|
6
6
|
electric_slide
|
7
|
-
electric_slide/queued_call
|
8
|
-
electric_slide/queue_strategy
|
9
|
-
electric_slide/round_robin
|
10
7
|
rspec/core
|
11
|
-
|
12
|
-
flexmock/rspec
|
13
|
-
}.each { |r| require r }
|
8
|
+
).each { |r| require r }
|
14
9
|
|
15
10
|
RSpec.configure do |config|
|
16
|
-
config.
|
17
|
-
config.filter_run :focus => true
|
11
|
+
config.filter_run focus: true
|
18
12
|
config.run_all_when_everything_filtered = true
|
19
|
-
config.color_enabled = true
|
20
13
|
end
|
21
14
|
|
22
15
|
def dummy_call
|
23
|
-
|
16
|
+
Adhearsion::Call.new
|
24
17
|
end
|
25
18
|
|
metadata
CHANGED
@@ -1,125 +1,139 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: electric_slide
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Klang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-07-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: adhearsion
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: countdownlatch
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: activesupport
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 2.5.0
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 2.5.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: ci_reporter
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 0
|
75
|
+
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0
|
82
|
+
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: guard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: guard-rspec
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
|
-
- -
|
101
|
+
- - ">="
|
88
102
|
- !ruby/object:Gem::Version
|
89
103
|
version: '0'
|
90
104
|
type: :development
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
|
-
- -
|
108
|
+
- - ">="
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: simplecov
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
|
-
- -
|
115
|
+
- - ">="
|
102
116
|
- !ruby/object:Gem::Version
|
103
117
|
version: '0'
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
|
-
- -
|
122
|
+
- - ">="
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: '0'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: simplecov-rcov
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
114
128
|
requirements:
|
115
|
-
- -
|
129
|
+
- - ">="
|
116
130
|
- !ruby/object:Gem::Version
|
117
131
|
version: '0'
|
118
132
|
type: :development
|
119
133
|
prerelease: false
|
120
134
|
version_requirements: !ruby/object:Gem::Requirement
|
121
135
|
requirements:
|
122
|
-
- -
|
136
|
+
- - ">="
|
123
137
|
- !ruby/object:Gem::Version
|
124
138
|
version: '0'
|
125
139
|
description: Automatic Call Distributor (ACD) for Adhearsion. Currently implements
|
@@ -129,21 +143,25 @@ executables: []
|
|
129
143
|
extensions: []
|
130
144
|
extra_rdoc_files: []
|
131
145
|
files:
|
132
|
-
- .gitignore
|
146
|
+
- ".gitignore"
|
147
|
+
- ".rspec"
|
133
148
|
- Gemfile
|
149
|
+
- Guardfile
|
134
150
|
- LICENSE
|
135
151
|
- README.markdown
|
136
152
|
- Rakefile
|
137
153
|
- config/ahn_acd.yml
|
138
154
|
- electric_slide.gemspec
|
139
155
|
- lib/electric_slide.rb
|
140
|
-
- lib/electric_slide/
|
141
|
-
- lib/electric_slide/
|
142
|
-
- lib/electric_slide/
|
143
|
-
- lib/electric_slide/
|
144
|
-
-
|
145
|
-
-
|
146
|
-
- spec/electric_slide/
|
156
|
+
- lib/electric_slide/agent.rb
|
157
|
+
- lib/electric_slide/agent_strategy/fixed_priority.rb
|
158
|
+
- lib/electric_slide/agent_strategy/longest_idle.rb
|
159
|
+
- lib/electric_slide/call_queue.rb
|
160
|
+
- lib/electric_slide/plugin.rb
|
161
|
+
- lib/electric_slide/version.rb
|
162
|
+
- spec/electric_slide/agent_spec.rb
|
163
|
+
- spec/electric_slide/agent_strategy/fixed_priority_spec.rb
|
164
|
+
- spec/electric_slide/call_queue_spec.rb
|
147
165
|
- spec/electric_slide_spec.rb
|
148
166
|
- spec/spec_helper.rb
|
149
167
|
homepage: http://github.com/adhearsion/electric_slide
|
@@ -155,19 +173,18 @@ require_paths:
|
|
155
173
|
- lib
|
156
174
|
required_ruby_version: !ruby/object:Gem::Requirement
|
157
175
|
requirements:
|
158
|
-
- -
|
176
|
+
- - ">="
|
159
177
|
- !ruby/object:Gem::Version
|
160
178
|
version: '0'
|
161
179
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
180
|
requirements:
|
163
|
-
- -
|
181
|
+
- - ">="
|
164
182
|
- !ruby/object:Gem::Version
|
165
183
|
version: '0'
|
166
184
|
requirements: []
|
167
185
|
rubyforge_project:
|
168
|
-
rubygems_version: 2.
|
186
|
+
rubygems_version: 2.4.5
|
169
187
|
signing_key:
|
170
188
|
specification_version: 2
|
171
189
|
summary: Automatic Call Distributor for Adhearsion
|
172
190
|
test_files: []
|
173
|
-
has_rdoc: true
|
@@ -1,18 +0,0 @@
|
|
1
|
-
class ElectricSlide
|
2
|
-
module QueueStrategy
|
3
|
-
def wrap_call(call)
|
4
|
-
call = QueuedCall.new(call) unless call.respond_to?(:queued_time)
|
5
|
-
call
|
6
|
-
end
|
7
|
-
|
8
|
-
def priority_enqueue(call)
|
9
|
-
# TODO: Add this call to the front of the line
|
10
|
-
enqueue call
|
11
|
-
end
|
12
|
-
|
13
|
-
def enqueue(call)
|
14
|
-
call.hold
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'countdownlatch'
|
2
|
-
|
3
|
-
class ElectricSlide
|
4
|
-
class QueuedCall
|
5
|
-
attr_accessor :call, :queued_time
|
6
|
-
|
7
|
-
def initialize(call)
|
8
|
-
@call = call
|
9
|
-
@queued_time = Time.now
|
10
|
-
end
|
11
|
-
|
12
|
-
def hold
|
13
|
-
call.execute 'StartMusicOnHold'
|
14
|
-
@latch = CountDownLatch.new 1
|
15
|
-
@latch.wait
|
16
|
-
call.execute 'StopMusicOnHold'
|
17
|
-
end
|
18
|
-
|
19
|
-
def make_ready!
|
20
|
-
@latch.countdown!
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'thread'
|
2
|
-
require 'electric_slide/queue_strategy'
|
3
|
-
|
4
|
-
class ElectricSlide
|
5
|
-
class RoundRobin
|
6
|
-
include QueueStrategy
|
7
|
-
attr_reader :queue
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
@queue = []
|
11
|
-
@agents_waiting = []
|
12
|
-
@conditional = ConditionVariable.new
|
13
|
-
end
|
14
|
-
|
15
|
-
def next_call
|
16
|
-
call = nil
|
17
|
-
synchronize do
|
18
|
-
@agents_waiting << Thread.current
|
19
|
-
@conditional.wait(@mutex) if @queue.length == 0
|
20
|
-
@agents_waiting.delete Thread.current
|
21
|
-
call = @queue.shift
|
22
|
-
end
|
23
|
-
|
24
|
-
call.make_ready!
|
25
|
-
call
|
26
|
-
end
|
27
|
-
|
28
|
-
def agents_waiting
|
29
|
-
synchronize do
|
30
|
-
@agents_waiting.dup
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# TODO: Add mechanism to add calls with higher priority to the front of the queue.
|
35
|
-
|
36
|
-
def enqueue(call)
|
37
|
-
call = wrap_call(call)
|
38
|
-
synchronize do
|
39
|
-
@queue << call
|
40
|
-
@conditional.signal if @queue.length == 1
|
41
|
-
end
|
42
|
-
super
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
@@ -1,34 +0,0 @@
|
|
1
|
-
class ElectricSlide
|
2
|
-
class RoundRobinMeetme
|
3
|
-
include QueueStrategy
|
4
|
-
|
5
|
-
def initialize(call)
|
6
|
-
@queue = []
|
7
|
-
end
|
8
|
-
|
9
|
-
def next_call
|
10
|
-
call = synchronize do
|
11
|
-
@queue.pop
|
12
|
-
end
|
13
|
-
|
14
|
-
call.make_ready!
|
15
|
-
call
|
16
|
-
end
|
17
|
-
|
18
|
-
def priority_enqueue(call)
|
19
|
-
call = wrap_call(call)
|
20
|
-
|
21
|
-
synchronize do
|
22
|
-
@queue.unshift call
|
23
|
-
end
|
24
|
-
super
|
25
|
-
end
|
26
|
-
|
27
|
-
def enqueue(call)
|
28
|
-
synchronize do
|
29
|
-
@queue << call
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe ElectricSlide::QueueStrategy do
|
4
|
-
include ElectricSlide::QueueStrategy
|
5
|
-
|
6
|
-
describe '#wrap_call' do
|
7
|
-
it 'should pass through a QueuedCall object' do
|
8
|
-
obj = ElectricSlide::QueuedCall.new dummy_call
|
9
|
-
wrap_call(obj).should be obj
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'should wrap any object that does not respond to #queued_time' do
|
13
|
-
wrap_call(dummy_call).should be_a ElectricSlide::QueuedCall
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe ElectricSlide::QueuedCall do
|
4
|
-
it 'should initialize the queued_time to the current time' do
|
5
|
-
now = Time.now
|
6
|
-
flexmock(Time).should_receive(:now).once.and_return now
|
7
|
-
qcall = ElectricSlide::QueuedCall.new dummy_call
|
8
|
-
qcall.instance_variable_get(:@queued_time).should == now
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'should start and stop music on hold when put on hold and released' do
|
12
|
-
# Both tests are combined here so we do not leave too many suspended threads lying about
|
13
|
-
queued_caller = dummy_call
|
14
|
-
flexmock(queued_caller).should_receive(:execute).once.with('StartMusicOnHold')
|
15
|
-
flexmock(queued_caller).should_receive(:execute).once.with('StopMusicOnHold')
|
16
|
-
qcall = ElectricSlide::QueuedCall.new queued_caller
|
17
|
-
|
18
|
-
# Place the call on hold and wait for it to enqueue
|
19
|
-
Thread.new { qcall.hold }
|
20
|
-
sleep 0.5
|
21
|
-
|
22
|
-
# Release the call from being on hold and sleep to ensure we get the Stop MOH signal
|
23
|
-
qcall.make_ready!
|
24
|
-
sleep 0.5
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'should block the call when put on hold' do
|
28
|
-
queued_caller = dummy_call
|
29
|
-
flexmock(queued_caller).should_receive(:execute).once.with('StartMusicOnHold')
|
30
|
-
flexmock(queued_caller).should_receive(:execute).once.with('StopMusicOnHold')
|
31
|
-
qcall = ElectricSlide::QueuedCall.new queued_caller
|
32
|
-
|
33
|
-
hold_thread = Thread.new { qcall.hold }
|
34
|
-
|
35
|
-
# Give the holding thread a chance to block...
|
36
|
-
sleep 0.5
|
37
|
-
hold_thread.status.should == "sleep"
|
38
|
-
qcall.make_ready!
|
39
|
-
sleep 0.5
|
40
|
-
hold_thread.status.should be false
|
41
|
-
end
|
42
|
-
end
|