miu 0.1.0 → 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.
Files changed (54) hide show
  1. data/.rspec +2 -0
  2. data/.travis.yml +21 -0
  3. data/Gemfile +7 -0
  4. data/Guardfile +8 -0
  5. data/README.md +19 -2
  6. data/Rakefile +3 -0
  7. data/bin/miu +0 -2
  8. data/lib/miu/cli.rb +49 -24
  9. data/lib/miu/cli_base.rb +7 -0
  10. data/lib/miu/command.rb +19 -12
  11. data/lib/miu/errors.rb +22 -0
  12. data/lib/miu/forwarder.rb +54 -0
  13. data/lib/miu/logger.rb +11 -5
  14. data/lib/miu/messages/base.rb +14 -4
  15. data/lib/miu/messages/text.rb +4 -2
  16. data/lib/miu/messages/unknown.rb +11 -0
  17. data/lib/miu/messages.rb +17 -2
  18. data/lib/miu/{plugin.rb → node.rb} +10 -9
  19. data/lib/miu/nodes/.gitkeep +0 -0
  20. data/lib/miu/{plugins.rb → nodes.rb} +1 -1
  21. data/lib/miu/packet.rb +11 -18
  22. data/lib/miu/proxy.rb +57 -0
  23. data/lib/miu/publishable.rb +18 -0
  24. data/lib/miu/publisher.rb +16 -22
  25. data/lib/miu/resources/base.rb +2 -2
  26. data/lib/miu/resources/content.rb +1 -1
  27. data/lib/miu/resources/network.rb +1 -1
  28. data/lib/miu/resources/room.rb +1 -1
  29. data/lib/miu/resources/text_content.rb +3 -5
  30. data/lib/miu/resources/user.rb +1 -1
  31. data/lib/miu/server.rb +10 -25
  32. data/lib/miu/socket.rb +100 -28
  33. data/lib/miu/subscribable.rb +44 -0
  34. data/lib/miu/subscriber.rb +17 -48
  35. data/lib/miu/utility.rb +13 -8
  36. data/lib/miu/version.rb +1 -1
  37. data/lib/miu.rb +42 -25
  38. data/miu.gemspec +6 -4
  39. data/spec/miu/command_spec.rb +26 -0
  40. data/spec/miu/logger_spec.rb +39 -0
  41. data/spec/miu/messages/base_spec.rb +43 -0
  42. data/spec/miu/messages/text_spec.rb +35 -0
  43. data/spec/miu/node_spec.rb +31 -0
  44. data/spec/miu/packet_spec.rb +47 -0
  45. data/spec/miu/publishable_spec.rb +24 -0
  46. data/spec/miu/publisher_spec.rb +36 -0
  47. data/spec/miu/subscribable_spec.rb +44 -0
  48. data/spec/miu/subscriber_spec.rb +36 -0
  49. data/spec/miu/utility_spec.rb +60 -0
  50. data/spec/miu_spec.rb +23 -0
  51. data/spec/spec_helper.rb +15 -0
  52. metadata +86 -19
  53. data/lib/miu/plugins/null.rb +0 -59
  54. data/lib/templates/Gemfile +0 -8
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,21 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+
7
+ before_install:
8
+ - sudo apt-get update -qq
9
+ - sudo apt-get install -qq libzmq3-dev
10
+
11
+ branches:
12
+ only:
13
+ - master
14
+
15
+ notifications:
16
+ irc:
17
+ channels:
18
+ - "irc.freenode.net#miu-dev"
19
+ use_notice: true
20
+ skip_join: true
21
+
data/Gemfile CHANGED
@@ -1,4 +1,11 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ group :development do
4
+ gem 'guard-rspec'
5
+ gem 'rb-inotify', :require => false
6
+ gem 'rb-fsevent', :require => false
7
+ gem 'rb-fchange', :require => false
8
+ end
9
+
3
10
  # Specify your gem's dependencies in miu.gemspec
4
11
  gemspec
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Miu
1
+ # Miu [![Build Status](https://travis-ci.org/yuijo/miu.png?branch=master)](https://travis-ci.org/yuijo/miu)
2
2
 
3
3
  TODO: Write a gem description
4
4
 
@@ -18,7 +18,24 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
- TODO: Write usage instructions here
21
+ ### Setup
22
+
23
+ ```ruby
24
+ mkdir miu
25
+ cd miu
26
+ miu init
27
+ ```
28
+
29
+ ### Start
30
+
31
+ ```ruby
32
+ miu supervise
33
+ ```
34
+
35
+ ### Quit
36
+ ```ruby
37
+ miu terminate
38
+ ```
22
39
 
23
40
  ## Contributing
24
41
 
data/Rakefile CHANGED
@@ -1 +1,4 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+ RSpec::Core::RakeTask.new(:spec)
4
+ task :default => :spec
data/bin/miu CHANGED
@@ -1,6 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
  # -*- encoding: utf-8 -*-
3
- require 'bundler'
4
- Bundler.require(:default)
5
3
  require 'miu/cli'
6
4
  Miu::CLI.start
data/lib/miu/cli.rb CHANGED
@@ -1,11 +1,9 @@
1
1
  require 'miu'
2
+ require 'miu/cli_base'
2
3
  require 'thor'
3
4
 
4
5
  module Miu
5
- class CLI < ::Thor
6
- include ::Thor::Actions
7
- add_runtime_options!
8
-
6
+ class CLI < CLIBase
9
7
  class << self
10
8
  def source_root
11
9
  File.expand_path('../../templates', __FILE__)
@@ -17,7 +15,6 @@ module Miu
17
15
  end
18
16
 
19
17
  map ['--version', '-v'] => :version
20
-
21
18
  desc 'version', 'Show version'
22
19
  def version
23
20
  say "Miu #{Miu::VERSION}"
@@ -25,7 +22,6 @@ module Miu
25
22
 
26
23
  desc 'init', 'Generates a miu configuration files'
27
24
  def init
28
- copy_file 'Gemfile'
29
25
  inside 'config' do
30
26
  template 'miu.god'
31
27
  end
@@ -33,49 +29,78 @@ module Miu
33
29
  empty_directory 'tmp/pids'
34
30
  end
35
31
 
36
- desc 'list', 'Lists plugins'
32
+ desc 'list', 'Lists nodes'
37
33
  def list
38
- require 'miu/plugins'
39
- table = Miu.plugins.map { |k, v| [k, "# #{v}" ] }
40
- say 'Plugins:'
34
+ table = Miu.nodes.map do |name, node|
35
+ [name, "# #{node.description}"]
36
+ end
37
+ say 'Nodes:'
41
38
  print_table table, :indent => 2, :truncate => true
42
- say
43
39
  end
44
40
 
45
- desc 'start', 'Start miu'
41
+ desc 'start', 'Start miu server'
46
42
  option 'pub-host', :type => :string, :default => '127.0.0.1', :desc => 'pub host'
47
43
  option 'pub-port', :type => :numeric, :default => Miu.default_pub_port, :desc => 'pub port'
48
44
  option 'sub-host', :type => :string, :default => '127.0.0.1', :desc => 'sub host'
49
45
  option 'sub-port', :type => :numeric, :default => Miu.default_sub_port, :desc => 'sub port'
46
+ option 'bridge-host', :type => :string, :default => '127.0.0.1', :desc => 'bridge host'
47
+ option 'bridge-port', :type => :numeric, :desc => 'bridge port'
50
48
  option 'verbose', :type => :boolean, :default => false, :desc => 'verbose output', :aliases => '-V'
51
49
  def start
52
- server = Miu::Server.new Miu::Utility.optionalize_keys(options)
50
+ server = Miu::Server.new Miu::Utility.optionify_keys(options)
53
51
  server.run
54
52
  end
55
53
 
56
- desc 'cat tag [body]', 'Nyan'
54
+ desc 'cat TAG ROOM TEXT', 'Okaka kakeyoune'
57
55
  option 'host', :type => :string, :default => '127.0.0.1', :desc => 'miu sub host'
58
56
  option 'port', :type => :numeric, :default => Miu.default_sub_port, :desc => 'miu sub port'
59
- def cat(tag, body = nil)
57
+ option 'network', :type => :string, :default => 'debug', :desc => 'miu network name'
58
+ def cat(tag, room, text)
59
+ require 'miu/messages'
60
60
  require 'json'
