zero-moo 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f0bab789674475cb28264d22f2a00921e0c67357
4
+ data.tar.gz: 9c8bb11d05b8b355c666a5021546671aeac77075
5
+ SHA512:
6
+ metadata.gz: 81ac54f2f9ccf32ad7d46b36624ed52b25ad41e855e0fa42281851ebf6667bfa614af8885f53cef9d99837eee60cd674d71999b4d401ff3750984b84dd3ea7ed
7
+ data.tar.gz: 32a28e22a66cad1ef50b7aa2679c75f6bf3b86fdc358d0172e2385709dadd57ac08b827fba63964bc5ff863447718fcc651e4babadcd23c4992778cc41b78572
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'pry'
4
+ gem 'ffi-rzmq-core', path: "/tmp/ffi-rzmq-core"
5
+
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Tim Förster
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,53 @@
1
+ # Zero::Moo
2
+
3
+ An easy to use publisher - subscriber communication util.
4
+
5
+ *It is currently hard under development.
6
+ There is no recovery after server restart*
7
+
8
+ Unit tests will also follow.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'zero-moo'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install zero-moo
25
+
26
+ ## Usage
27
+
28
+ **Add a subscriber: **
29
+
30
+ ```ruby
31
+ require 'zero/moo/subscriber'
32
+ s = Zero::Moo::Subscriber address: '127.0.0.1:64000'
33
+ s.on_receive{|message| puts message}
34
+ ```
35
+
36
+ **Add a publisher: **
37
+
38
+ ```ruby
39
+ require 'zero/moo/publisher'
40
+ p = Zero::Moo::Publisher address: '127.0.0.1:64000'
41
+ p.push! "moo"
42
+ ```
43
+
44
+
45
+ ## Contributing
46
+
47
+ Bug reports and pull requests are welcome on GitHub at https://github.com/timmyArch/zero-moo.
48
+
49
+
50
+ ## License
51
+
52
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
53
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "zero/moo"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/lib/zero/moo.rb ADDED
@@ -0,0 +1,11 @@
1
+ require "zero/moo/version"
2
+ require "zero/moo/logger"
3
+ require 'ffi-rzmq'
4
+
5
+ module Zero
6
+ module Moo
7
+
8
+ class Error < StandardError; end
9
+
10
+ end
11
+ end
@@ -0,0 +1,79 @@
1
+ require 'zero/moo'
2
+ require 'ffi-rzmq'
3
+
4
+ Thread.abort_on_exception
5
+
6
+ module Zero
7
+ module Moo
8
+
9
+ class Communicator
10
+
11
+ class Error < Zero::Moo::Error; end
12
+ class ContextError < Error; end
13
+ class ArgumentError < Error; end
14
+
15
+ attr_reader :context
16
+
17
+ ##
18
+ # Instanziate ZeroMQ context.
19
+ #
20
+ # @params type [Fixnum] ZMQ::Context type
21
+ #
22
+ def initialize type: ZMQ::REQ
23
+ logger.debug "Creating ZMQ::Context type: #{type.inspect}"
24
+ @context = ZMQ::Context.create(type)
25
+ raise ContextError, "Zmq context couldn't created." unless @context
26
+ logger.debug "Add finalizer for context termination."
27
+ ObjectSpace.define_finalizer(self,
28
+ proc{self.context.terminate if self.context})
29
+ end
30
+
31
+ protected
32
+
33
+ ##
34
+ # Get logger instance.
35
+ #
36
+ # @return [Zero::Moo::Logger]
37
+ #
38
+ def logger
39
+ unless @logger
40
+ @logger = Logger.dup
41
+ @logger.instance_variable_set(:@progname,
42
+ "#{self.class.name} ##{self.__id__}")
43
+ end
44
+ @logger
45
+ end
46
+
47
+ ##
48
+ # Checking return codes.
49
+ #
50
+ # @param rc [Fixnum] Return code
51
+ # @params raize [Class]
52
+ #
53
+ # @return [TrueClass, FalseClass]
54
+ # If true, an error has ocoured.
55
+ #
56
+ def error?(rc, raize: nil)
57
+ if raize and raize.is_a?(Class) and
58
+ not raize.ancestors.include?(StandardError)
59
+ raise ArgumentError, ":raize must contain a raisable class"
60
+ end
61
+ logger.debug "Checking error code ..."
62
+ if ZMQ::Util.resultcode_ok?(rc)
63
+ false
64
+ else
65
+ err = <<-ERR.split.join(' ')
66
+ Operation failed, errno [#{ZMQ::Util.errno}]
67
+ description [#{ZMQ::Util.error_string}]
68
+ ERR
69
+ logger.error err
70
+ caller(1).each { |callstack| logger.error(callstack) }
71
+ raise raize, err if raize
72
+ true
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+ end
@@ -0,0 +1,10 @@
1
+ require 'syslog/logger'
2
+
3
+ module Zero
4
+ module Moo
5
+
6
+ #Logger = Syslog::Logger.new("Zero::Moo")
7
+ Logger = Logger.new(STDOUT)
8
+
9
+ end
10
+ end
@@ -0,0 +1,107 @@
1
+ require 'zero/moo/communicator'
2
+
3
+ module Zero
4
+ module Moo
5
+
6
+ class Publisher < Communicator
7
+
8
+ class Error < Communicator::Error; end
9
+ class MissingAddressError < Error; end
10
+ class InvalidAddressError < Error; end
11
+ class SocketOptionError < Error; end
12
+ class SocketShutdownError < Error; end
13
+ class MessageError < Error; end
14
+ class BindError < Error; end
15
+
16
+ attr_reader :address, :thread, :socket
17
+ private :thread, :socket
18
+
19
+ ##
20
+ # Get publishing instance.
21
+ #
22
+ # @param address [String]
23
+ #
24
+ def initialize **kwargs
25
+ @address = kwargs.delete(:address)
26
+ kwargs[:type] = 1
27
+ raise MissingAddressError,
28
+ ":address for bind was not given" unless @address
29
+ validate_address
30
+ validate_port
31
+ super **kwargs
32
+ end
33
+
34
+ ##
35
+ # Push a message to all subscribers.
36
+ #
37
+ def push! message
38
+ bind! unless socket
39
+ error? socket.send_string(message), raize: MessageError
40
+ message
41
+ end
42
+
43
+ private
44
+
45
+ ##
46
+ # Bind publisher to address.
47
+ #
48
+ # @return [void]
49
+ #
50
+ def bind!
51
+ @socket = context.socket(ZMQ::PUSH)
52
+ error? @socket.setsockopt(ZMQ::LINGER, 1), raize: SocketOptionError
53
+ error? @socket.bind("tcp://#{address}"), raize: BindError
54
+ end
55
+
56
+
57
+ ##
58
+ # Closing the publisher socket.
59
+ #
60
+ # @return [void]
61
+ #
62
+ def stop!
63
+ if socket.respond_to? :close
64
+ error? socket.close, raize: SocketShutdownError
65
+ end
66
+ if thread.instance_of? Thread
67
+ thread.kill
68
+ end
69
+ @thread = nil
70
+ end
71
+
72
+ protected
73
+
74
+ ##
75
+ # Validating Address/Host part of given address.
76
+ #
77
+ # @return [void]
78
+ #
79
+ def validate_address
80
+ logger.debug "Validating address: #{@address.inspect}"
81
+ address = @address.to_s[/[^:]+/]
82
+ ip = IPAddr.new(address) rescue nil
83
+ Socket.gethostbyname(address) unless ip
84
+ rescue SocketError => e
85
+ raise InvalidAddressError,
86
+ "Address: #{@address.inspect} is invalid. - #{e.message}"
87
+ end
88
+
89
+ ##
90
+ # Validating port section in @address
91
+ #
92
+ # @return [void]
93
+ #
94
+ def validate_port
95
+ logger.debug "Validating port: #{@address.inspect}"
96
+ port = @address.to_s[/[^:]+$/].to_s[/\d+/]
97
+ raise InvalidAddressError, "Missing port in #{address}" if port.nil?
98
+ unless (1024..65535).include? port.to_i
99
+ raise InvalidAddressError,
100
+ "Out of range. Port must be between 1024 and 65535"
101
+ end
102
+ end
103
+
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,75 @@
1
+ require 'zero/moo/publisher'
2
+
3
+ module Zero
4
+ module Moo
5
+
6
+ class Subscriber < Publisher
7
+
8
+ class Error < Communicator::Error; end
9
+ class MissingAddressError < Error; end
10
+ class InvalidAddressError < Error; end
11
+ class SocketOptionError < Error; end
12
+ class SocketShutdownError < Error; end
13
+ class MessageError < Error; end
14
+ class ConnectError < Error; end
15
+
16
+ undef :bind!
17
+ undef :push!
18
+
19
+ attr_reader :receivers
20
+ private :receivers, :stop!
21
+
22
+ ##
23
+ # Add callbacks. The block will called with one
24
+ # argument. The message.
25
+ #
26
+ # @yield [message]
27
+ # @yieldparam message [String]
28
+ #
29
+ # @return [void]
30
+ #
31
+ def on_receive &block
32
+ listen! unless thread.instance_of? Thread
33
+ unless @receivers
34
+ ObjectSpace.define_finalizer(self, proc{ stop! })
35
+ end
36
+ @receivers ||= []
37
+ @receivers << block
38
+ end
39
+
40
+ private
41
+
42
+ ##
43
+ # Bind listener.
44
+ #
45
+ # @return [void]
46
+ #
47
+ def listen!
48
+ @thread = Thread.new do
49
+ @socket = context.socket(ZMQ::PULL)
50
+ error? socket.setsockopt(ZMQ::LINGER, 1), raize: SocketOptionError
51
+ error? socket.connect("tcp://#{address}"), raize: ConnectError
52
+ loop do
53
+ message = ''
54
+ error? socket.recv_string(message), raize: MessageError
55
+ handle_callbacks message
56
+ end
57
+ end
58
+ end
59
+
60
+ ##
61
+ # Iterate over all callbacks and
62
+ # call them with given message.
63
+ #
64
+ # @return [void]
65
+ #
66
+ def handle_callbacks message
67
+ receivers.to_a.each do |block|
68
+ block.call message
69
+ end
70
+ end
71
+
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,5 @@
1
+ module Zero
2
+ module Moo
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
data/zero-moo.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'zero/moo/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "zero-moo"
8
+ spec.version = Zero::Moo::VERSION
9
+ spec.authors = ["Tim Förster"]
10
+ spec.email = ["github@mailserver.1n3t.de"]
11
+
12
+ spec.summary = %q{ZMQ based communication util}
13
+ spec.homepage = "https://github.com/timmyArch/zero-moo"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.10"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec"
24
+
25
+ spec.add_dependency "ffi-rzmq", '2.0.4'
26
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zero-moo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tim Förster
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-08-16 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.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
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: ffi-rzmq
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 2.0.4
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 2.0.4
69
+ description:
70
+ email:
71
+ - github@mailserver.1n3t.de
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - bin/console
84
+ - bin/setup
85
+ - lib/zero/moo.rb
86
+ - lib/zero/moo/communicator.rb
87
+ - lib/zero/moo/logger.rb
88
+ - lib/zero/moo/publisher.rb
89
+ - lib/zero/moo/subscriber.rb
90
+ - lib/zero/moo/version.rb
91
+ - zero-moo.gemspec
92
+ homepage: https://github.com/timmyArch/zero-moo
93
+ licenses:
94
+ - MIT
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.4.5
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: ZMQ based communication util
116
+ test_files: []