miu 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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