61
61
  publisher = Miu::Publisher.new :host => options[:host], :port => options[:port]
62
- publisher.connect
63
- body = JSON.load(body) rescue body
64
- publisher.send tag, body
62
+ message = Miu::Messages::Text.new do |m|
63
+ m.network.name = options[:network]
64
+ m.content.tap do |c|
65
+ c.room.name = room
66
+ c.text = text
67
+ end
68
+ end
69
+
70
+ packet = publisher.write tag, message
71
+ Miu::Logger.info packet.inspect
72
+ rescue => e
73
+ Miu::Logger.exception e
65
74
  end
66
75
 
67
- desc 'supervise', 'Supervise miu and plugins'
76
+ desc 'supervise', 'Supervise miu and nodes'
68
77
  def supervise(*args)
69
- require 'god'
70
- args.unshift "bundle exec god -c #{Miu.default_god_config}"
71
- run args.join(' ')
78
+ args.unshift "-c #{Miu.default_god_config}"
79
+ run_god *args
72
80
  end
73
81
 
74
- desc 'god', 'Miu is a god'
82
+ desc 'terminate', 'Terminate miu and nodes'
83
+ def terminate(*args)
84
+ args.unshift "-p #{Miu.default_god_port} terminate"
85
+ run_god *args
86
+ end
87
+
88
+ desc 'god [ARGS]', 'Miu is a god'
75
89
  def god(*args)
90
+ args.unshift "-p #{Miu.default_god_port}"
91
+ run_god *args
92
+ end
93
+
94
+ private
95
+
96
+ def run_god(*args)
76
97
  require 'god'
77
- args.unshift "bundle exec god -p #{Miu.default_god_port}"
98
+ args.unshift 'god'
78
99
  run args.join(' ')
79
100
  end
80
101
  end
81
102
  end
103
+
104
+ # load miu nodes
105
+ Miu.load_nodes
106
+
@@ -0,0 +1,7 @@
1
+ require 'thor'
2
+
3
+ module Miu
4
+ class CLIBase < ::Thor
5
+ include ::Thor::Actions
6
+ end
7
+ end
data/lib/miu/command.rb CHANGED
@@ -1,16 +1,16 @@
1
1
  require 'miu'
2
+ require 'miu/cli_base'
2
3
 
3
4
  module Miu
4
5
  class Command
5
- def self.new(name, plugin, options = {}, &block)
6
- require 'thor'
7
- Class.new ::Thor do
8
- include ::Thor::Actions
9
- add_runtime_options!
6
+ def self.new(name, node, options = {}, &block)
7
+ Class.new Miu::CLIBase do
8
+ attr_accessor :node
9
+ @node = node
10
10
 
11
11
  class << self
12
12
  def source_root
13
- Miu.find_root('Gemfile', plugin.called_from)
13
+ @node.spec.full_gem_path rescue nil
14
14
  end
15
15
 
16
16
  def destination_root
@@ -21,14 +21,21 @@ module Miu
21
21
  super task, namespace, subcommand || options.fetch(:subcommand, true)
22
22
  end
23
23
 
24
- def add_miu_pub_options!
25
- option 'miu-pub-host', :type => :string, :default => '127.0.0.1', :desc => 'miu pub host'
26
- option 'miu-pub-port', :type => :numeric, :default => Miu.default_sub_port, :desc => 'miu pub port'
24
+ def add_miu_pub_options(name)
25
+ option 'pub-host', :type => :string, :default => '127.0.0.1', :desc => 'miu pub host'
26
+ option 'pub-port', :type => :numeric, :default => Miu.default_sub_port, :desc => 'miu pub port'
27
+ option 'pub-tag', :type => :string, :default => "miu.input.#{name}.", :desc => 'miu pub tag'
27
28
  end
28
29
 
29
- def add_miu_sub_options!
30
- option 'miu-sub-host', :type => :string, :default => '127.0.0.1', :desc => 'miu sub host'
31
- option 'miu-sub-port', :type => :numeric, :default => Miu.default_pub_port, :desc => 'miu sub port'
30
+ def add_miu_sub_options(name)
31
+ option 'sub-host', :type => :string, :default => '127.0.0.1', :desc => 'miu sub host'
32
+ option 'sub-port', :type => :numeric, :default => Miu.default_pub_port, :desc => 'miu sub port'
33
+ option 'sub-tag', :type => :string, :default => "miu.output.#{name}.", :desc => 'miu sub tag'
34
+ end
35
+
36
+ def add_miu_pub_sub_options(name)
37
+ add_miu_pub_options name
38
+ add_miu_sub_options name
32
39
  end
33
40
  end
34
41
 
data/lib/miu/errors.rb ADDED
@@ -0,0 +1,22 @@
1
+ module Miu
2
+ class Error < StandardError
3
+ end
4
+
5
+ class WrappedError < Error
6
+ attr_accessor :error
7
+
8
+ def initialize(error)
9
+ @error = error
10
+ super "#{@error.class}: #{@error.to_s}"
11
+ end
12
+ end
13
+
14
+ class InvalidTypeError < Error
15
+ end
16
+
17
+ class PacketLoadError < WrappedError
18
+ end
19
+
20
+ class MessageLoadError < WrappedError
21
+ end
22
+ end
@@ -0,0 +1,54 @@
1
+ require 'miu/socket'
2
+ require 'miu/proxy'
3
+ require 'ffi-rzmq'
4
+
5
+ module Miu
6
+ class Forwarder
7
+ def initialize(options = {})
8
+ @pub = pub_socket_class.new
9
+ @pub.bind Miu::Socket.build_address(options[:pub_host], options[:pub_port])
10
+
11
+ @sub = sub_socket_class.new
12
+ @sub.bind Miu::Socket.build_address(options[:sub_host], options[:sub_port])
13
+ @sub.subscribe ''
14
+
15
+ if options[:bridge_port]
16
+ @bridge = sub_socket_class.new
17
+ @bridge.connect Miu::Socket.build_address(options[:bridge_host], options[:bridge_port])
18
+ @bridge.subscribe ''
19
+ end
20
+ end
21
+
22
+ def close
23
+ @bridge.close if @bridge
24
+ @sub.close
25
+ @pub.close
26
+ end
27
+
28
+ def run
29
+ frontends = [@sub, @bridge].compact
30
+ backends = [@pub]
31
+
32
+ proxy = Proxy.new frontends, backends
33
+ proxy.run
34
+ end
35
+
36
+ private
37
+
38
+ def pub_socket_class
39
+ if ::ZMQ::LibZMQ.version3?
40
+ XPubSocket
41
+ else
42
+ PubSocket
43
+ end
44
+ end
45
+
46
+ def sub_socket_class
47
+ if ::ZMQ::LibZMQ.version3?
48
+ XSubSocket
49
+ else
50
+ SubSocket
51
+ end
52
+ end
53
+ end
54
+ end
data/lib/miu/logger.rb CHANGED
@@ -5,19 +5,23 @@ module Miu
5
5
  module_function
6
6
 
7
7
  %w(debug info warn error fatal).each do |name|
8
- instance_eval <<-EOS
8
+ eval <<-EOS
9
9
  def #{name}(msg)
10
10
  Miu.logger.#{name}(msg) if Miu.logger
11
11
  end
12
12
  EOS
13
13
  end
14
14
 
