rcom 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 95a36229bc381e17c5190154a0679add12a794bf
4
+ data.tar.gz: ab8d5adbcb9b0a599a3da61badd4197dfec6c732
5
+ SHA512:
6
+ metadata.gz: d2199539d074722c55d225ac420f953fc6299d15c24569d7e2e9ce1f58031d3ddc1b3782a23b2c340083b13768a1a6a0f485958c5aee4284e5f840ebc5a67df2
7
+ data.tar.gz: 28cf9fd25c94b73073c0cd3aeaa77fdccb2544c1a27a518d7da2401f1252c347eaea9d38fdeddd6f5c4f4b0a15396263dedf001440c873a815ffeba10ebcdc55
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rcom.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Marco Lisci
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # Rcom
2
+
3
+ Redis inter-service messaging: request-response, publish-subscribe and tasks. A thin, minimal layer on top of [Redis-rb](https://github.com/redis/redis-rb).
4
+
5
+ ## Installation.
6
+
7
+ - [Install](http://redis.io/topics/quickstart) a local Redis server and start it:
8
+ ```sh
9
+ # OSX example
10
+ $ brew install redis
11
+ $ redis-server
12
+ ```
13
+
14
+ - Add rcom to your Gemfile:
15
+ ```ruby
16
+ gem 'rcom'
17
+ ```
18
+
19
+ ## Usage.
20
+
21
+ ## Test.
22
+
23
+ ## Contributing.
24
+
25
+ 1. Fork it ( https://github.com/badshark/rcom/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
30
+
31
+ ## License.
32
+
33
+ [MIT](LICENSE.txt)
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ namespace :test do
5
+ Rake::TestTask.new(:spec) do |t|
6
+ t.pattern = 'test/spec/*_spec.rb'
7
+ end
8
+
9
+ Rake::TestTask.new(:all) do |t|
10
+ t.pattern = 'test/**/*.rb'
11
+ end
12
+ end
13
+
14
+
data/lib/rcom/node.rb ADDED
@@ -0,0 +1,14 @@
1
+ module Rcom
2
+ class Node
3
+ attr_reader :uri
4
+
5
+ def initialize(uri)
6
+ raise ArgumentError unless ENV[uri.upcase]
7
+ @uri = ENV[uri.upcase]
8
+ end
9
+
10
+ def connect
11
+ Redis.new(url: uri)
12
+ end
13
+ end
14
+ end
data/lib/rcom/rpc.rb ADDED
@@ -0,0 +1,53 @@
1
+ module Rcom
2
+ class Rpc
3
+ attr_reader :node, :service
4
+
5
+ def initialize(params)
6
+ @node = params[:node]
7
+ @service = params[:service]
8
+ end
9
+
10
+ def request(params)
11
+ request = {
12
+ id: SecureRandom.hex,
13
+ method: params[:method],
14
+ args: params[:args]
15
+ }
16
+ node.rpush(service, request.to_msgpack)
17
+ ch, response = node.brpop(request[:id], timeout=10)
18
+ MessagePack.unpack(
19
+ response,
20
+ symbolize_keys: true
21
+ )
22
+ end
23
+
24
+ def subscribe
25
+ begin
26
+ loop do
27
+ ch, request = node.brpop(service)
28
+ message = MessagePack.unpack(
29
+ request,
30
+ symbolize_keys: true
31
+ )
32
+ router = Rcom::Router.new(message)
33
+ yield router
34
+ node.rpush(message[:id], router.reply.to_msgpack)
35
+ end
36
+ rescue Interrupt => _
37
+ end
38
+ end
39
+ end
40
+
41
+ class Router
42
+ attr_accessor :message, :reply
43
+
44
+ def initialize(message)
45
+ @message = message
46
+ end
47
+
48
+ def on(method)
49
+ return nil unless message[:method] == method
50
+ yield message[:args]
51
+ end
52
+ end
53
+ end
data/lib/rcom/task.rb ADDED
@@ -0,0 +1,28 @@
1
+ module Rcom
2
+ class Task
3
+ attr_reader :node, :queue
4
+
5
+ def initialize(args)
6
+ @node = args[:node]
7
+ @queue = args[:queue]
8
+ end
9
+
10
+ def publish(message)
11
+ node.lpush(queue, message.to_msgpack)
12
+ end
13
+
14
+ def subscribe
15
+ begin
16
+ loop do
17
+ ch, request = node.brpop(queue)
18
+ message = MessagePack.unpack(
19
+ request,
20
+ symbolize_keys: true
21
+ )
22
+ yield message
23
+ end
24
+ rescue Interrupt => _
25
+ end
26
+ end
27
+ end
28
+ end
data/lib/rcom/topic.rb ADDED
@@ -0,0 +1,29 @@
1
+ module Rcom
2
+ class Topic
3
+ attr_reader :node, :key
4
+
5
+ def initialize(args)
6
+ @node = args[:node]
7
+ @key = args[:key]
8
+ end
9
+
10
+ def publish(message)
11
+ node.publish(key, message.to_msgpack)
12
+ end
13
+
14
+ def subscribe
15
+ begin
16
+ node.subscribe(key) do |on|
17
+ on.message do |channel, message|
18
+ message = MessagePack.unpack(
19
+ message,
20
+ symbolize_keys: true
21
+ )
22
+ yield message
23
+ end
24
+ end
25
+ rescue Interrupt => _
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module Rcom
2
+ VERSION = "0.0.1"
3
+ end
data/lib/rcom.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'securerandom'
2
+ require 'redis'
3
+ require 'msgpack'
4
+ require 'rcom/version'
5
+ require 'rcom/node'
6
+ require 'rcom/topic'
7
+ require 'rcom/task'
8
+ require 'rcom/rpc'
data/rcom.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rcom/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rcom"
8
+ spec.version = Rcom::VERSION
9
+ spec.authors = ["Marco Lisci"]
10
+ spec.email = ["info@badshark.io"]
11
+ spec.summary = %q{Redis inter-service messaging.}
12
+ spec.description = %q{Redis inter-service messaging: request-response, publish-subscribe and tasks.}
13
+ spec.homepage = "https://github.com/badshark/rcom"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "yard"
24
+
25
+ spec.add_dependency "redis", "~> 3.1.0"
26
+ spec.add_dependency "msgpack", "~> 0.5.9"
27
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['LOCAL'] = 'redis://localhost'
3
+
4
+ require 'rcom'
5
+ require 'json'
6
+
7
+ node = Rcom::Node.new('local').connect
8
+ service = Rcom::Rpc.new(node: node, service: 'auth')
9
+
10
+ service.subscribe do |request|
11
+ request.on('user.key') do |params|
12
+ request.reply = 'xxxccc'
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['LOCAL'] = 'redis://localhost'
3
+
4
+ require 'rcom'
5
+ require 'json'
6
+
7
+ message = {
8
+ method: 'user.key',
9
+ args: 1
10
+ }
11
+ node = Rcom::Node.new('local').connect
12
+ service = Rcom::Rpc.new(node: node, service: 'auth')
13
+ p service.request(message)
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['LOCAL'] = 'redis://localhost'
3
+
4
+ require 'rcom'
5
+ require 'json'
6
+
7
+ node = Rcom::Node.new('local').connect
8
+ messages = Rcom::Task.new(node: node, queue: 'messages')
9
+
10
+ messages.subscribe do |message|
11
+ sleep 1
12
+ p message
13
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['LOCAL'] = 'redis://localhost'
3
+
4
+ require 'rcom'
5
+ require 'json'
6
+
7
+ message = {
8
+ id: 1,
9
+ key: 'xxxccc'
10
+ }
11
+ node = Rcom::Node.new('local').connect
12
+ messages = Rcom::Task.new(node: node, queue: 'messages')
13
+ messages.publish(message)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['local'] = 'redis://localhost'
3
+
4
+ require 'rcom'
5
+ require 'json'
6
+
7
+ message = {
8
+ id: 1,
9
+ key: 'xxxccc'
10
+ }
11
+ node = Rcom::Node.new('local').connect
12
+ topic = Rcom::Topic.new(node: node, key: 'users')
13
+
14
+ topic.publish(message)
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['local'] = 'redis://localhost'
3
+
4
+ require 'rcom'
5
+ require 'json'
6
+
7
+ node = Rcom::Node.new('local').connect
8
+ topic = Rcom::Topic.new(node: node, key: 'users')
9
+
10
+ topic.subscribe do |message|
11
+ p message
12
+ end
@@ -0,0 +1,3 @@
1
+ require 'rcom'
2
+ require 'minitest/autorun'
3
+ require 'minitest/pride'
@@ -0,0 +1,23 @@
1
+ require_relative './_init'
2
+
3
+ describe 'Node' do
4
+ before do
5
+ ENV['LOCAL'] = 'redis://127.0.0.1'
6
+ @local = Rcom::Node.new('local')
7
+ end
8
+
9
+ it 'represents a Redis connection to a node' do
10
+ @local.must_be_instance_of Rcom::Node
11
+ end
12
+
13
+ it 'cannot represent a node not present in ENV' do
14
+ lambda do
15
+ Rcom::Node.new('mail')
16
+ end.must_raise ArgumentError
17
+ end
18
+
19
+ it 'can connect to the Redis node' do
20
+ connection = @local.connect
21
+ connection.must_be_instance_of Redis
22
+ end
23
+ end
@@ -0,0 +1,37 @@
1
+ require_relative './_init'
2
+
3
+ describe 'Rpc' do
4
+ before do
5
+ ENV['LOCAL'] = 'redis://localhost'
6
+ @node = Rcom::Node.new('local').connect
7
+ end
8
+
9
+ it 'represents a remote procedure call' do
10
+ service = Rcom::Rpc.new(node: @node, service: 'auth')
11
+ service.must_be_instance_of Rcom::Rpc
12
+ end
13
+
14
+ it 'works in a request/response scenario' do
15
+ user_key = 'xxxccc'
16
+ response = ''
17
+ publisher = 'bundle exec ruby test/bin/rpc_publisher.rb'
18
+ consumer = 'bundle exec ruby test/bin/rpc_consumer.rb'
19
+
20
+ # Start the consumer, wait for it to be up,
21
+ # start the publisher and wait for the message
22
+ # on the consumer side. Process, then kill
23
+ # the long-running consumer.
24
+
25
+ consumer_pid = spawn(consumer)
26
+ sleep 1
27
+
28
+ Open3.popen3(publisher) do |stdin, stdout, stderr, wait_thr|
29
+ response = stdout.gets
30
+ Process.kill('INT', wait_thr.pid)
31
+ end
32
+
33
+ Process.kill('INT', consumer_pid)
34
+
35
+ eval(response.chomp).must_equal user_key
36
+ end
37
+ end
@@ -0,0 +1,36 @@
1
+ require_relative './_init'
2
+
3
+ describe 'Task' do
4
+ # Doesn't stop processes
5
+ before do
6
+ ENV['LOCAL'] = 'redis://localhost'
7
+ @node = Rcom::Node.new('local').connect
8
+ end
9
+
10
+ it 'represents a Task' do
11
+ task = Rcom::Task.new(node: @node, queue: 'messages')
12
+ task.must_be_instance_of Rcom::Task
13
+ end
14
+
15
+ it 'works in a pub/consumer scenario' do
16
+ message = {
17
+ id: 1,
18
+ key: 'xxxccc'
19
+ }
20
+ completed_job = ''
21
+ publisher = 'bundle exec ruby test/bin/task_publisher.rb'
22
+ consumer = 'bundle exec ruby test/bin/task_consumer.rb'
23
+
24
+ # Start the consumer, wait for it to be up,
25
+ # start the publisher and wait for the message
26
+ # on the consumer side. Process, then kill
27
+ # the long-running consumer.
28
+ Open3.popen3(consumer) do |stdin, stdout, stderr, wait_thr|
29
+ spawn(publisher)
30
+ completed_job = stdout.gets
31
+ Process.kill('INT', wait_thr.pid)
32
+ end
33
+
34
+ eval(completed_job.chomp).must_equal message
35
+ end
36
+ end
@@ -0,0 +1,37 @@
1
+ require_relative './_init'
2
+
3
+ describe 'Topic' do
4
+ before do
5
+ ENV['LOCAL'] = 'redis://localhost'
6
+ @node = Rcom::Node.new('local').connect
7
+ end
8
+
9
+ it 'represents a Topic' do
10
+ topic = Rcom::Topic.new(node: @node, key: 'users')
11
+ topic.must_be_instance_of Rcom::Topic
12
+ end
13
+
14
+ it 'works in a pub/sub scenario' do
15
+ message = {
16
+ id: 1,
17
+ key: 'xxxccc'
18
+ }
19
+ read_message = ''
20
+ publisher = 'bundle exec ruby test/bin/topic_publisher.rb'
21
+ subscriber = 'bundle exec ruby test/bin/topic_subscriber.rb'
22
+
23
+ # Start the subscriber, wait for it to be up,
24
+ # start the publisher and wait for the message
25
+ # on the subscriber side. Then kill
26
+ # the long-running subscriber.
27
+ Open3.popen3(subscriber) do |stdin, stdout, stderr, wait_thr|
28
+ sleep 1
29
+ spawn(publisher)
30
+ read_message = stdout.gets
31
+ Process.kill('INT', wait_thr.pid)
32
+ end
33
+
34
+ output = eval read_message.chomp
35
+ output.must_equal message
36
+ end
37
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rcom
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Marco Lisci
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: yard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: redis
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.1.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 3.1.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: msgpack
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.5.9
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.5.9
83
+ description: 'Redis inter-service messaging: request-response, publish-subscribe and
84
+ tasks.'
85
+ email:
86
+ - info@badshark.io
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - lib/rcom.rb
97
+ - lib/rcom/node.rb
98
+ - lib/rcom/rpc.rb
99
+ - lib/rcom/task.rb
100
+ - lib/rcom/topic.rb
101
+ - lib/rcom/version.rb
102
+ - rcom.gemspec
103
+ - test/bin/rpc_consumer.rb
104
+ - test/bin/rpc_publisher.rb
105
+ - test/bin/task_consumer.rb
106
+ - test/bin/task_publisher.rb
107
+ - test/bin/topic_publisher.rb
108
+ - test/bin/topic_subscriber.rb
109
+ - test/spec/_init.rb
110
+ - test/spec/node_spec.rb
111
+ - test/spec/rpc_spec.rb
112
+ - test/spec/task_spec.rb
113
+ - test/spec/topic_spec.rb
114
+ homepage: https://github.com/badshark/rcom
115
+ licenses:
116
+ - MIT
117
+ metadata: {}
118
+ post_install_message:
119
+ rdoc_options: []
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ required_rubygems_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ requirements: []
133
+ rubyforge_project:
134
+ rubygems_version: 2.2.2
135
+ signing_key:
136
+ specification_version: 4
137
+ summary: Redis inter-service messaging.
138
+ test_files:
139
+ - test/bin/rpc_consumer.rb
140
+ - test/bin/rpc_publisher.rb
141
+ - test/bin/task_consumer.rb
142
+ - test/bin/task_publisher.rb
143
+ - test/bin/topic_publisher.rb
144
+ - test/bin/topic_subscriber.rb
145
+ - test/spec/_init.rb
146
+ - test/spec/node_spec.rb
147
+ - test/spec/rpc_spec.rb
148
+ - test/spec/task_spec.rb
149
+ - test/spec/topic_spec.rb
150
+ has_rdoc: