bernstein 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/Gemfile +9 -0
- data/LICENSE +21 -0
- data/README.md +57 -0
- data/Rakefile +23 -0
- data/bernstein.gemspec +22 -0
- data/bernstein.sample.yml +14 -0
- data/bin/bernstein +26 -0
- data/lib/bernstein/client.rb +34 -0
- data/lib/bernstein/message.rb +78 -0
- data/lib/bernstein/osc_connection.rb +20 -0
- data/lib/bernstein/redis_queue.rb +86 -0
- data/lib/bernstein/server.rb +41 -0
- data/lib/bernstein/states.rb +5 -0
- data/lib/bernstein/version.rb +3 -0
- data/lib/bernstein.rb +20 -0
- data/spec/bernstein/client_spec.rb +35 -0
- data/spec/bernstein/message_spec.rb +221 -0
- data/spec/bernstein/osc_connection_spec.rb +31 -0
- data/spec/bernstein/redis_queue_spec.rb +125 -0
- data/spec/bernstein/server_spec.rb +91 -0
- data/spec/helper.rb +15 -0
- metadata +171 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 28bd90208deb3660afce5ecadda52636d9c31e8c
|
4
|
+
data.tar.gz: e84c2e6717ed39563921b813f676e678b91e79f5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1c5605a448740f7e0940175e9c72ada85f6f6ea36e6d1c24fb53982cca179e8de9891cea93ed71da27294e12058eb022f3d8fdccc9dc2f66b25ae0c5236d97f9
|
7
|
+
data.tar.gz: 1e52a953484c378fc81638411255d5a6b1a4896995658639af604d9450ea770ee7a104c1581302126befaf76be1676d2c9880cd74e9697a8163f59213bf5a510
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Anthony Plekhov
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Bernstein
|
2
|
+
|
3
|
+
Bernstein is a simple Ruby message queue for [OSC](http://en.wikipedia.org/wiki/Open_Sound_Control) messages
|
4
|
+
that gives Ruby the ability to asynchronously send messages to OSC-enabled software and hardware.
|
5
|
+
It is built on top of the [ruby-osc](https://github.com/maca/ruby-osc) libray and currently uses Redis to
|
6
|
+
queue the messages. Bernstein provides support for float,integer and string datatypes. In addition, it offers an
|
7
|
+
awk-mode that a client can use to be notified that an OSC message was delivered and awknowledged.
|
8
|
+
|
9
|
+
## Why is it useful?
|
10
|
+
|
11
|
+
While typical OSC communication is 1:1 between a client and an OSC consumer, Bernstein allows for many clients
|
12
|
+
to control an OSC device or process. For example, there could be a web interface adapting requests from
|
13
|
+
many users and sending them as OSC messages to a sound generator in an installation or performance.
|
14
|
+
See [here](https://github.com/aplekhov/bernstein-web).
|
15
|
+
Due to the queuing there is an inherent latency, however that might be neglible in certain situations.
|
16
|
+
|
17
|
+
|
18
|
+
## Basic Usage
|
19
|
+
|
20
|
+
gem install bernstein
|
21
|
+
|
22
|
+
Make sure that Redis is running. Start the background poller daemon:
|
23
|
+
|
24
|
+
bernstein start -- -c bernstein.yml
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require 'bernstein'
|
28
|
+
|
29
|
+
# see sample yml file for options
|
30
|
+
Bernstein.configure_from_yaml!('bernstein.yml')
|
31
|
+
|
32
|
+
# send a message string, all parameters will be converted to floats
|
33
|
+
msg_id = Bernstein::Client.send_message_by_string "/synths/4/filter_cutoff 0.5"
|
34
|
+
|
35
|
+
# send a message with specific types
|
36
|
+
msg_id = Bernstein::Client.send_message '/synth/params', 'sinewave', 440, 556.3, 334.0
|
37
|
+
|
38
|
+
# get status ('queued','sending','sent')
|
39
|
+
Bernstein::Client.message_status(msg_id)
|
40
|
+
```
|
41
|
+
|
42
|
+
Stop the background poller like this:
|
43
|
+
|
44
|
+
bernstein stop
|
45
|
+
|
46
|
+
## Default Configuration
|
47
|
+
See bernstein.sample.yml.
|
48
|
+
Note: if no redis options are passed, then the redis connection defaults will be used.
|
49
|
+
|
50
|
+
## Awk mode
|
51
|
+
By default, bernstein has awk mode enabled which means that it will send an internal message id along with every
|
52
|
+
message and expect the OSC receiver to respond back with an OSC 'awk' that contains the same message id. For many software
|
53
|
+
OSC implementations this is pretty easy to setup, however it is not likely to work with hardware. Make sure to disable it
|
54
|
+
using the `require_awks` config key.
|
55
|
+
|
56
|
+
## License
|
57
|
+
The MIT License. Copyright (c) 2014 Anthony Plekhov. See LICENSE.
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
require 'rdoc/task'
|
3
|
+
|
4
|
+
desc "Run specs"
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
desc "Generate code coverage"
|
8
|
+
RSpec::Core::RakeTask.new(:coverage) do |t|
|
9
|
+
t.rcov = true
|
10
|
+
t.rcov_opts = ['--exclude', 'spec']
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'Generate documentation for plugin.'
|
14
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
15
|
+
rdoc.rdoc_dir = 'rdoc'
|
16
|
+
rdoc.title = 'Timeliness'
|
17
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
18
|
+
rdoc.rdoc_files.include('README')
|
19
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
20
|
+
end
|
21
|
+
|
22
|
+
desc 'Default: run specs.'
|
23
|
+
task :default => :spec
|
data/bernstein.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/bernstein/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Anthony Plekhov"]
|
6
|
+
gem.email = ["anthony.plekhov@gmail.com"]
|
7
|
+
gem.description = gem.summary = "Ruby OSC message queue"
|
8
|
+
gem.license = "MIT"
|
9
|
+
gem.executables = ['bernstein']
|
10
|
+
gem.files = `git ls-files`.split("\n")
|
11
|
+
gem.test_files = `git ls-files -- spec/*`.split("\n")
|
12
|
+
gem.name = "bernstein"
|
13
|
+
gem.require_paths = ["lib"]
|
14
|
+
gem.version = Bernstein::VERSION
|
15
|
+
gem.add_dependency 'redis', '>= 3.1.0'
|
16
|
+
gem.add_dependency 'redis-namespace', '>= 1.5.1'
|
17
|
+
gem.add_dependency 'eventmachine', '>= 1.0.3'
|
18
|
+
gem.add_dependency 'json', '>= 1.8.1'
|
19
|
+
gem.add_dependency 'daemons', '>= 1.1.9'
|
20
|
+
gem.add_dependency 'ruby-osc', '>= 0.31.0'
|
21
|
+
gem.add_development_dependency 'rspec', '>= 3.1.0'
|
22
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# osc config for where osc messages need to be delivered
|
2
|
+
:osc_client:
|
3
|
+
:port: 9090
|
4
|
+
:host: '127.0.0.1'
|
5
|
+
# osc config that bernstein listens on for awk OSC messages
|
6
|
+
:osc_server:
|
7
|
+
:port: 9000
|
8
|
+
:host: '127.0.0.1'
|
9
|
+
:require_awks: true
|
10
|
+
# redis config, accepts all Redis gem options
|
11
|
+
:redis_queue:
|
12
|
+
:key_expiry: 300
|
13
|
+
:host: '127.0.0.1'
|
14
|
+
:port: 6379
|
data/bin/bernstein
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bernstein'
|
4
|
+
require 'daemons'
|
5
|
+
|
6
|
+
#options = {
|
7
|
+
# :backtrace => true,
|
8
|
+
# :ontop => true,
|
9
|
+
# :log_output => true,
|
10
|
+
#}
|
11
|
+
|
12
|
+
working_directory = Dir.pwd
|
13
|
+
config_opt_index = ARGV.find_index('-c')
|
14
|
+
if ARGV[0] == "start" && config_opt_index.nil?
|
15
|
+
puts "Usage: bundle exec bernstein [start|stop|restart] -- -c <bernstein yaml file>"
|
16
|
+
exit
|
17
|
+
else
|
18
|
+
init_proc = Proc.new do
|
19
|
+
Bernstein.configure_from_yaml!(File.join( working_directory, ARGV[config_opt_index + 1]))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Daemons.run_proc('bernstein') do
|
24
|
+
init_proc.call
|
25
|
+
Bernstein::Server.start
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Bernstein
|
2
|
+
class Client
|
3
|
+
##
|
4
|
+
# Example: Bernstein::Client.send_message("/synths/4/filter_cutoff .5")
|
5
|
+
# note: only accepts float arguments
|
6
|
+
#
|
7
|
+
def self.send_message_by_string(message_string)
|
8
|
+
msg = Message.build_from_string(message_string)
|
9
|
+
save_and_return_id(msg)
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# Example: Bernstein::Client.send_message("/synths/frequencies", 440, 556.3 334.0")
|
14
|
+
# note: only accepts float arguments
|
15
|
+
#
|
16
|
+
def self.send_message(address = '/', *args)
|
17
|
+
msg = Message.build(address, *args)
|
18
|
+
save_and_return_id(msg)
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Example: Bernstein::Client.message_status("34246456458856")
|
23
|
+
#
|
24
|
+
def self.message_status(message_id)
|
25
|
+
Message.get_status(message_id)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def self.save_and_return_id(msg)
|
30
|
+
msg.save!
|
31
|
+
msg.id
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'ruby-osc'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Bernstein
|
5
|
+
class Message
|
6
|
+
attr_reader :id, :osc_message
|
7
|
+
@@persister = RedisQueue
|
8
|
+
@@osc_connection = OSCConnection
|
9
|
+
|
10
|
+
def initialize(osc_message, id = nil)
|
11
|
+
@osc_message = osc_message
|
12
|
+
@id = id || new_id
|
13
|
+
@is_saved = false
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.build(address = '', *args)
|
17
|
+
Message.new(OSC::Message.new(address, *args))
|
18
|
+
end
|
19
|
+
|
20
|
+
# only supports float arguments
|
21
|
+
def self.build_from_string(message_string)
|
22
|
+
address, args = parse_message_string(message_string)
|
23
|
+
Message.new(OSC::Message.new(address, *args))
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.deserialize(serialized_msg)
|
27
|
+
data = JSON.parse(serialized_msg)
|
28
|
+
Message.new OSC::Message.new(data['address'], *data['args']), data['id']
|
29
|
+
end
|
30
|
+
|
31
|
+
def serialize
|
32
|
+
{'id' => @id, 'address' => @osc_message.address, 'args' => @osc_message.args}.to_json
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.get_status(id)
|
36
|
+
@@persister.status(id)
|
37
|
+
end
|
38
|
+
|
39
|
+
def status
|
40
|
+
@@persister.status(@id)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.get_queued_messages
|
44
|
+
@@persister.queued_messages
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.set_as_sent!(id)
|
48
|
+
@@persister.mark_as_sent(id)
|
49
|
+
end
|
50
|
+
|
51
|
+
def save!
|
52
|
+
unless @is_saved
|
53
|
+
@@persister.add(self)
|
54
|
+
@is_saved = true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def send!(expect_awk = true)
|
59
|
+
@@osc_connection.send_message self, expect_awk
|
60
|
+
@@persister.dequeue @id, !expect_awk
|
61
|
+
end
|
62
|
+
|
63
|
+
def ==(other)
|
64
|
+
(self.class == other.class) && (self.osc_message == other.osc_message) &&
|
65
|
+
(self.id == other.id)
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
def new_id
|
70
|
+
Time.now.to_f.to_s.delete('.')
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.parse_message_string message_string
|
74
|
+
message_array = message_string.split
|
75
|
+
[message_array.shift, message_array.map{|arg| arg.to_f}]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'ruby-osc'
|
2
|
+
|
3
|
+
module Bernstein
|
4
|
+
class OSCConnection
|
5
|
+
include OSC
|
6
|
+
|
7
|
+
@options = {port: 8000, host: '127.0.0.1'}
|
8
|
+
|
9
|
+
def self.configure!(options = {})
|
10
|
+
@options.merge!(options || {})
|
11
|
+
@connection = OSC::Client.new @options[:port], @options[:host]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.send_message(message, with_message_id = true)
|
15
|
+
osc_message = message.osc_message
|
16
|
+
osc_message = OSC::Bundle.new(nil, osc_message, OSC::Message.new('/message_id', message.id)) if with_message_id
|
17
|
+
@connection.send osc_message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'redis'
|
2
|
+
require 'redis-namespace'
|
3
|
+
|
4
|
+
module Bernstein
|
5
|
+
class RedisQueue
|
6
|
+
include States
|
7
|
+
|
8
|
+
QUEUE_SET = "queued_messages"
|
9
|
+
@options = {key_expiry: 300, redis: {}}
|
10
|
+
|
11
|
+
def self.configure!(options = {})
|
12
|
+
@options.merge!(options || {})
|
13
|
+
@redis = Redis::Namespace.new(:bernstein, :redis => Redis.new(@options[:redis]))
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.add(message)
|
17
|
+
@redis.multi do
|
18
|
+
@redis.sadd QUEUE_SET, message.id
|
19
|
+
@redis.setex message.id, @options[:key_expiry], message.serialize
|
20
|
+
@redis.setex status_key(message.id), @options[:key_expiry], STATES[:queued]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.status(id)
|
25
|
+
@redis.get(status_key(id)) || STATES[:not_yet_queued]
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.queued_messages
|
29
|
+
queued_message_ids = @redis.smembers QUEUE_SET
|
30
|
+
messages = []
|
31
|
+
unless queued_message_ids.empty?
|
32
|
+
messages = @redis.mget(queued_message_ids).compact
|
33
|
+
unless messages.empty?
|
34
|
+
messages.map!{|m| Message.deserialize(m)}
|
35
|
+
end
|
36
|
+
if messages.size < queued_message_ids.size
|
37
|
+
clean_up_queue(queued_message_ids - messages.map{|m| m.id})
|
38
|
+
end
|
39
|
+
end
|
40
|
+
messages
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.clear
|
44
|
+
@redis.del QUEUE_SET
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.dequeue(id, mark_as_sent = false)
|
48
|
+
remove_and_change_status(id, (mark_as_sent ? STATES[:sent] : STATES[:sending]))
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.mark_as_sent(id)
|
52
|
+
set_status(id, STATES[:sent])
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def self.status_key(id)
|
57
|
+
"#{id}_status"
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.remove_and_change_status(id, status)
|
61
|
+
remove(id){ set_status(id, status) }
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.set_status(id, status)
|
65
|
+
@redis.setex status_key(id), @options[:key_expiry], status
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.remove(id)
|
69
|
+
if block_given?
|
70
|
+
@redis.multi do
|
71
|
+
@redis.srem QUEUE_SET, id
|
72
|
+
yield
|
73
|
+
end
|
74
|
+
else
|
75
|
+
@redis.srem QUEUE_SET, id
|
76
|
+
end
|
77
|
+
@redis.del id
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.clean_up_queue(ids_to_remove)
|
81
|
+
@redis.pipelined do
|
82
|
+
ids_to_remove.each{|id| @redis.srem QUEUE_SET, id}
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'ruby-osc'
|
3
|
+
|
4
|
+
module Bernstein
|
5
|
+
class Server
|
6
|
+
@options = {port: 9000, host: '127.0.0.1', require_awks: true, poll_interval: 5, awk_address: '/awk_id'}
|
7
|
+
def self.configure!(options = {})
|
8
|
+
@options.merge!(options || {})
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.start
|
12
|
+
OSC.run do
|
13
|
+
@server = OSC::Server.new(@options[:port],@options[:host])
|
14
|
+
if @options[:require_awks]
|
15
|
+
@server.add_pattern @options[:awk_address] do |*args|
|
16
|
+
handle_awknowledgement(args[1])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
@timer = EventMachine::PeriodicTimer.new(@options[:poll_interval]) do
|
21
|
+
process_queued_messages
|
22
|
+
end
|
23
|
+
yield if block_given?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.stop
|
28
|
+
@server.stop unless @server.nil?
|
29
|
+
@timer.cancel unless @timer.nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def self.process_queued_messages
|
34
|
+
Message.get_queued_messages.each{|m| m.send!(@options[:require_awks])}
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.handle_awknowledgement(id)
|
38
|
+
Message.set_as_sent!(id)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/bernstein.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'bernstein/states'
|
2
|
+
require 'bernstein/redis_queue'
|
3
|
+
require 'bernstein/osc_connection'
|
4
|
+
require 'bernstein/message'
|
5
|
+
require 'bernstein/client'
|
6
|
+
require 'bernstein/server'
|
7
|
+
require 'bernstein/version'
|
8
|
+
require 'yaml'
|
9
|
+
|
10
|
+
module Bernstein
|
11
|
+
def self.configure_from_yaml!(file_path)
|
12
|
+
configure!(YAML.load_file(file_path))
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.configure!(options = {})
|
16
|
+
RedisQueue.configure!(options[:redis_queue])
|
17
|
+
OSCConnection.configure!(options[:osc_client])
|
18
|
+
Server.configure!(options[:osc_server])
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Bernstein::Client do
|
4
|
+
subject { Bernstein::Client }
|
5
|
+
|
6
|
+
describe "sending a message" do
|
7
|
+
it "should build the message object and return its id" do
|
8
|
+
id = subject.send_message_by_string("/synths/4/chord/notes 25 30 10")
|
9
|
+
expect(id).to_not be_nil
|
10
|
+
queued_messages = Bernstein::Message.get_queued_messages
|
11
|
+
message = queued_messages.find{|m| m.id == id}
|
12
|
+
expect(message).to_not be_nil
|
13
|
+
expect(message.osc_message.address).to eq("/synths/4/chord/notes")
|
14
|
+
expect(message.osc_message.args).to eq([25.0, 30.0, 10.0])
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should accept arguments to build the message" do
|
18
|
+
id = subject.send_message("/synths/4/parameters", 20, 34.2, 'squarewave')
|
19
|
+
expect(id).to_not be_nil
|
20
|
+
queued_messages = Bernstein::Message.get_queued_messages
|
21
|
+
message = queued_messages.find{|m| m.id == id}
|
22
|
+
expect(message).to_not be_nil
|
23
|
+
expect(message.osc_message.address).to eq("/synths/4/parameters")
|
24
|
+
expect(message.osc_message.args).to eq([20, 34.2, 'squarewave'])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "querying a message's status by id" do
|
29
|
+
it "should return the current status or not yet queued" do
|
30
|
+
id = subject.send_message("/synths/4/chord/notes 25 30 10")
|
31
|
+
expect_state(subject.message_status(id), :queued)
|
32
|
+
expect_state(subject.message_status('123'), :not_yet_queued)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'ruby-osc'
|
3
|
+
|
4
|
+
class DummyPersister
|
5
|
+
attr_accessor :queue, :sent_messages, :message_states
|
6
|
+
def initialize
|
7
|
+
@queue, @sent_messages, @message_states = [],[], {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def add(message)
|
11
|
+
@queue << message
|
12
|
+
@message_states[message] = :queued
|
13
|
+
end
|
14
|
+
|
15
|
+
def queued_messages
|
16
|
+
@queue
|
17
|
+
end
|
18
|
+
|
19
|
+
def dequeue(id, mark_as_sent = false)
|
20
|
+
message = @queue.find{|m| m.id == id}
|
21
|
+
if !message.nil?
|
22
|
+
@message_states[message] = (mark_as_sent ? :sent : :sending)
|
23
|
+
@sent_messages << message
|
24
|
+
@queue.delete(message)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def mark_as_sent(id)
|
29
|
+
message = @message_states.keys.find{|m| m.id == id}
|
30
|
+
@message_states[message] = :sent unless message.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
def status(id)
|
34
|
+
message = @message_states.keys.find{|m| m.id == id}
|
35
|
+
Bernstein::States::STATES[@message_states[message]]
|
36
|
+
end
|
37
|
+
|
38
|
+
def clear
|
39
|
+
@queue.clear
|
40
|
+
@sent_messages.clear
|
41
|
+
@message_states.clear
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class DummyOSCConnection
|
46
|
+
attr_accessor :fail_send, :sent_messages, :sent_ids
|
47
|
+
def initialize
|
48
|
+
@fail_send, @sent_messages, @sent_ids = false, [], []
|
49
|
+
end
|
50
|
+
|
51
|
+
def send_message message, with_message_id = true
|
52
|
+
if @fail_send
|
53
|
+
throw "something went wrong"
|
54
|
+
else
|
55
|
+
@sent_messages << message
|
56
|
+
@sent_ids << message.id if with_message_id
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe Bernstein::Message do
|
62
|
+
subject { Bernstein::Message }
|
63
|
+
|
64
|
+
before(:all) do
|
65
|
+
@mock_queue = DummyPersister.new
|
66
|
+
@mock_osc_connection = DummyOSCConnection.new
|
67
|
+
@real_persister = Bernstein::Message.class_variable_get('@@persister')
|
68
|
+
@real_osc_connection = Bernstein::Message.class_variable_get('@@osc_connection')
|
69
|
+
Bernstein::Message.class_variable_set('@@persister', @mock_queue)
|
70
|
+
Bernstein::Message.class_variable_set('@@osc_connection', @mock_osc_connection)
|
71
|
+
end
|
72
|
+
|
73
|
+
after(:all) do
|
74
|
+
Bernstein::Message.class_variable_set('@@persister', @real_persister)
|
75
|
+
Bernstein::Message.class_variable_set('@@osc_connection', @real_osc_connection)
|
76
|
+
end
|
77
|
+
|
78
|
+
before(:each) do
|
79
|
+
@mock_queue.clear
|
80
|
+
@message = Bernstein::Message.build_from_string("/test 1 2 3")
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "building a new message" do
|
84
|
+
it "should be able to be built from a message string and turn all parameters into floats" do
|
85
|
+
address = "/test/this/out"
|
86
|
+
args = ['1', '2', '3.5']
|
87
|
+
message = subject.build_from_string("#{address} #{args.join(' ')}")
|
88
|
+
expect(message.osc_message.address).to eq(address)
|
89
|
+
expect(message.osc_message.args).to eq(args.map{|a| a.to_f})
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should be able to built from address and args, preserving types" do
|
93
|
+
address = "/test/this/out"
|
94
|
+
args = [5, 'pizza', 9.9, 2.0]
|
95
|
+
message = subject.build(address,*args)
|
96
|
+
expect(message.osc_message.address).to eq(address)
|
97
|
+
expect(message.osc_message.args).to eq(args)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should be able to be built from an already built osc message" do
|
101
|
+
msg = OSC::Message.new('/hi/msg','2',4)
|
102
|
+
message1 = subject.new(msg)
|
103
|
+
expect(message1.osc_message).to eq(msg)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should return a unique id" do
|
107
|
+
messages = []
|
108
|
+
5.times {|i| messages << subject.build_from_string("/test #{i}")}
|
109
|
+
messages.each do |message|
|
110
|
+
expect(message.id).to_not be_nil
|
111
|
+
(messages - [message]).each{|other_message| expect(other_message.id).to_not eq(message.id)}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should be able to be built with a set id" do
|
116
|
+
address = "/test/this/out"
|
117
|
+
args = ['1', '2', '3']
|
118
|
+
id = "456"
|
119
|
+
osc_msg = OSC::Message.new(address, *args)
|
120
|
+
message = subject.new osc_msg, id
|
121
|
+
expect(message.id).to eq(id)
|
122
|
+
expect(message.osc_message.address).to eq(address)
|
123
|
+
expect(message.osc_message.args).to eq(args)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should be equal to another message with the same id, args and address" do
|
127
|
+
message1 = subject.build_from_string("/test 1 2 3")
|
128
|
+
message2 = subject.new(OSC::Message.new("/test", 1,2,3), message1.id)
|
129
|
+
message3 = subject.new(message2.osc_message, '999')
|
130
|
+
expect(message1).to eq(message2)
|
131
|
+
expect(message1).to_not eq(message3)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "serialization" do
|
136
|
+
it "should serialize and deserialize the osc message and id" do
|
137
|
+
@message = subject.build_from_string("/test 1 2 3.2345")
|
138
|
+
serialized_msg = @message.serialize
|
139
|
+
expect(@message).to eq(subject.deserialize(serialized_msg))
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should handle float, integer and string arguments" do
|
143
|
+
@message = subject.build("/test", 3.4567, 10, 'a_string')
|
144
|
+
serialized_msg = @message.serialize
|
145
|
+
expect(@message).to eq(subject.deserialize(serialized_msg))
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "saving a message" do
|
150
|
+
it "should add message onto the queue upon save" do
|
151
|
+
@message.save!
|
152
|
+
expect(@mock_queue.queue).to include(@message)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should not be able to add the same message onto the queue again" do
|
156
|
+
@message.save!
|
157
|
+
expect{@message.save!}.to_not change(@mock_queue.queue, :size)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "sending a message" do
|
162
|
+
before(:each) do
|
163
|
+
@message.save!
|
164
|
+
end
|
165
|
+
|
166
|
+
after(:each) do
|
167
|
+
@mock_osc_connection.fail_send = false
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should send the message and message id on the OSC connection and remove from queue" do
|
171
|
+
@message.send!
|
172
|
+
expect(@mock_osc_connection.sent_messages).to include(@message)
|
173
|
+
expect(@mock_osc_connection.sent_ids).to include(@message.id)
|
174
|
+
expect(@mock_queue.sent_messages).to include(@message)
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should not mark the message as sent on the queue if there is an error" do
|
178
|
+
@mock_osc_connection.fail_send = true
|
179
|
+
@message.send rescue
|
180
|
+
expect(@mock_queue.sent_messages).to_not include(@message)
|
181
|
+
expect(@mock_osc_connection.sent_messages).to_not include(@message)
|
182
|
+
expect(@mock_osc_connection.sent_ids).to_not include(@message.id)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should send the message and mark as sent and not ask to send message id along" do
|
186
|
+
@message.send!(false)
|
187
|
+
expect_state(@message.status, :sent)
|
188
|
+
expect(@mock_osc_connection.sent_messages).to include(@message)
|
189
|
+
expect(@mock_osc_connection.sent_ids).to_not include(@message.id)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe "querying status" do
|
194
|
+
before(:each) do
|
195
|
+
@message.save!
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should return the current status for a message object" do
|
199
|
+
expect_state(@message.status, :queued)
|
200
|
+
@message.send!
|
201
|
+
expect_state(@message.status, :sending)
|
202
|
+
@mock_queue.mark_as_sent(@message.id)
|
203
|
+
expect_state(@message.status, :sent)
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should return the current status by message id" do
|
207
|
+
expect_state(subject.get_status(@message.id), :queued)
|
208
|
+
@message.send!(false)
|
209
|
+
expect_state(subject.get_status(@message.id), :sent)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "getting queued messages" do
|
214
|
+
it "should return all queued messages" do
|
215
|
+
@message.save!
|
216
|
+
@message2 = subject.build_from_string("/test/2 4 5 6")
|
217
|
+
@message2.save!
|
218
|
+
expect(subject.get_queued_messages).to eq([@message, @message2])
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
def current_client
|
4
|
+
Bernstein::OSCConnection.instance_variable_get('@connection')
|
5
|
+
end
|
6
|
+
|
7
|
+
describe Bernstein::OSCConnection do
|
8
|
+
describe "configuring" do
|
9
|
+
it "should instantiate a new osc client based on the port and host that was given" do
|
10
|
+
expect(OSC::Client).to receive(:new).with(9000, '10.10.10.1')
|
11
|
+
Bernstein::OSCConnection.configure!({port: 9000, host: '10.10.10.1'})
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "sending a message" do
|
16
|
+
it "should create a new osc message from the passed in message and call send on the client" do
|
17
|
+
Bernstein::OSCConnection.configure!({port: 9000, host: '10.10.10.1'})
|
18
|
+
expect(OSC::Message).to receive(:new).with('/test', 1.0,2.0,3.0).and_return("mock")
|
19
|
+
message1 = Bernstein::Message.build_from_string("/test 1 2 3")
|
20
|
+
expect(current_client).to receive(:send).with("mock")
|
21
|
+
Bernstein::OSCConnection.send_message(message1, false)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should send a bundle when asked to send message id" do
|
25
|
+
Bernstein::OSCConnection.configure!({port: 9000, host: '10.10.10.1'})
|
26
|
+
message1 = Bernstein::Message.build_from_string("/test 1 2 3")
|
27
|
+
expect(current_client).to receive(:send).with(kind_of(OSC::Bundle))
|
28
|
+
Bernstein::OSCConnection.send_message(message1, true)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
def redis_connection
|
4
|
+
Bernstein::RedisQueue.instance_variable_get('@redis')
|
5
|
+
end
|
6
|
+
|
7
|
+
def redis_queue
|
8
|
+
redis_connection.smembers(Bernstein::RedisQueue::QUEUE_SET)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe Bernstein::RedisQueue do
|
12
|
+
subject { Bernstein::RedisQueue }
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
@message = Bernstein::Message.build_from_string("/test/3 1 2.55 4")
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "initialization and configuration" do
|
19
|
+
after(:all){Bernstein::RedisQueue.configure!({redis:{}})}
|
20
|
+
|
21
|
+
it "should pass redis options to initialize a new redis connection" do
|
22
|
+
redis_opts = {host: "10.0.1.1", port: 6380, db: 15}
|
23
|
+
expect(Redis).to receive(:new).with(redis_opts).and_call_original
|
24
|
+
Bernstein::RedisQueue.configure!({key_expiry: 600, redis: redis_opts})
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be namespaced" do
|
28
|
+
expect(redis_connection.class).to eq(Redis::Namespace)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "adding a new message" do
|
33
|
+
it "should serialize the message and add it to the proper sets" do
|
34
|
+
subject.add(@message)
|
35
|
+
data = redis_connection.get(@message.id)
|
36
|
+
expect(Bernstein::Message.deserialize(data)).to eq(@message)
|
37
|
+
expect(redis_queue).to include(@message.id)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "expired messages" do
|
42
|
+
before(:all) do
|
43
|
+
@key_expiry = 1
|
44
|
+
Bernstein::RedisQueue.configure! key_expiry: @key_expiry
|
45
|
+
end
|
46
|
+
|
47
|
+
after(:all) do
|
48
|
+
Bernstein::RedisQueue.configure! key_expiry: 300
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should expire messages based on set expiry times" do
|
52
|
+
subject.add(@message)
|
53
|
+
expect_state(subject.status(@message.id), :queued)
|
54
|
+
expect(redis_connection.get(@message.id)).to_not be_nil
|
55
|
+
sleep @key_expiry + 1
|
56
|
+
expect(redis_connection.get(@message.id)).to be_nil
|
57
|
+
expect_state(subject.status(@message.id), :not_yet_queued)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should expire messages that have had their status changed" do
|
61
|
+
subject.add(@message)
|
62
|
+
subject.mark_as_sent(@message.id)
|
63
|
+
expect_state(subject.status(@message.id), :sent)
|
64
|
+
sleep @key_expiry + 1
|
65
|
+
expect_state(subject.status(@message.id), :not_yet_queued)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should clean up request_queue of unhandled expired messages" do
|
69
|
+
subject.add(@message)
|
70
|
+
expect(subject.queued_messages).to include(@message)
|
71
|
+
sleep @key_expiry + 1
|
72
|
+
@another_message = Bernstein::Message.build_from_string("/test/current 5 6 7")
|
73
|
+
subject.add(@another_message)
|
74
|
+
queued_messages = subject.queued_messages
|
75
|
+
queue_set = redis_queue
|
76
|
+
expect(queued_messages).to_not include(@message)
|
77
|
+
expect(queued_messages).to include(@another_message)
|
78
|
+
expect(queue_set).to_not include(@message.id)
|
79
|
+
expect(queue_set).to include(@another_message.id)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "marking and requesting status" do
|
84
|
+
it "should return not yet sent queued for unknown messages" do
|
85
|
+
expect_state(subject.status('123456'), :not_yet_queued)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should set new messages' status to queued" do
|
89
|
+
subject.add(@message)
|
90
|
+
expect_state(subject.status(@message.id), :queued)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should mark a message as sent" do
|
94
|
+
subject.add(@message)
|
95
|
+
subject.mark_as_sent(@message.id)
|
96
|
+
expect_state(subject.status(@message.id), :sent)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should dequeue messages and set them to sending state by default" do
|
100
|
+
subject.add(@message)
|
101
|
+
subject.dequeue(@message.id)
|
102
|
+
expect_state(subject.status(@message.id), :sending)
|
103
|
+
expect(redis_queue).to_not include(@message.id)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should dequeue messages and set their state straight to sent" do
|
107
|
+
subject.add(@message)
|
108
|
+
subject.dequeue(@message.id, true)
|
109
|
+
expect_state(subject.status(@message.id), :sent)
|
110
|
+
expect(redis_queue).to_not include(@message.id)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "getting queued messages" do
|
115
|
+
it "should pull queued messages and deserialize them" do
|
116
|
+
subject.clear
|
117
|
+
message = Bernstein::Message.build_from_string("/test/1 1")
|
118
|
+
message2 = Bernstein::Message.build_from_string("/test/2 1 2")
|
119
|
+
message3 = Bernstein::Message.build_from_string("/test/3 1 2 3")
|
120
|
+
messages = [message, message2, message3]
|
121
|
+
messages.each{|m| subject.add(m)}
|
122
|
+
expect(subject.queued_messages.sort{|a,b| a.id <=> b.id}).to eq(messages.sort{|a,b| a.id <=> b.id})
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'ruby-osc'
|
3
|
+
require 'eventmachine'
|
4
|
+
|
5
|
+
describe Bernstein::Server do
|
6
|
+
describe "initialization and configuration" do
|
7
|
+
it "should pass options to initialize a new OSC server" do
|
8
|
+
opts = {port: 9004, host: '127.0.0.1'}
|
9
|
+
expect(OSC::Server).to receive(:new).with(opts[:port], opts[:host]).and_call_original
|
10
|
+
Bernstein::Server.configure!(opts)
|
11
|
+
Bernstein::Server.start do
|
12
|
+
Bernstein::Server.stop
|
13
|
+
EventMachine.stop_event_loop
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "processing queued messages" do
|
19
|
+
before(:each) do
|
20
|
+
connection = Bernstein::Message.class_variable_get('@@osc_connection')
|
21
|
+
allow(connection).to receive(:send_message)
|
22
|
+
Bernstein::RedisQueue.clear
|
23
|
+
@message = Bernstein::Client.send_message_by_string("/test/1 1")
|
24
|
+
@message2 = Bernstein::Client.send_message_by_string("/test/2 1 2")
|
25
|
+
@message3 = Bernstein::Client.send_message_by_string("/test/3 1 2 3")
|
26
|
+
[@message, @message2, @message3].each do |message_id|
|
27
|
+
expect_state(Bernstein::Client.message_status(message_id), :queued)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
it "should call send on all queued messages" do
|
33
|
+
Bernstein::Server.configure!({poll_interval:1, require_awks:true})
|
34
|
+
Bernstein::Server.start do
|
35
|
+
EventMachine.add_timer 4 do
|
36
|
+
Bernstein::Server.stop
|
37
|
+
EventMachine.stop_event_loop
|
38
|
+
end
|
39
|
+
end
|
40
|
+
[@message, @message2, @message3].each do |message_id|
|
41
|
+
expect_state(Bernstein::Client.message_status(message_id), :sending)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "awks" do
|
47
|
+
before(:each) do
|
48
|
+
connection = Bernstein::Message.class_variable_get('@@osc_connection')
|
49
|
+
allow(connection).to receive(:send_message)
|
50
|
+
Bernstein::RedisQueue.clear
|
51
|
+
@message_id = Bernstein::Client.send_message_by_string("/test/1 1")
|
52
|
+
expect_state(Bernstein::Client.message_status(@message_id), :queued)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should listen for awks and set messages with corresponding ids to sent if configured" do
|
56
|
+
Bernstein::Server.configure!({port: 9090, host: '127.0.0.1', poll_interval: 1, require_awks: true})
|
57
|
+
Bernstein::Server.start do
|
58
|
+
client = OSC::Client.new 9090
|
59
|
+
EventMachine.add_timer 2 do
|
60
|
+
expect_state(Bernstein::Client.message_status(@message_id), :sending)
|
61
|
+
end
|
62
|
+
EventMachine.add_timer 3 do
|
63
|
+
client.send OSC::Message.new('/awk_id', @message_id)
|
64
|
+
end
|
65
|
+
EventMachine.add_timer 4 do
|
66
|
+
Bernstein::Server.stop
|
67
|
+
EventMachine.stop_event_loop
|
68
|
+
end
|
69
|
+
end
|
70
|
+
expect_state(Bernstein::Client.message_status(@message_id), :sent)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should not listen for awks and set messages directly to sent if configured" do
|
74
|
+
Bernstein::Server.configure!({port: 9090, host: '127.0.0.1', require_awks: false, poll_interval: 1})
|
75
|
+
Bernstein::Server.start do
|
76
|
+
client = OSC::Client.new 9090
|
77
|
+
EventMachine.add_timer 2 do
|
78
|
+
expect_state(Bernstein::Client.message_status(@message_id), :sent)
|
79
|
+
end
|
80
|
+
EventMachine.add_timer 3 do
|
81
|
+
client.send OSC::Message.new('/awk_id', @message_id)
|
82
|
+
end
|
83
|
+
EventMachine.add_timer 4 do
|
84
|
+
Bernstein::Server.stop
|
85
|
+
EventMachine.stop_event_loop
|
86
|
+
end
|
87
|
+
end
|
88
|
+
expect_state(Bernstein::Client.message_status(@message_id), :sent)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/spec/helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
$:.unshift( File.join( File.dirname( __FILE__), '..', 'lib' ) )
|
3
|
+
require 'bernstein'
|
4
|
+
|
5
|
+
RSpec.configure do |c|
|
6
|
+
c.mock_with :rspec
|
7
|
+
end
|
8
|
+
|
9
|
+
Bernstein.configure!
|
10
|
+
|
11
|
+
include Bernstein::States
|
12
|
+
|
13
|
+
def expect_state(something, state)
|
14
|
+
expect(something).to eq(STATES[state])
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bernstein
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Anthony Plekhov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: redis
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.1.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: redis-namespace
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.5.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.5.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: eventmachine
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.0.3
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.0.3
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: json
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.8.1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.8.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: daemons
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.1.9
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.1.9
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: ruby-osc
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.31.0
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.31.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 3.1.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 3.1.0
|
111
|
+
description: Ruby OSC message queue
|
112
|
+
email:
|
113
|
+
- anthony.plekhov@gmail.com
|
114
|
+
executables:
|
115
|
+
- bernstein
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- .gitignore
|
120
|
+
- Gemfile
|
121
|
+
- LICENSE
|
122
|
+
- README.md
|
123
|
+
- Rakefile
|
124
|
+
- bernstein.gemspec
|
125
|
+
- bernstein.sample.yml
|
126
|
+
- bin/bernstein
|
127
|
+
- lib/bernstein.rb
|
128
|
+
- lib/bernstein/client.rb
|
129
|
+
- lib/bernstein/message.rb
|
130
|
+
- lib/bernstein/osc_connection.rb
|
131
|
+
- lib/bernstein/redis_queue.rb
|
132
|
+
- lib/bernstein/server.rb
|
133
|
+
- lib/bernstein/states.rb
|
134
|
+
- lib/bernstein/version.rb
|
135
|
+
- spec/bernstein/client_spec.rb
|
136
|
+
- spec/bernstein/message_spec.rb
|
137
|
+
- spec/bernstein/osc_connection_spec.rb
|
138
|
+
- spec/bernstein/redis_queue_spec.rb
|
139
|
+
- spec/bernstein/server_spec.rb
|
140
|
+
- spec/helper.rb
|
141
|
+
homepage:
|
142
|
+
licenses:
|
143
|
+
- MIT
|
144
|
+
metadata: {}
|
145
|
+
post_install_message:
|
146
|
+
rdoc_options: []
|
147
|
+
require_paths:
|
148
|
+
- lib
|
149
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - '>='
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '0'
|
159
|
+
requirements: []
|
160
|
+
rubyforge_project:
|
161
|
+
rubygems_version: 2.4.2
|
162
|
+
signing_key:
|
163
|
+
specification_version: 4
|
164
|
+
summary: Ruby OSC message queue
|
165
|
+
test_files:
|
166
|
+
- spec/bernstein/client_spec.rb
|
167
|
+
- spec/bernstein/message_spec.rb
|
168
|
+
- spec/bernstein/osc_connection_spec.rb
|
169
|
+
- spec/bernstein/redis_queue_spec.rb
|
170
|
+
- spec/bernstein/server_spec.rb
|
171
|
+
- spec/helper.rb
|