devp2p 0.2.0 → 0.3.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 +4 -4
- data/lib/devp2p.rb +14 -29
- data/lib/devp2p/app.rb +70 -0
- data/lib/devp2p/command.rb +1 -1
- data/lib/devp2p/connection_monitor.rb +27 -21
- data/lib/devp2p/discovery.rb +1 -1
- data/lib/devp2p/discovery/protocol.rb +2 -2
- data/lib/devp2p/discovery/service.rb +108 -49
- data/lib/devp2p/p2p_protocol.rb +9 -9
- data/lib/devp2p/peer.rb +53 -59
- data/lib/devp2p/peer_manager.rb +77 -39
- data/lib/devp2p/{base_protocol.rb → protocol.rb} +19 -17
- data/lib/devp2p/service.rb +50 -0
- data/lib/devp2p/sync_queue.rb +58 -45
- data/lib/devp2p/version.rb +2 -1
- data/lib/devp2p/wired_service.rb +3 -3
- metadata +19 -35
- data/lib/devp2p/app_helper.rb +0 -85
- data/lib/devp2p/base_app.rb +0 -88
- data/lib/devp2p/base_service.rb +0 -55
- data/lib/devp2p/control.rb +0 -32
| @@ -20,9 +20,8 @@ module DEVp2p | |
| 20 20 | 
             
              # The default implementation of `command.receive` calls callbacks which can
         | 
| 21 21 | 
             
              # be registered in a list which is available as: `protocol.receive_X_callbacks`.
         | 
| 22 22 | 
             
              #
         | 
| 23 | 
            -
              class  | 
| 24 | 
            -
                include  | 
| 25 | 
            -
                include Control
         | 
| 23 | 
            +
              class Protocol
         | 
| 24 | 
            +
                include Concurrent::Async
         | 
| 26 25 |  | 
| 27 26 | 
             
                extend Configurable
         | 