15
- def exception(msg, ex)
16
- error %(#{msg}\n#{format_exception(ex)})
15
+ def exception(*args)
16
+ ex = args.pop
17
+ error [*args, format_exception(ex)].join("\n")
17
18
  end
18
19
 
19
20
  def format_exception(ex)
20
- %(#{ex.class}: #{ex.to_s}\n#{ex.backtrace.join("\n")})
21
+ rows = []
22
+ rows << "#{ex.class}: #{ex.to_s}"
23
+ rows += ex.backtrace.map { |s| "\tfrom #{s}" }
24
+ rows.join("\n")
21
25
  end
22
26
 
23
27
  def formatter(severity, time, progname, msg)
@@ -26,9 +30,11 @@ module Miu
26
30
  end
27
31
 
28
32
  class << self
33
+ attr_accessor :default_logger
29
34
  attr_accessor :logger
30
35
  end
31
- self.logger = ::Logger.new(STDERR)
36
+ self.default_logger = ::Logger.new(STDERR)
37
+ self.logger = self.default_logger
32
38
  self.logger.level = ::Logger::INFO
33
39
  self.logger.formatter = Miu::Logger.method(:formatter)
34
40
  end
@@ -1,26 +1,36 @@
1
- require 'miu/resources/network'
1
+ require 'miu/messages'
2
2
  require 'msgpack'
3
+ require 'securerandom'
3
4
 
4
5
  module Miu
5
6
  module Messages
6
7
  class Base
8
+ attr_accessor :id, :time
7
9
  attr_accessor :network, :type, :content
8
10
 
9
11
  def initialize(options = {})
10
- @network = options[:network] || Resources::Network.new(options[:network] || {})
12
+ @id = options[:id] || SecureRandom.uuid
13
+ @time = options[:time] || Time.now.to_i
14
+ @network = Miu::Utility.adapt(Resources::Network, options[:network] || {})
11
15
  @type = options[:type]
12
- @type = [@type, *Array(options[:sub_type])].compact.join('.')
13
16
  @content = options[:content]
14
17
  yield self if block_given?
15
18
  end
16
19
 
17
20
  def to_hash
18
- {:network => @network.to_hash, :type => @type, :content => @content.to_hash}
21
+ {
22
+ :network => @network.to_hash,
23
+ :type => @type,
24
+ :content => @content ? @content.to_hash : {}
25
+ }
19
26
  end
20
27
 
21
28
  def to_msgpack(*args)
22
29
  to_hash.to_msgpack(*args)
23
30
  end
24
31
  end
32
+
33
+ class Unknown < Base
34
+ end
25
35
  end
26
36
  end
@@ -1,14 +1,16 @@
1
+ require 'miu/resources'
1
2
  require 'miu/messages/base'
2
- require 'miu/resources/text_content'
3
3
 
4
4
  module Miu
5
5
  module Messages
6
6
  class Text < Base
7
7
  def initialize(options = {})
8
8
  options[:type] ||= 'text'
9
- options[:content] ||= Resources::TextContent.new(options[:content] || {})
9
+ options[:content] = Miu::Utility.adapt(Resources::TextContent, options[:content] || {})
10
10
  super
11
11
  end
12
12
  end
13
+
14
+ register :text, Text
13
15
  end
14
16
  end
@@ -0,0 +1,11 @@
1
+ require 'miu/messages/base'
2
+
3
+ module Miu
4
+ module Messages
5
+ class Unknown < Base
6
+ def initialize(value)
7
+ super({:type => 'unknown', :content => value})
8
+ end
9
+ end
10
+ end
11
+ end
data/lib/miu/messages.rb CHANGED
@@ -1,6 +1,21 @@
1
1
  module Miu
2
2
  module Messages
3
- autoload :Base, 'miu/messages/base'
4
- autoload :Text, 'miu/messages/text'
3
+ class << self
4
+ def types
5
+ @types ||= {}
6
+ end
7
+
8
+ def register(type, klass)
9
+ types[type.to_s] = klass
10
+ end
11
+
12
+ def guess(type)
13
+ types[type.to_s] || Unknown
14
+ end
15
+ end
5
16
  end
6
17
  end
18
+
19
+ require 'miu/messages/base'
20
+ require 'miu/messages/unknown'
21
+ require 'miu/messages/text'
@@ -1,26 +1,27 @@
1
1
  require 'miu'
2
2
 
3
3
  module Miu
4
- module Plugin
4
+ module Node
5
5
  def self.included(base)
6
6
  STDOUT.sync = true
7
7
  STDERR.sync = true
8
-
9
8
  base.extend ClassMethods
10
- base.called_from = begin
11
- call_stack = caller.map { |p| p.sub(/:\d+.*/, '') }
12
- File.dirname(call_stack.detect { |p| p !~ %r(miu[\w.-]*/lib/miu/plugins) })
13
- end
14
9
  end
15
10
 
16
11
  module ClassMethods
17
- attr_accessor :called_from
12
+ attr_accessor :spec
13
+
14
+ def description(value = nil)
15
+ @description ||= self.name
16
+ @description = value if value
17
+ @description
18
+ end
18
19
 
19
20
  def register(*args, &block)
20
21
  options = Miu::Utility.extract_options!(args)
21
22
  name = args.shift
22
- plugin = args.shift || self
23
- Miu.register name, plugin, options, &block
23
+ node = args.shift || self
24
+ Miu.register name, node, options, &block
24
25
  end
25
26
  end
26
27
  end
File without changes
@@ -1,4 +1,4 @@
1
1
  module Miu
2
- module Plugins
2
+ module Nodes
3
3
  end
4
4
  end
data/lib/miu/packet.rb CHANGED
@@ -1,36 +1,29 @@
1
- require 'miu'
2
- require 'securerandom'
1
+ require 'miu/errors'
3
2
  require 'msgpack'
4
3
 
5
4
  module Miu
6
5
  class Packet
7
- attr_accessor :tag, :body, :id, :time
6
+ attr_accessor :tag, :data
8
7
 
9
- def initialize(tag, body, options = {})
8
+ def initialize(tag, data)
10
9
  @tag = tag
11
- @body = body
12
- @id = options[:id] || SecureRandom.uuid
13
- @time = options[:time] || Time.now.to_i
10
+ @data = data
14
11
  end
15
12
 
16
13
  def dump
17
- data = {
18
- 'body' => @body,
19
- 'id' => @id,
20
- 'time' => @time,
21
- }
22
- [@tag, data.to_msgpack]
14
+ [@tag.to_s, @data.to_msgpack]
23
15
  end
24
16
 
25
17
  def self.load(parts)
26
- tag = parts.shift
27
- data = MessagePack.unpack(parts.shift)
28
- body = data.delete('body')
29
- new tag, body, Miu::Utility.symbolized_keys(data)
18
+ tag = parts[0]
19
+ data = MessagePack.unpack(parts[1])
20
+ new tag, data
21
+ rescue => e
22
+ raise PacketLoadError, e
30
23
  end
31
24
 
32
25
  def inspect
33
- inspection = [:tag, :body, :id, :time].map do |name|
26
+ inspection = [:tag, :data].map do |name|
34
27
  "#{name}: #{__send__(name).inspect}"
35
28
  end.join(', ')
36
29
  "#<#{self.class} #{inspection}>"
data/lib/miu/proxy.rb ADDED
@@ -0,0 +1,57 @@
1
+ require 'miu/socket'
2
+ require 'ffi-rzmq'
3
+
4
+ module Miu
5
+ class Proxy
6
+ attr_reader :frontends, :backends
7
+ attr_reader :poller
8
+
9
+ PROXY_TO = '@__proxy_to__'
10
+
11
+ def initialize(frontends, backends)
12
+ @frontends = Array(frontends).map { |s| unwrap s }
13
+ @backends = Array(backends).map { |s| unwrap s }
14
+
15
+ @frontends.each { |s| s.instance_variable_set PROXY_TO, @backends }
16
+ @backends.each { |s| s.instance_variable_set PROXY_TO, @frontends }
17
+
18
+ @poller = ::ZMQ::Poller.new
19
+ @frontends.each { |s| @poller.register_readable s }
20
+ @backends.each { |s| @poller.register_readable s }
21
+ end
22
+
23
+ def run
24
+ loop do
25
+ @poller.poll
26
+ @poller.readables.each do |from|
27
+ loop do
28
+ msg = ::ZMQ::Message.new
29
+ from.recvmsg msg
30
+ more = from.more_parts?
31
+
32
+ proxy_to = from.instance_variable_get PROXY_TO
33
+ proxy_to.each do |to|
34
+ ctrl = ::ZMQ::Message.new
35
+ ctrl.copy msg.pointer
36
+ to.sendmsg ctrl, (more ? ::ZMQ::SNDMORE : 0)
37
+ end
38
+
39
+ msg.close
40
+ break unless more
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def unwrap(socket)
49
+ case socket
50
+ when Miu::Socket
51
+ socket.socket
52
+ else
53
+ socket
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,18 @@
1
+ require 'miu/packet'
2
+
3
+ module Miu
4
+ module Publishable
5
+ def self.included(base)
6
+ base.class_eval do
7
+ def write_with_packet(tag, message)
8
+ packet = Packet.new tag, message
9
+ write_without_packet *packet.dump
10
+ packet
11
+ end
12
+
13
+ alias_method :write_without_packet, :write
14
+ alias_method :write, :write_with_packet
15
+ end
16
+ end
17
+ end
18
+ end