concurrent-ruby 0.1.1.pre.2 → 0.1.1.pre.3
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.
- data/lib/concurrent.rb +4 -3
- data/lib/concurrent/agent.rb +3 -1
- data/lib/concurrent/defer.rb +4 -4
- data/lib/concurrent/executor.rb +4 -0
- data/lib/concurrent/functions.rb +30 -30
- data/lib/concurrent/future.rb +3 -8
- data/lib/concurrent/global_thread_pool.rb +13 -0
- data/lib/concurrent/null_thread_pool.rb +22 -0
- data/lib/concurrent/promise.rb +4 -10
- data/lib/concurrent/reactor/drb_async_demux.rb +74 -0
- data/lib/concurrent/reactor/tcp_sync_demux.rb +98 -0
- data/lib/concurrent/thread_pool.rb +7 -3
- data/lib/concurrent/version.rb +1 -1
- data/md/defer.md +4 -4
- data/md/promise.md +2 -0
- data/md/thread_pool.md +27 -0
- data/spec/concurrent/agent_spec.rb +5 -1
- data/spec/concurrent/cached_thread_pool_spec.rb +13 -0
- data/spec/concurrent/defer_spec.rb +9 -23
- data/spec/concurrent/event_machine_defer_proxy_spec.rb +13 -10
- data/spec/concurrent/executor_spec.rb +38 -0
- data/spec/concurrent/functions_spec.rb +160 -0
- data/spec/concurrent/future_spec.rb +2 -19
- data/spec/concurrent/global_thread_pool_spec.rb +38 -0
- data/spec/concurrent/null_thread_pool_spec.rb +54 -0
- data/spec/concurrent/promise_spec.rb +6 -0
- data/spec/concurrent/reactor/drb_async_demux_spec.rb +12 -0
- data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +12 -0
- data/spec/concurrent/reactor_spec.rb +10 -0
- data/spec/concurrent/thread_pool_shared.rb +3 -2
- data/spec/spec_helper.rb +9 -0
- metadata +15 -4
- data/lib/concurrent/drb_async_demux.rb +0 -72
- data/lib/concurrent/tcp_sync_demux.rb +0 -96
    
        data/lib/concurrent.rb
    CHANGED
    
    | @@ -11,16 +11,17 @@ require 'concurrent/future' | |
| 11 11 | 
             
            require 'concurrent/goroutine'
         | 
| 12 12 | 
             
            require 'concurrent/promise'
         | 
| 13 13 | 
             
            require 'concurrent/obligation'
         | 
| 14 | 
            -
            require 'concurrent/reactor'
         | 
| 15 14 | 
             
            require 'concurrent/smart_mutex'
         | 
| 16 15 | 
             
            require 'concurrent/utilities'
         | 
| 17 16 |  | 
| 18 | 
            -
            require 'concurrent/ | 
| 19 | 
            -
            require 'concurrent/ | 
| 17 | 
            +
            require 'concurrent/reactor'
         | 
| 18 | 
            +
            require 'concurrent/reactor/drb_async_demux'
         | 
| 19 | 
            +
            require 'concurrent/reactor/tcp_sync_demux'
         | 
| 20 20 |  | 
| 21 21 | 
             
            require 'concurrent/thread_pool'
         | 
| 22 22 | 
             
            require 'concurrent/cached_thread_pool'
         | 
| 23 23 | 
             
            require 'concurrent/fixed_thread_pool'
         | 
| 24 | 
            +
            require 'concurrent/null_thread_pool'
         | 
| 24 25 |  | 
| 25 26 | 
             
            require 'concurrent/global_thread_pool'
         | 
| 26 27 |  | 
    
        data/lib/concurrent/agent.rb
    CHANGED
    
    | @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            require 'observer'
         | 
| 2 2 | 
             
            require 'thread'
         | 
| 3 3 |  | 
| 4 | 
            +
            require 'concurrent/global_thread_pool'
         | 
| 4 5 | 
             
            require 'concurrent/utilities'
         | 
| 5 6 |  | 
| 6 7 | 
             
            module Concurrent
         | 
| @@ -13,6 +14,7 @@ module Concurrent | |
| 13 14 | 
             
              # A good example of an agent is a shared incrementing counter, such as the score in a video game.
         | 
| 14 15 | 
             
              class Agent
         | 
| 15 16 | 
             
                include Observable
         | 
| 17 | 
            +
                include UsesGlobalThreadPool
         | 
| 16 18 |  | 
| 17 19 | 
             
                TIMEOUT = 5
         | 
| 18 20 |  | 
| @@ -26,7 +28,7 @@ module Concurrent | |
| 26 28 | 
             
                  @validator = nil
         | 
| 27 29 | 
             
                  @queue = Queue.new
         | 
| 28 30 |  | 
| 29 | 
            -
                   | 
| 31 | 
            +
                  Agent.thread_pool.post{ work }
         | 
| 30 32 | 
             
                end
         | 
| 31 33 |  | 
| 32 34 | 
             
                def value(timeout = 0) return @value; end
         | 
    
        data/lib/concurrent/defer.rb
    CHANGED
    
    | @@ -7,6 +7,7 @@ module Concurrent | |
| 7 7 | 
             
              IllegalMethodCallError = Class.new(StandardError)
         | 
| 8 8 |  | 
| 9 9 | 
             
              class Defer
         | 
| 10 | 
            +
                include UsesGlobalThreadPool
         | 
| 10 11 |  | 
| 11 12 | 
             
                def initialize(opts = {}, &block)
         | 
| 12 13 | 
             
                  operation = opts[:op] || opts[:operation]
         | 
| @@ -22,7 +23,7 @@ module Concurrent | |
| 22 23 | 
             
                  if operation.nil?
         | 
| 23 24 | 
             
                    @running = false
         | 
| 24 25 | 
             
                  else
         | 
| 25 | 
            -
                    self.go | 
| 26 | 
            +
                    self.go
         | 
| 26 27 | 
             
                  end
         | 
| 27 28 | 
             
                end
         | 
| 28 29 |  | 
| @@ -44,12 +45,11 @@ module Concurrent | |
| 44 45 | 
             
                alias_method :catch, :rescue
         | 
| 45 46 | 
             
                alias_method :on_error, :rescue
         | 
| 46 47 |  | 
| 47 | 
            -
                def go | 
| 48 | 
            +
                def go
         | 
| 48 49 | 
             
                  return nil if @running
         | 
| 49 50 | 
             
                  atomic {
         | 
| 50 | 
            -
                    thread_pool ||= $GLOBAL_THREAD_POOL
         | 
| 51 51 | 
             
                    @running = true
         | 
| 52 | 
            -
                    thread_pool.post { Thread.pass; fulfill }
         | 
| 52 | 
            +
                    Defer.thread_pool.post { Thread.pass; fulfill }
         | 
| 53 53 | 
             
                  }
         | 
| 54 54 | 
             
                  return nil
         | 
| 55 55 | 
             
                end
         | 
    
        data/lib/concurrent/executor.rb
    CHANGED
    
    | @@ -10,6 +10,8 @@ module Concurrent | |
| 10 10 | 
             
                  attr_reader :execution_interval
         | 
| 11 11 | 
             
                  attr_reader :timeout_interval
         | 
| 12 12 |  | 
| 13 | 
            +
                  protected
         | 
| 14 | 
            +
             | 
| 13 15 | 
             
                  def initialize(name, execution_interval, timeout_interval, thread)
         | 
| 14 16 | 
             
                    @name = name
         | 
| 15 17 | 
             
                    @execution_interval = execution_interval
         | 
| @@ -18,6 +20,8 @@ module Concurrent | |
| 18 20 | 
             
                    @thread[:stop] = false
         | 
| 19 21 | 
             
                  end
         | 
| 20 22 |  | 
| 23 | 
            +
                  public
         | 
| 24 | 
            +
             | 
| 21 25 | 
             
                  def status
         | 
| 22 26 | 
             
                    return @thread.status unless @thread.nil?
         | 
| 23 27 | 
             
                  end
         | 
    
        data/lib/concurrent/functions.rb
    CHANGED
    
    | @@ -12,11 +12,11 @@ module Kernel | |
| 12 12 | 
             
              end
         | 
| 13 13 | 
             
              module_function :agent
         | 