| 28 27 | 
             
                add_config(
         | 
| @@ -41,28 +40,31 @@ module DEVp2p | |
| 41 40 | 
             
                  @peer = peer
         | 
| 42 41 | 
             
                  @service = service
         | 
| 43 42 |  | 
| 44 | 
            -
                   | 
| 43 | 
            +
                  @stopped = false
         | 
| 45 44 |  | 
| 46 45 | 
             
                  setup
         | 
| 47 46 | 
             
                end
         | 
| 48 47 |  | 
| 49 48 | 
             
                def start
         | 
| 50 | 
            -
                  logger.debug 'starting', proto:  | 
| 51 | 
            -
                  service.on_wire_protocol_start  | 
| 52 | 
            -
             | 
| 49 | 
            +
                  logger.debug 'starting', proto: self
         | 
| 50 | 
            +
                  service.async.on_wire_protocol_start self
         | 
| 51 | 
            +
                rescue
         | 
| 52 | 
            +
                  puts $!
         | 
| 53 | 
            +
                  puts $!.backtrace[0,10].join("\n")
         | 
| 53 54 | 
             
                end
         | 
| 54 55 |  | 
| 55 56 | 
             
                def stop
         | 
| 56 | 
            -
                  logger.debug 'stopping', proto:  | 
| 57 | 
            -
                  service.on_wire_protocol_stop  | 
| 57 | 
            +
                  logger.debug 'stopping', proto: self
         | 
| 58 | 
            +
                  service.async.on_wire_protocol_stop self
         | 
| 58 59 |  | 
| 59 | 
            -
                   | 
| 60 | 
            -
             | 
| 61 | 
            -
                   | 
| 60 | 
            +
                  @stopped = true
         | 
| 61 | 
            +
                rescue
         | 
| 62 | 
            +
                  puts $!
         | 
| 63 | 
            +
                  puts $!.backtrace[0,10].join("\n")
         | 
| 62 64 | 
             
                end
         | 
| 63 65 |  | 
| 64 | 
            -
                def  | 
| 65 | 
            -
                   | 
| 66 | 
            +
                def stopped?
         | 
| 67 | 
            +
                  @stopped
         | 
| 66 68 | 
             
                end
         | 
| 67 69 |  | 
| 68 70 | 
             
                def receive_packet(packet)
         | 
| @@ -75,7 +77,7 @@ module DEVp2p | |
| 75 77 | 
             
                end
         | 
| 76 78 |  | 
| 77 79 | 
             
                def send_packet(packet)
         | 
| 78 | 
            -
                  peer.send_packet packet
         | 
| 80 | 
            +
                  peer.async.send_packet packet
         | 
| 79 81 | 
             
                end
         | 
| 80 82 |  | 
| 81 83 | 
             
                def to_s
         | 
| @@ -98,14 +100,14 @@ module DEVp2p | |
| 98 100 |  | 
| 99 101 | 
             
                  raise DuplicatedCommand unless klasses.map(&:cmd_id).uniq.size == klasses.size
         | 
| 100 102 |  | 
| 101 | 
            -
                  proto =  | 
| 103 | 
            +
                  proto = self
         | 
| 102 104 |  | 
| 103 105 | 
             
                  klasses.each do |klass|
         | 
| 104 106 | 
             
                    instance = klass.new
         | 
| 105 107 |  | 
| 106 108 | 
             
                    # decode rlp, create hash, call receive
         | 
| 107 109 | 
             
                    receive = lambda do |packet|
         | 
| 108 | 
            -
                      raise ArgumentError unless packet.is_a?(Packet)
         | 
| 110 | 
            +
                      raise ArgumentError, "packet is not a Packet: #{packet.inspect}" unless packet.is_a?(Packet)
         | 
| 109 111 | 
             
                      instance.receive proto, klass.decode_payload(packet.payload)
         | 
| 110 112 | 
             
                    end
         | 
| 111 113 |  | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            # -*- encoding : ascii-8bit -*-
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module DEVp2p
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              class Service
         | 
| 6 | 
            +
                include Concurrent::Async
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                extend Configurable
         | 
| 9 | 
            +
                add_config(
         | 
| 10 | 
            +
                  name: '',
         | 
| 11 | 
            +
                  default_config: {},
         | 
| 12 | 
            +
                  required_services: []
         | 
| 13 | 
            +
                )
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                class <<self
         | 
| 16 | 
            +
                  def register_with_app(app)
         | 
| 17 | 
            +
                    app.register_service self, app
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                attr :app, :config
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def initialize(app)
         | 
| 24 | 
            +
                  super()
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  @app = app
         | 
| 27 | 
            +
                  @config = app.config.reverse_merge(default_config)
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  available_services = app.services.each_value.map(&:class)
         | 
| 30 | 
            +
                  required_services.each do |r|
         | 
| 31 | 
            +
                    raise MissingRequiredServiceError, "require service #{r}" unless available_services.include?(r)
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def start
         | 
| 36 | 
            +
                  raise NotImplemented
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def stop
         | 
| 40 | 
            +
                  raise NotImplemented
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def to_s
         | 
| 44 | 
            +
                  "<Service #{name}##{object_id}>"
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
                alias inspect to_s
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            end
         | 
    
        data/lib/devp2p/sync_queue.rb
    CHANGED
    
    | @@ -1,8 +1,7 @@ | |
| 1 1 | 
             
            # -*- encoding : ascii-8bit -*-
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
            #
         | 
| 3 | 
            +
            require 'thread'
         | 
| 4 | 
            +
             | 
| 6 5 | 
             
            class SyncQueue
         | 
| 7 6 |  | 
| 8 7 | 
             
              attr :queue, :max_size
         | 
| @@ -12,69 +11,83 @@ class SyncQueue | |
| 12 11 | 
             
                @num_waiting = 0
         | 
| 13 12 |  | 
| 14 13 | 
             
                @max_size = max_size
         | 
| 15 | 
            -
             | 
| 16 | 
            -
                @ | 
| 14 | 
            +
             | 
| 15 | 
            +
                @mutex = Mutex.new
         | 
| 16 | 
            +
                @cond_full = ConditionVariable.new
         | 
| 17 | 
            +
                @cond_empty = ConditionVariable.new
         | 
| 17 18 | 
             
              end
         | 
| 18 19 |  | 
| 19 20 | 
             
              def enq(obj, non_block=false)
         | 
| 20 | 
            -
                 | 
| 21 | 
            -
                   | 
| 22 | 
            -
                     | 
| 23 | 
            -
                       | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
                         | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 21 | 
            +
                Thread.handle_interrupt(StandardError => :on_blocking) do
         | 
| 22 | 
            +
                  loop do
         | 
| 23 | 
            +
                    @mutex.synchronize do
         | 
| 24 | 
            +
                      if full?
         | 
| 25 | 
            +
                        if non_block
         | 
| 26 | 
            +
                          raise ThreadError, 'queue full'
         | 
| 27 | 
            +
                        else
         | 
| 28 | 
            +
                          begin
         | 
| 29 | 
            +
                            @num_waiting += 1
         | 
| 30 | 
            +
                            @cond_full.wait @mutex
         | 
| 31 | 
            +
                          ensure
         | 
| 32 | 
            +
                            @num_waiting -= 1
         | 
| 33 | 
            +
                          end
         | 
| 34 | 
            +
                        end
         | 
| 35 | 
            +
                      else
         | 
| 36 | 
            +
                        @queue.push obj
         | 
| 37 | 
            +
                        @cond_empty.signal
         | 
| 38 | 
            +
                        return obj
         | 
| 30 39 | 
             
                      end
         | 
| 31 40 | 
             
                    end
         | 
| 32 | 
            -
                  else
         | 
| 33 | 
            -
                    @queue.push obj
         | 
| 34 | 
            -
                    @cond_empty.signal
         | 
| 35 | 
            -
                    return obj
         | 
| 36 41 | 
             
                  end
         | 
| 37 42 | 
             
                end
         | 
| 38 43 | 
             
              end
         | 
| 39 44 | 
             
              alias << enq
         | 
| 40 45 |  | 
| 41 46 | 
             
              def deq(non_block=false)
         | 
| 42 | 
            -
                 | 
| 43 | 
            -
                   | 
| 44 | 
            -
                     | 
| 45 | 
            -
                       | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
                         | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 47 | 
            +
                Thread.handle_interrupt(StandardError => :on_blocking) do
         | 
| 48 | 
            +
                  loop do
         | 
| 49 | 
            +
                    @mutex.synchronize do
         | 
| 50 | 
            +
                      if empty?
         | 
| 51 | 
            +
                        if non_block
         | 
| 52 | 
            +
                          raise ThreadError, 'queue empty'
         | 
| 53 | 
            +
                        else
         | 
| 54 | 
            +
                          begin
         | 
| 55 | 
            +
                            @num_waiting += 1
         | 
| 56 | 
            +
                            @cond_empty.wait @mutex
         | 
| 57 | 
            +
                          ensure
         | 
| 58 | 
            +
                            @num_waiting -= 1
         | 
| 59 | 
            +
                          end
         | 
| 60 | 
            +
                        end
         | 
| 61 | 
            +
                      else
         | 
| 62 | 
            +
                        obj = @queue.shift
         | 
| 63 | 
            +
                        @cond_full.signal
         | 
| 64 | 
            +
                        return obj
         | 
| 52 65 | 
             
                      end
         | 
| 53 66 | 
             
                    end
         | 
| 54 | 
            -
                  else
         | 
| 55 | 
            -
                    obj = @queue.shift
         | 
| 56 | 
            -
                    @cond_full.signal
         | 
| 57 | 
            -
                    return obj
         | 
| 58 67 | 
             
                  end
         | 
| 59 68 | 
             
                end
         | 
| 60 69 | 
             
              end
         | 
| 61 70 |  | 
| 62 71 | 
             
              # Same as pop except it will not remove the element from queue, just peek.
         | 
| 63 72 | 
             
              def peek(non_block=false)
         | 
| 64 | 
            -
                 | 
| 65 | 
            -
                   | 
| 66 | 
            -
                     | 
| 67 | 
            -
                       | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
                         | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 73 | 
            +
                Thread.handle_interrupt(StandardError => :on_blocking) do
         | 
| 74 | 
            +
                  loop do
         | 
| 75 | 
            +
                    @mutex.synchronize do
         | 
| 76 | 
            +
                      if empty?
         | 
| 77 | 
            +
                        if non_block
         | 
| 78 | 
            +
                          raise ThreadError, 'queue empty'
         | 
| 79 | 
            +
                        else
         | 
| 80 | 
            +
                          begin
         | 
| 81 | 
            +
                            @num_waiting += 1
         | 
| 82 | 
            +
                            @cond_empty.wait @mutex
         | 
| 83 | 
            +
                          ensure
         | 
| 84 | 
            +
                            @num_waiting -= 1
         | 
| 85 | 
            +
                          end
         | 
| 86 | 
            +
                        end
         | 
| 87 | 
            +
                      else
         | 
| 88 | 
            +
                        return @queue[0]
         | 
| 74 89 | 
             
                      end
         | 
| 75 90 | 
             
                    end
         | 
| 76 | 
            -
                  else
         | 
| 77 | 
            -
                    return @queue[0]
         | 
| 78 91 | 
             
                  end
         | 
| 79 92 | 
             
                end
         | 
| 80 93 | 
             
              end
         | 
    
        data/lib/devp2p/version.rb
    CHANGED
    
    
    
        data/lib/devp2p/wired_service.rb
    CHANGED
    
    | @@ -12,17 +12,17 @@ module DEVp2p | |
| 12 12 | 
             
              #         with instances of Peer and WiredService
         | 
| 13 13 | 
             
              #       WiredService.wire_protocol(Peer.new, WiredService.new)
         | 
| 14 14 | 
             
              #
         | 
| 15 | 
            -
              class WiredService <  | 
| 15 | 
            +
              class WiredService < Service
         | 
| 16 16 | 
             
                name 'wired'
         | 
| 17 17 |  | 
| 18 18 | 
             
                attr_accessor :wire_protocol
         | 
| 19 19 |  | 
| 20 20 | 
             
                def on_wire_protocol_start(proto)
         | 
| 21 | 
            -
                  raise ArgumentError, "argument is not a protocol" unless proto.is_a?( | 
| 21 | 
            +
                  raise ArgumentError, "argument is not a protocol" unless proto.is_a?(::DEVp2p::Protocol)
         | 
| 22 22 | 
             
                end
         | 
| 23 23 |  | 
| 24 24 | 
             
                def on_wire_protocol_stop(proto)
         | 
| 25 | 
            -
                  raise ArgumentError, "argument is not a protocol" unless proto.is_a?( | 
| 25 | 
            +
                  raise ArgumentError, "argument is not a protocol" unless proto.is_a?(::DEVp2p::Protocol)
         | 
| 26 26 | 
             
                end
         | 
| 27 27 |  | 
| 28 28 | 
             
              end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: devp2p
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.3.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Jan Xie
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2016- | 
| 11 | 
            +
            date: 2016-06-16 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: hashie
         | 
| @@ -38,34 +38,6 @@ dependencies: | |
| 38 38 | 
             
                - - '='
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 40 | 
             
                    version: 0.1.2
         | 
| 41 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            -
              name: celluloid
         | 
| 43 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            -
                requirements:
         | 
| 45 | 
            -
                - - "~>"
         | 
| 46 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            -
                    version: '0.17'
         | 
| 48 | 
            -
              type: :runtime
         | 
| 49 | 
            -
              prerelease: false
         | 
| 50 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            -
                requirements:
         | 
| 52 | 
            -
                - - "~>"
         | 
| 53 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            -
                    version: '0.17'
         | 
| 55 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            -
              name: celluloid-io
         | 
| 57 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            -
                requirements:
         | 
| 59 | 
            -
                - - "~>"
         | 
| 60 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            -
                    version: 0.17.3
         | 
| 62 | 
            -
              type: :runtime
         | 
| 63 | 
            -
              prerelease: false
         | 
| 64 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            -
                requirements:
         | 
| 66 | 
            -
                - - "~>"
         | 
| 67 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            -
                    version: 0.17.3
         | 
| 69 41 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 70 42 | 
             
              name: digest-sha3
         | 
| 71 43 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -108,6 +80,20 @@ dependencies: | |
| 108 80 | 
             
                - - ">="
         | 
| 109 81 | 
             
                  - !ruby/object:Gem::Version
         | 
| 110 82 | 
             
                    version: 0.7.1
         | 
| 83 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 84 | 
            +
              name: concurrent-ruby
         | 
| 85 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 | 
            +
                requirements:
         | 
| 87 | 
            +
                - - "~>"
         | 
| 88 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            +
                    version: '1.0'
         | 
| 90 | 
            +
              type: :runtime
         | 
| 91 | 
            +
              prerelease: false
         | 
| 92 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 93 | 
            +
                requirements:
         | 
| 94 | 
            +
                - - "~>"
         | 
| 95 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            +
                    version: '1.0'
         | 
| 111 97 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 112 98 | 
             
              name: rake
         | 
| 113 99 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -162,14 +148,10 @@ files: | |
| 162 148 | 
             
            - LICENSE
         | 
| 163 149 | 
             
            - README.md
         | 
| 164 150 | 
             
            - lib/devp2p.rb
         | 
| 165 | 
            -
            - lib/devp2p/ | 
| 166 | 
            -
            - lib/devp2p/base_app.rb
         | 
| 167 | 
            -
            - lib/devp2p/base_protocol.rb
         | 
| 168 | 
            -
            - lib/devp2p/base_service.rb
         | 
| 151 | 
            +
            - lib/devp2p/app.rb
         | 
| 169 152 | 
             
            - lib/devp2p/command.rb
         | 
| 170 153 | 
             
            - lib/devp2p/configurable.rb
         | 
| 171 154 | 
             
            - lib/devp2p/connection_monitor.rb
         | 
| 172 | 
            -
            - lib/devp2p/control.rb
         | 
| 173 155 | 
             
            - lib/devp2p/crypto.rb
         | 
| 174 156 | 
             
            - lib/devp2p/crypto/ecc_x.rb
         | 
| 175 157 | 
             
            - lib/devp2p/crypto/ecies.rb
         | 
| @@ -194,7 +176,9 @@ files: | |
| 194 176 | 
             
            - lib/devp2p/peer.rb
         | 
| 195 177 | 
             
            - lib/devp2p/peer_errors.rb
         | 
| 196 178 | 
             
            - lib/devp2p/peer_manager.rb
         | 
| 179 | 
            +
            - lib/devp2p/protocol.rb
         | 
| 197 180 | 
             
            - lib/devp2p/rlpx_session.rb
         | 
| 181 | 
            +
            - lib/devp2p/service.rb
         | 
| 198 182 | 
             
            - lib/devp2p/sync_queue.rb
         | 
| 199 183 | 
             
            - lib/devp2p/utils.rb
         | 
| 200 184 | 
             
            - lib/devp2p/version.rb
         | 
    
        data/lib/devp2p/app_helper.rb
    DELETED
    
    | @@ -1,85 +0,0 @@ | |
| 1 | 
            -
            # -*- encoding : ascii-8bit -*-
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            module DEVp2p
         | 
| 4 | 
            -
              class AppHelper
         | 
| 5 | 
            -
             | 
| 6 | 
            -
                def run(app_class, service_class, num_nodes: 3, seed: 0, min_peers: 2, max_peers: 2, random_port: false)
         | 
| 7 | 
            -
                  base_port = random_port ? SecureRandom.random_number(50000) + 10000 : 29870
         | 
| 8 | 
            -
             | 
| 9 | 
            -
                  bootstrap_node_privkey = Crypto.mk_privkey "#{seed}:udp:0"
         | 
| 10 | 
            -
                  bootstrap_node_pubkey = Crypto.privtopub bootstrap_node_privkey
         | 
| 11 | 
            -
                  enode = Utils.host_port_pubkey_to_uri "0.0.0.0", base_port, bootstrap_node_pubkey
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                  services = [Discovery::Service, PeerManager]#, service_class]
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                  base_config = {}
         | 
| 16 | 
            -
                  services.each {|s| Utils.update_config_with_defaults base_config, s.default_config }
         | 
| 17 | 
            -
             | 
| 18 | 
            -
                  base_config[:discovery][:bootstrap_nodes] = [enode]
         | 
| 19 | 
            -
                  base_config[:seed] = seed
         | 
| 20 | 
            -
                  base_config[:base_port] = base_port
         | 
| 21 | 
            -
                  base_config[:num_nodes] = num_nodes
         | 
| 22 | 
            -
                  base_config[:min_peers] = min_peers
         | 
| 23 | 
            -
                  base_config[:max_peers] = max_peers
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                  apps = []
         | 
| 26 | 
            -
                  num_nodes.times do |node_num|
         | 
| 27 | 
            -
                    app = create_app node_num, base_config, services, app_class
         | 
| 28 | 
            -
                    apps.push app
         | 
| 29 | 
            -
                  end
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                  serve_until_stopped apps
         | 
| 32 | 
            -
                end
         | 
| 33 | 
            -
             | 
| 34 | 
            -
                def create_app(node_num, config, services, app_class)
         | 
| 35 | 
            -
                  num_nodes = config[:num_nodes]
         | 
| 36 | 
            -
                  base_port = config[:base_port]
         | 
| 37 | 
            -
                  seed = config[:seed]
         | 
| 38 | 
            -
                  min_peers = config[:min_peers]
         | 
| 39 | 
            -
                  max_peers = config[:max_peers]
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                  raise "invalid node_num" unless node_num < num_nodes
         | 
| 42 | 
            -
                  #raise "invalid min/max peers" unless min_peers <= max_peers && max_peers < num_nodes
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                  config = Marshal.load Marshal.dump(config)
         | 
| 45 | 
            -
                  config[:node_num] = node_num
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                  config[:node][:privkey_hex] = Utils.encode_hex Crypto.mk_privkey("#{seed}:udp:#{node_num}")
         | 
| 48 | 
            -
                  config[:discovery][:listen_port] = base_port + node_num
         | 
| 49 | 
            -
                  config[:p2p][:listen_port] = base_port + node_num
         | 
| 50 | 
            -
                  config[:p2p][:min_peers] = [min_peers, 10].min
         | 
| 51 | 
            -
                  config[:p2p][:max_peers] = max_peers
         | 
| 52 | 
            -
                  config[:client_version_string] = "NODE#{node_num}"
         | 
| 53 | 
            -
             | 
| 54 | 
            -
                  app = app_class.new config
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                  services.each do |service|
         | 
| 57 | 
            -
                    raise "invalid service" unless service.instance_of?(Class) && service < BaseService
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                    if !app.config[:deactivated_services].include?(service.name)
         | 
| 60 | 
            -
                      raise "service should not be active" if app.services.has_key?(service.name)
         | 
| 61 | 
            -
                      service.register_with_app app
         | 
| 62 | 
            -
                      raise "servier should be active" unless app.services.has_key?(service.name)
         | 
| 63 | 
            -
                    end
         | 
| 64 | 
            -
                  end
         | 
| 65 | 
            -
             | 
| 66 | 
            -
                  app
         | 
| 67 | 
            -
                end
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                def serve_until_stopped(apps)
         | 
| 70 | 
            -
                  apps.each do |app|
         | 
| 71 | 
            -
                    app.start
         | 
| 72 | 
            -
             | 
| 73 | 
            -
                    if app.config[:post_app_start_callback]
         | 
| 74 | 
            -
                      app.config[:post_app_start_callback].call(app)
         | 
| 75 | 
            -
                    end
         | 
| 76 | 
            -
                  end
         | 
| 77 | 
            -
             | 
| 78 | 
            -
                  apps.each(&:join)
         | 
| 79 | 
            -
             | 
| 80 | 
            -
                  # finally stop
         | 
| 81 | 
            -
                  apps.each(&:stop)
         | 
| 82 | 
            -
                end
         | 
| 83 | 
            -
             | 
| 84 | 
            -
              end
         | 
| 85 | 
            -
            end
         |