| 14 14 |  | 
| 15 | 
            -
              def post( | 
| 16 | 
            -
                if  | 
| 17 | 
            -
                  return  | 
| 15 | 
            +
              def post(object, &block)
         | 
| 16 | 
            +
                if object.respond_to?(:post)
         | 
| 17 | 
            +
                  return object.post(&block)
         | 
| 18 18 | 
             
                else
         | 
| 19 | 
            -
                   | 
| 19 | 
            +
                  raise ArgumentError.new('object does not support #post')
         | 
| 20 20 | 
             
                end
         | 
| 21 21 | 
             
              end
         | 
| 22 22 | 
             
              module_function :post
         | 
| @@ -44,53 +44,53 @@ module Kernel | |
| 44 44 |  | 
| 45 45 | 
             
              ## obligation
         | 
| 46 46 |  | 
| 47 | 
            -
              def deref( | 
| 48 | 
            -
                if  | 
| 49 | 
            -
                  return  | 
| 50 | 
            -
                elsif  | 
| 51 | 
            -
                  return  | 
| 47 | 
            +
              def deref(object, timeout = nil)
         | 
| 48 | 
            +
                if object.respond_to?(:deref)
         | 
| 49 | 
            +
                  return object.deref(timeout)
         | 
| 50 | 
            +
                elsif object.respond_to?(:value)
         | 
| 51 | 
            +
                  return object.value(timeout)
         | 
| 52 52 | 
             
                else
         | 
| 53 | 
            -
                   | 
| 53 | 
            +
                  raise ArgumentError.new('object does not support #deref')
         | 
| 54 54 | 
             
                end
         | 
| 55 55 | 
             
              end
         | 
| 56 56 | 
             
              module_function :deref
         | 
| 57 57 |  | 
| 58 | 
            -
              def pending?( | 
| 59 | 
            -
                if  | 
| 60 | 
            -
                  return  | 
| 58 | 
            +
              def pending?(object)
         | 
| 59 | 
            +
                if object.respond_to?(:pending?)
         | 
| 60 | 
            +
                  return object.pending?
         | 
| 61 61 | 
             
                else
         | 
| 62 | 
            -
                   | 
| 62 | 
            +
                  raise ArgumentError.new('object does not support #pending?')
         | 
| 63 63 | 
             
                end
         | 
| 64 64 | 
             
              end
         | 
| 65 65 | 
             
              module_function :pending?
         | 
| 66 66 |  | 
| 67 | 
            -
              def fulfilled?( | 
| 68 | 
            -
                if  | 
| 69 | 
            -
                  return  | 
| 70 | 
            -
                elsif  | 
| 71 | 
            -
                  return  | 
| 67 | 
            +
              def fulfilled?(object)
         | 
| 68 | 
            +
                if object.respond_to?(:fulfilled?)
         | 
| 69 | 
            +
                  return object.fulfilled?
         | 
| 70 | 
            +
                elsif object.respond_to?(:realized?)
         | 
| 71 | 
            +
                  return object.realized?
         | 
| 72 72 | 
             
                else
         | 
| 73 | 
            -
                   | 
| 73 | 
            +
                  raise ArgumentError.new('object does not support #fulfilled?')
         | 
| 74 74 | 
             
                end
         | 
| 75 75 | 
             
              end
         | 
| 76 76 | 
             
              module_function :fulfilled?
         | 
| 77 77 |  | 
| 78 | 
            -
              def realized?( | 
| 79 | 
            -
                if  | 
| 80 | 
            -
                  return  | 
| 81 | 
            -
                elsif  | 
| 82 | 
            -
                  return  | 
| 78 | 
            +
              def realized?(object)
         | 
| 79 | 
            +
                if object.respond_to?(:realized?)
         | 
| 80 | 
            +
                  return object.realized?
         | 
| 81 | 
            +
                elsif object.respond_to?(:fulfilled?)
         | 
| 82 | 
            +
                  return object.fulfilled?
         | 
| 83 83 | 
             
                else
         | 
| 84 | 
            -
                   | 
| 84 | 
            +
                  raise ArgumentError.new('object does not support #realized?')
         | 
| 85 85 | 
             
                end
         | 
| 86 86 | 
             
              end
         | 
| 87 87 | 
             
              module_function :realized?
         | 
| 88 88 |  | 
| 89 | 
            -
              def rejected?( | 
| 90 | 
            -
                if  | 
| 91 | 
            -
                  return  | 
| 89 | 
            +
              def rejected?(object)
         | 
| 90 | 
            +
                if object.respond_to?(:rejected?)
         | 
| 91 | 
            +
                  return object.rejected?
         | 
| 92 92 | 
             
                else
         | 
| 93 | 
            -
                   | 
| 93 | 
            +
                  raise ArgumentError.new('object does not support #rejected?')
         | 
| 94 94 | 
             
                end
         | 
| 95 95 | 
             
              end
         | 
| 96 96 | 
             
              module_function :rejected?
         | 
    
        data/lib/concurrent/future.rb
    CHANGED
    
    | @@ -8,22 +8,17 @@ module Concurrent | |
| 8 8 |  | 
| 9 9 | 
             
              class Future
         | 
| 10 10 | 
             
                include Obligation
         | 
| 11 | 
            +
                include UsesGlobalThreadPool
         | 
| 12 | 
            +
             | 
| 11 13 | 
             
                behavior(:future)
         | 
| 12 14 |  | 
| 13 15 | 
             
                def initialize(*args, &block)
         | 
| 14 | 
            -
                  if args.first.behaves_as?(:global_thread_pool)
         | 
| 15 | 
            -
                    thread_pool = args.first
         | 
| 16 | 
            -
                    args = args.slice(1, args.length)
         | 
| 17 | 
            -
                  else
         | 
| 18 | 
            -
                    thread_pool = $GLOBAL_THREAD_POOL
         | 
| 19 | 
            -
                  end
         | 
| 20 | 
            -
             | 
| 21 16 | 
             
                  unless block_given?
         | 
| 22 17 | 
             
                    @state = :fulfilled
         | 
| 23 18 | 
             
                  else
         | 
| 24 19 | 
             
                    @value = nil
         | 
| 25 20 | 
             
                    @state = :pending
         | 
| 26 | 
            -
                    thread_pool.post do
         | 
| 21 | 
            +
                    Future.thread_pool.post(*args) do
         | 
| 27 22 | 
             
                      Thread.pass
         | 
| 28 23 | 
             
                      work(*args, &block)
         | 
| 29 24 | 
             
                    end
         | 
| @@ -1,3 +1,16 @@ | |
| 1 1 | 
             
            require 'concurrent/cached_thread_pool'
         | 
| 2 2 |  | 
| 3 3 | 
             
            $GLOBAL_THREAD_POOL ||= Concurrent::CachedThreadPool.new
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Concurrent
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              module UsesGlobalThreadPool
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def self.included(base)
         | 
| 10 | 
            +
                  class << base
         | 
| 11 | 
            +
                    attr_accessor :thread_pool
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                  base.thread_pool = $GLOBAL_THREAD_POOL
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            require 'concurrent/global_thread_pool'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Concurrent
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              class NullThreadPool
         | 
| 6 | 
            +
                behavior(:global_thread_pool)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def self.post(*args, &block)
         | 
| 9 | 
            +
                  Thread.new(*args, &block)
         | 
| 10 | 
            +
                  return true
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def post(*args, &block)
         | 
| 14 | 
            +
                  return NullThreadPool.post(*args, &block)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def <<(block)
         | 
| 18 | 
            +
                  NullThreadPool.post(&block)
         | 
| 19 | 
            +
                  return self
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
    
        data/lib/concurrent/promise.rb
    CHANGED
    
    | @@ -1,5 +1,6 @@ | |
| 1 1 | 
             
            require 'thread'
         | 
| 2 2 |  | 
| 3 | 
            +
            require 'concurrent/global_thread_pool'
         | 
| 3 4 | 
             
            require 'concurrent/obligation'
         | 
| 4 5 | 
             
            require 'concurrent/utilities'
         | 
| 5 6 |  | 
| @@ -7,6 +8,8 @@ module Concurrent | |
| 7 8 |  | 
| 8 9 | 
             
              class Promise
         | 
| 9 10 | 
             
                include Obligation
         | 
| 11 | 
            +
                include UsesGlobalThreadPool
         | 
| 12 | 
            +
             | 
| 10 13 | 
             
                behavior(:future)
         | 
| 11 14 | 
             
                behavior(:promise)
         | 
| 12 15 |  | 
| @@ -90,15 +93,6 @@ module Concurrent | |
| 90 93 | 
             
                # @private
         | 
| 91 94 | 
             
                Rescuer = Struct.new(:clazz, :block)
         | 
| 92 95 |  | 
| 93 | 
            -
                # @private
         | 
| 94 | 
            -
                def root # :nodoc:
         | 
| 95 | 
            -
                  return atomic {
         | 
| 96 | 
            -
                    current = self
         | 
| 97 | 
            -
                    current = current.parent until current.root?
         | 
| 98 | 
            -
                    current
         | 
| 99 | 
            -
                  }
         | 
| 100 | 
            -
                end
         | 
| 101 | 
            -
             | 
| 102 96 | 
             
                # @private
         | 
| 103 97 | 
             
                def root? # :nodoc:
         | 
| 104 98 | 
             
                  @parent.nil?
         | 
| @@ -148,7 +142,7 @@ module Concurrent | |
| 148 142 |  | 
| 149 143 | 
             
                # @private
         | 
| 150 144 | 
             
                def realize(*args) # :nodoc:
         | 
| 151 | 
            -
                   | 
| 145 | 
            +
                  Promise.thread_pool.post(@chain, @mutex, args) do |chain, mutex, args|
         | 
| 152 146 | 
             
                    result = args.length == 1 ? args.first : args
         | 
| 153 147 | 
             
                    index = 0
         | 
| 154 148 | 
             
                    loop do
         | 
| @@ -0,0 +1,74 @@ | |
| 1 | 
            +
            require 'drb/drb'
         | 
| 2 | 
            +
            require 'drb/acl'
         | 
| 3 | 
            +
            require 'functional'
         | 
| 4 | 
            +
            require 'concurrent/reactor'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Concurrent
         | 
| 7 | 
            +
              class Reactor
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                class DRbAsyncDemux
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  behavior(:async_event_demux)
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  DEFAULT_URI = 'druby://localhost:12345'
         | 
| 14 | 
            +
                  DEFAULT_ACL = %[allow all]
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def initialize(opts = {})
         | 
| 17 | 
            +
                    @uri = opts[:uri] || DEFAULT_URI
         | 
| 18 | 
            +
                    @acl = ACL.new(opts[:acl] || DEFAULT_ACL)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def set_reactor(reactor)
         | 
| 22 | 
            +
                    raise ArgumentError.new('invalid reactor') unless reactor.behaves_as?(:demux_reactor)
         | 
| 23 | 
            +
                    @reactor = reactor
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def start
         | 
| 27 | 
            +
                    DRb.install_acl(@acl)
         | 
| 28 | 
            +
                    @service = DRb.start_service(@uri, Demultiplexer.new(@reactor))
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  def stop
         | 
| 32 | 
            +
                    @service = DRb.stop_service
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  def stopped?
         | 
| 36 | 
            +
                    return @service.nil?
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  private
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  class Demultiplexer
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    def initialize(reactor)
         | 
| 44 | 
            +
                      @reactor = reactor
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    Concurrent::Reactor::RESERVED_EVENTS.each do |event|
         | 
| 48 | 
            +
                      define_method(event){|*args| false }
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    def method_missing(method, *args, &block)
         | 
| 52 | 
            +
                      (class << self; self; end).class_eval do
         | 
| 53 | 
            +
                        define_method(method) do |*args|
         | 
| 54 | 
            +
                          result = @reactor.handle(method, *args)
         | 
| 55 | 
            +
                          case result.first
         | 
| 56 | 
            +
                          when :ok
         | 
| 57 | 
            +
                            return result.last
         | 
| 58 | 
            +
                          when :ex
         | 
| 59 | 
            +
                            raise result.last
         | 
| 60 | 
            +
                          when :noop
         | 
| 61 | 
            +
                            raise NoMethodError.new("undefined method '#{method}' for #{self}")
         | 
| 62 | 
            +
                          else
         | 
| 63 | 
            +
                            raise DRb::DRbUnknownError.new("unexpected error when calling method '#{method}'")
         | 
| 64 | 
            +
                          end
         | 
| 65 | 
            +
                        end
         | 
| 66 | 
            +
                      end
         | 
| 67 | 
            +
                      self.send(method, *args)
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                DRbAsyncDemultiplexer = DRbAsyncDemux
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
            end
         | 
| @@ -0,0 +1,98 @@ | |
| 1 | 
            +
            require 'socket'
         | 
| 2 | 
            +
            require 'drb/acl'
         | 
| 3 | 
            +
            require 'functional'
         | 
| 4 | 
            +
            require 'concurrent/reactor'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Concurrent
         | 
| 7 | 
            +
              class Reactor
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                class TcpSyncDemux
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  behavior(:sync_event_demux)
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  DEFAULT_HOST = '127.0.0.1'
         | 
| 14 | 
            +
                  DEFAULT_PORT = 12345
         | 
| 15 | 
            +
                  DEFAULT_ACL = %[allow all]
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def initialize(opts = {})
         | 
| 18 | 
            +
                    @host = opts[:host] || DEFAULT_HOST
         | 
| 19 | 
            +
                    @port = opts[:port] || DEFAULT_PORT
         | 
| 20 | 
            +
                    @acl = ACL.new(opts[:acl] || DEFAULT_ACL)
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def start
         | 
| 24 | 
            +
                    @server = TCPServer.new(@host, @port)
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  def stop
         | 
| 28 | 
            +
                    atomic {
         | 
| 29 | 
            +
                      @socket.close unless @socket.nil?
         | 
| 30 | 
            +
                      @server.close unless @server.nil?
         | 
| 31 | 
            +
                      @server = @socket = nil
         | 
| 32 | 
            +
                    }
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  def stopped?
         | 
| 36 | 
            +
                    return @server.nil?
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  def accept
         | 
| 40 | 
            +
                    @socket = @server.accept if @socket.nil?
         | 
| 41 | 
            +
                    return nil unless @acl.allow_socket?(@socket)
         | 
| 42 | 
            +
                    event, args = get_message(@socket)
         | 
| 43 | 
            +
                    return nil if event.nil?
         | 
| 44 | 
            +
                    return Reactor::EventContext.new(event, args)
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  def respond(result, message)
         | 
| 48 | 
            +
                    return nil if @socket.nil?
         | 
| 49 | 
            +
                    @socket.puts(format_message(result, message))
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  def close
         | 
| 53 | 
            +
                    @socket.close
         | 
| 54 | 
            +
                    @socket = nil
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  def self.format_message(event, *args)
         | 
| 58 | 
            +
                    args = args.reduce('') do |memo, arg|
         | 
| 59 | 
            +
                      memo << "#{arg}\r\n"
         | 
| 60 | 
            +
                    end
         | 
| 61 | 
            +
                    return ":#{event}\r\n#{args}\r\n"
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
                  def format_message(*args) self.class.format_message(*args); end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  def self.parse_message(message)
         | 
| 66 | 
            +
                    return atomic {
         | 
| 67 | 
            +
                      event = message.first.match /^:?(\w+)/
         | 
| 68 | 
            +
                      event = event[1].to_s.downcase.to_sym unless event.nil?
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                      args = message.slice(1, message.length) || []
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                      [event, args]
         | 
| 73 | 
            +
                    }
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                  def parse_message(*args) self.class.parse_message(*args); end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                  def self.get_message(socket)
         | 
| 78 | 
            +
                    message = []
         | 
| 79 | 
            +
                    while line = socket.gets
         | 
| 80 | 
            +
                      if line.nil? || (line = line.strip).empty?
         | 
| 81 | 
            +
                        break
         | 
| 82 | 
            +
                      else
         | 
| 83 | 
            +
                        message << line
         | 
| 84 | 
            +
                      end
         | 
| 85 | 
            +
                    end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                    if message.empty?
         | 
| 88 | 
            +
                      return nil
         | 
| 89 | 
            +
                    else
         | 
| 90 | 
            +
                      return parse_message(message)
         | 
| 91 | 
            +
                    end
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
                  def get_message(*args) self.class.get_message(*args); end
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                TcpSyncDemultiplexer = TcpSyncDemux
         | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
            end
         |