dht 0.0.1

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.
File without changes
@@ -0,0 +1,10 @@
1
+ .DS_Store
2
+ public/.DS_Store
3
+ .bundle
4
+ .kdev4
5
+ log/*.log
6
+ public/stylesheets/*.css
7
+ rerun.txt
8
+ tmp/*
9
+ vendor/bundle/*
10
+ !vendor/bundle/cache/*.gem
@@ -0,0 +1,16 @@
1
+ before_install: sudo apt-get install libzmq3-dev
2
+
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - ruby-head
7
+ - jruby-19mode
8
+ - jruby-head
9
+ - rbx-19mode
10
+
11
+ matrix:
12
+ allow_failures:
13
+ - rvm: ruby-head
14
+ - rvm: jruby-head
15
+ - rvm: jruby-19mode
16
+ - rvm: rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rake'
6
+ gem 'rspec'
7
+ gem 'bogus'
8
+ gem 'bbq-spawn'
9
+ gem 'coveralls', require: false
@@ -0,0 +1,90 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ dht (0.0.1)
5
+ dcell
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ bbq-spawn (0.0.3)
11
+ childprocess
12
+ bogus (0.1.2)
13
+ dependor (>= 0.0.4)
14
+ celluloid (0.14.1)
15
+ timers (>= 1.0.0)
16
+ celluloid-io (0.14.1)
17
+ celluloid (>= 0.14.1)
18
+ nio4r (>= 0.4.5)
19
+ celluloid-zmq (0.14.0)
20
+ celluloid (>= 0.13.0)
21
+ ffi
22
+ ffi-rzmq
23
+ certified (0.1.1)
24
+ childprocess (0.3.9)
25
+ ffi (~> 1.0, >= 1.0.11)
26
+ colorize (0.5.8)
27
+ coveralls (0.6.7)
28
+ colorize
29
+ multi_json (~> 1.3)
30
+ rest-client
31
+ simplecov (>= 0.7)
32
+ thor
33
+ dcell (0.14.0)
34
+ celluloid (>= 0.13.0)
35
+ celluloid-zmq (>= 0.13.0)
36
+ redis
37
+ redis-namespace
38
+ reel
39
+ dependor (0.0.6)
40
+ diff-lcs (1.2.4)
41
+ ffi (1.9.0)
42
+ ffi-rzmq (1.0.1)
43
+ ffi
44
+ http (0.4.0)
45
+ certified
46
+ http_parser.rb
47
+ http_parser.rb (0.5.3)
48
+ mime-types (1.23)
49
+ multi_json (1.7.7)
50
+ nio4r (0.4.6)
51
+ rack (1.5.2)
52
+ rake (10.1.0)
53
+ redis (3.0.4)
54
+ redis-namespace (1.3.0)
55
+ redis (~> 3.0.0)
56
+ reel (0.3.0)
57
+ celluloid-io (>= 0.8.0)
58
+ http (>= 0.2.0)
59
+ http_parser.rb (>= 0.5.3)
60
+ rack (>= 1.4.0)
61
+ websocket_parser (>= 0.1.0)
62
+ rest-client (1.6.7)
63
+ mime-types (>= 1.16)
64
+ rspec (2.14.1)
65
+ rspec-core (~> 2.14.0)
66
+ rspec-expectations (~> 2.14.0)
67
+ rspec-mocks (~> 2.14.0)
68
+ rspec-core (2.14.2)
69
+ rspec-expectations (2.14.0)
70
+ diff-lcs (>= 1.1.3, < 2.0)
71
+ rspec-mocks (2.14.1)
72
+ simplecov (0.7.1)
73
+ multi_json (~> 1.0)
74
+ simplecov-html (~> 0.7.1)
75
+ simplecov-html (0.7.1)
76
+ thor (0.18.1)
77
+ timers (1.1.0)
78
+ websocket_parser (0.1.4)
79
+ http
80
+
81
+ PLATFORMS
82
+ ruby
83
+
84
+ DEPENDENCIES
85
+ bbq-spawn
86
+ bogus
87
+ coveralls
88
+ dht!
89
+ rake
90
+ rspec
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2006-2010 Steve Sloan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
@@ -0,0 +1,16 @@
1
+ = DHT
2
+
3
+ [![Build Status](https://secure.travis-ci.org/LTe/dht.png)](http://travis-ci.org/LTe/dht)
4
+ [![Dependency Status](https://gemnasium.com/LTe/dht.png)](https://gemnasium.com/LTe/dht)
5
+ [![Code Climate](https://codeclimate.com/github/LTe/dht.png)](https://codeclimate.com/github/LTe/dht)
6
+ [![Coverage Status](https://coveralls.io/repos/LTe/dht/badge.png?branch=master)](https://coveralls.io/r/LTe/dht?branch=master)
7
+ [![Gem Version](https://badge.fury.io/rb/dht.png)](http://badge.fury.io/rb/dht)
8
+
9
+ A Ruby implementation of a Kademlia-style Distributed Hash Table.
10
+
11
+ == Work-in-progress
12
+
13
+ Author:: Steve Sloan (mailto:steve@finagle.org)
14
+ Website:: http://github.com/CodeMonkeySteve/dht
15
+ Copyright:: Copyright (c) 2009 Steve Sloan
16
+ License:: MIT
@@ -0,0 +1,5 @@
1
+ require 'rspec/core/rake_task'
2
+ require 'bundler/gem_tasks'
3
+
4
+ task :default => :spec
5
+ RSpec::Core::RakeTask.new :spec
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH << File.dirname(__FILE__)+'/..' << File.dirname(__FILE__)+'/../lib'
3
+
4
+ require 'irb'
5
+ require 'dcell'
6
+ require 'dht/node'
7
+ require 'optparse'
8
+
9
+ options = {}
10
+
11
+ opts = OptionParser.new do |opts|
12
+ opts.banner = "Usage: dht_dcell.rb [options]"
13
+
14
+ opts.on("-n", "--name [NAME]", String, "Select node name") do |name|
15
+ options[:name] = name
16
+ end
17
+
18
+ opts.on("-p", "--port [PORT]", String, "Select node port") do |port|
19
+ options[:port] = port.to_i
20
+ end
21
+
22
+ opts.on("-h", "--host [HOST]", String, "Select node host") do |host|
23
+ options[:host] = host
24
+ end
25
+
26
+ opts.on("-n", "--node [NODE]", String, "One of nodes: name:host:port") do |node|
27
+ if node
28
+ node_attributes = node.split(":")
29
+ options[:node] = { :id => node_attributes[0], :addr => "tcp://#{node_attributes[1]}:#{node_attributes[2]}" }
30
+ end
31
+ end
32
+
33
+ opts.on("-e", "--explorer") do |explorer|
34
+ options[:explorer] = explorer
35
+ end
36
+ end
37
+
38
+ opts.parse!
39
+
40
+ node = DHT::Node.new(options)
41
+ node.start
42
+
43
+ ARGV.clear
44
+ IRB.start
45
+
46
+
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/dht/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Piotr Niełacny"]
6
+ gem.email = ["piotr.nielacny@gmail.com"]
7
+ gem.description = %q{Ruby DHT hash}
8
+ gem.summary = %q{Implementation of the Distributed Hash Table (DHT) in Ruby}
9
+ gem.homepage = "https://github.com/LTe/dht"
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.name = "dht"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = DHT::Hash::VERSION
17
+ gem.required_ruby_version = '>= 1.9.3'
18
+
19
+ gem.add_dependency "dcell"
20
+ end
21
+
@@ -0,0 +1,40 @@
1
+ require 'dht/node'
2
+
3
+ module DHT
4
+ class Hash
5
+ attr_reader :node
6
+
7
+ def initialize(options = {})
8
+ @node = DHT::Node.new(options)
9
+ @node.start
10
+ end
11
+
12
+ def me
13
+ DCell.me
14
+ end
15
+
16
+ def storage
17
+ me[:storage]
18
+ end
19
+
20
+ def manager
21
+ me[:manager]
22
+ end
23
+
24
+ def store(key, value)
25
+ manager.storage_for(key).store(key, value)
26
+ end
27
+
28
+ def get(key)
29
+ manager.storage_for(key).get(key)
30
+ end
31
+
32
+ def []=(key, value)
33
+ store(key, value)
34
+ end
35
+
36
+ def [](key)
37
+ get(key)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,66 @@
1
+ require 'digest/sha1'
2
+
3
+ module DHT
4
+ class Key
5
+ Digest = ::Digest::SHA1
6
+ Size = Digest.new.digest_length
7
+
8
+ def self.for_content(content)
9
+ Key.new Digest.digest(content.to_s)
10
+ end
11
+
12
+ def initialize(key)
13
+ @key =
14
+ if Key === key
15
+ key.to_binary
16
+ elsif Integer === key
17
+ @key_i = key
18
+ k = @key_i.to_s(16)
19
+ [('0' * ((Size * 2) - k.size)) + k].pack('H*')
20
+ else
21
+ key = key.to_s
22
+ case key.size
23
+ when Size then key
24
+ when Size * 2 then [key].pack('H*')
25
+ else raise "Invalid key: #{key}"
26
+ end
27
+ end
28
+ end
29
+
30
+ def ==(that)
31
+ self.eql? that
32
+ end
33
+
34
+ def to_binary
35
+ @key
36
+ end
37
+
38
+ def to_s
39
+ to_binary.unpack('H*').first
40
+ end
41
+
42
+ def hash
43
+ @key.hash
44
+ end
45
+
46
+ def eql?(that)
47
+ if Key === that
48
+ @key == that.to_binary
49
+ else
50
+ @key.to_s == that.to_s
51
+ end
52
+ end
53
+
54
+ def inspect
55
+ to_s
56
+ end
57
+
58
+ def to_i
59
+ @key_i ||= eval( '0x' + self.to_s )
60
+ end
61
+
62
+ def distance_to(that)
63
+ self.to_i ^ that.to_i
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,43 @@
1
+ require 'celluloid'
2
+
3
+ module DHT
4
+ class Manager
5
+ include Celluloid
6
+
7
+ def find_nodes
8
+ dcell_nodes.inject({}) { |hash, node| hash[node[:storage].key] = node; hash }
9
+ end
10
+
11
+ def storage_for(key)
12
+ closest_node = node_for(key)
13
+
14
+ if closest_node == me
15
+ me[:storage]
16
+ else
17
+ closest_node[:manager].storage_for(key)
18
+ end
19
+ end
20
+
21
+ def node_for(key)
22
+ key = Key.for_content(key.to_s)
23
+ node_key = nodes.keys.min { |a,b| a.distance_to(key) <=> b.distance_to(key) }
24
+ nodes[node_key]
25
+ end
26
+
27
+ def key
28
+ Key.for_content(me.addr)
29
+ end
30
+
31
+ def nodes
32
+ @nodes = find_nodes
33
+ end
34
+
35
+ def dcell_nodes
36
+ DCell::Node.all
37
+ end
38
+
39
+ def me
40
+ DCell.me
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,47 @@
1
+ require 'set'
2
+ require 'celluloid'
3
+ require 'dcell/explorer'
4
+ require 'dht/key'
5
+ require 'dht/storage'
6
+ require 'dht/manager'
7
+ require 'dht/service'
8
+
9
+ module DHT
10
+ class Node
11
+ def initialize(options = {})
12
+ options = default_options.merge(options)
13
+
14
+ @host = options.delete(:host)
15
+ @port = options.delete(:port)
16
+ @name = options.delete(:name)
17
+ @node = options.delete(:node)
18
+ @explorer = options.delete(:explorer)
19
+ end
20
+
21
+ def start
22
+ DCell.start(configuration)
23
+ DHT::Service.new(:key => key, :explorer => @explorer).run
24
+ end
25
+
26
+ def configuration
27
+ configuration = {:id => @name, :addr => "tcp://#{@host}:#{@port}"}
28
+ configuration.merge!(:directory => @node) if @node
29
+
30
+ configuration
31
+ end
32
+
33
+ def key
34
+ @key ||= Key.for_content("#{@name}:#{@host}:#{@port}")
35
+ end
36
+
37
+ private
38
+
39
+ def default_options
40
+ {
41
+ :name => "default",
42
+ :port => 3000,
43
+ :host => "127.0.0.1"
44
+ }
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,37 @@
1
+ module DHT
2
+ class Service
3
+ def initialize(options = {})
4
+ @explorer = options.delete(:explorer)
5
+ @key = options.delete(:key)
6
+ end
7
+
8
+ def run
9
+ run_services
10
+ end
11
+
12
+ def run_services
13
+ create_explorer if enable_explorer?
14
+ create_storage
15
+ create_manager
16
+ end
17
+
18
+ def create_explorer
19
+ DCell::Explorer.new("127.0.0.1", 8000)
20
+ end
21
+
22
+ def create_storage
23
+ DHT::Storage.supervise_as :storage, @key
24
+ end
25
+
26
+ def create_manager
27
+ DHT::Manager.supervise_as :manager
28
+ end
29
+
30
+ private
31
+
32
+ def enable_explorer?
33
+ @explorer
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,30 @@
1
+ require 'celluloid'
2
+
3
+ module DHT
4
+ class Storage
5
+ include Celluloid
6
+
7
+ attr_reader :key, :database
8
+
9
+ def initialize(key)
10
+ @key = key
11
+ @database = {}
12
+ end
13
+
14
+ def store(key, value)
15
+ @database[key] = value
16
+ end
17
+
18
+ def get(key)
19
+ @database[key]
20
+ end
21
+
22
+ def [](key)
23
+ get(key)
24
+ end
25
+
26
+ def []=(key, value)
27
+ store(key, value)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ module DHT
2
+ class Hash
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ module DHT
4
+ describe Hash do
5
+ fake(:manager)
6
+ fake(:storage)
7
+ fake(:storage2) { Storage }
8
+ fake(:dcell_node) { DCell::Node }
9
+
10
+ before do
11
+ fake_class(DHT::Node, :new => dcell_node)
12
+ stub(dcell_node).[](:storage) { storage }
13
+ stub(dcell_node).[](:manager) { manager }
14
+ stub(manager).storage_for(:key) { storage }
15
+ stub(subject).me { dcell_node }
16
+ end
17
+
18
+ describe "#me" do
19
+ it "returns current node" do
20
+ subject.me.should == dcell_node
21
+ end
22
+ end
23
+
24
+ describe "#storage" do
25
+ it "returns storage of node" do
26
+ subject.storage.should == storage
27
+ end
28
+ end
29
+
30
+ describe "#manager" do
31
+ it "it returns manager of node" do
32
+ subject.manager.should == manager
33
+ end
34
+ end
35
+
36
+ describe "#[]=" do
37
+ it "store value in storage" do
38
+ mock(storage).store(:key, :value) { :value }
39
+ subject.store(:key, :value).should == :value
40
+ end
41
+
42
+ it "store key in another node" do
43
+ mock(manager).storage_for(:key) { storage2 }
44
+ mock(storage2).store(:key, :value) { :value }
45
+
46
+ subject.store(:key, :value).should == :value
47
+ end
48
+ end
49
+
50
+ describe "#[]" do
51
+ it "gets key from current node" do
52
+ mock(storage).get(:key) { :value }
53
+ mock(manager).storage_for(:key) { storage }
54
+
55
+ subject[:key].should == :value
56
+ end
57
+
58
+ it "cannot find key on closets node" do
59
+ mock(storage).get(:key) { nil }
60
+ mock(manager).storage_for(:key) { storage }
61
+
62
+ subject[:key].should == nil
63
+ end
64
+
65
+ it "get key from other node" do
66
+ mock(manager).storage_for(:key) { storage2 }
67
+ mock(storage2).get(:key) { :value }
68
+
69
+ subject[:key].should == :value
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'dht/key'
5
+
6
+ module DHT
7
+ describe Key do
8
+ before do
9
+ @key = Key.new "\v\xEE\xC7\xB5\xEA?\x0F\xDB\xC9]\r\xD4\x7F<[\xC2u\xDA\x000".force_encoding('binary')
10
+ end
11
+
12
+ it 'initializes from a hex String' do
13
+ Key.new('0beec7b5ea3f0fdbc95d0dd47f3c5bc275da0030').should == @key
14
+ end
15
+
16
+ it 'converts to an Integer' do
17
+ @key.to_i.should == 68123873083688143418383284816464454849230667824
18
+ end
19
+
20
+ it 'computes distance to another key' do
21
+ k = @key.to_i
22
+
23
+ @key.distance_to( k ).should == 0
24
+ for bit in 0...(Key::Size*8)
25
+ mask = 1 << bit
26
+ @key.distance_to( k ^ mask ).should == mask
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,70 @@
1
+ require "spec_helper"
2
+
3
+ module DHT
4
+ describe Manager do
5
+ let(:key) { Key.for_content("key") }
6
+ let(:node) { fake(:addr => "127.0.0.1") }
7
+ let(:node2) { fake }
8
+
9
+ fake(:storage, :key => Key.for_content("node"))
10
+ fake(:storage2, :key => Key.for_content("node2")) { Storage }
11
+ fake(:manager)
12
+ fake(:manager2) { Manager }
13
+
14
+ before do
15
+ stub(storage).key { key }
16
+ stub(node).[](:storage) { storage }
17
+ stub(node).[](:manager) { manager }
18
+ stub(node2).[](:storage) { storage2 }
19
+ stub(node2).[](:manager) { manager2 }
20
+ stub(subject).me { node }
21
+ stub(subject).dcell_nodes { [node] }
22
+ end
23
+
24
+ describe "#nodes" do
25
+ it "returns DCell nodes" do
26
+ subject.nodes.should == { key => node }
27
+ end
28
+ end
29
+
30
+ describe "#find_nodes" do
31
+ it "find nodes will fill @nodes array" do
32
+ subject.nodes.should == subject.find_nodes
33
+ end
34
+ end
35
+
36
+ describe "#key" do
37
+ it "returns key for addr of node" do
38
+ subject.key.should be_kind_of(Key)
39
+ subject.key.to_binary.should == Digest::SHA1.digest(node.addr)
40
+ end
41
+ end
42
+
43
+ describe "#storage_for" do
44
+ it "returns current node" do
45
+ mock(subject).node_for(:key) { node }
46
+
47
+ subject.storage_for(:key).should == storage
48
+ end
49
+
50
+ it "returns another node another node" do
51
+ mock(subject).node_for(:key) { node2 }
52
+ mock(manager2).storage_for(:key) { storage2 }
53
+
54
+ subject.storage_for(:key).should == storage2
55
+ end
56
+ end
57
+
58
+ describe "#node_for" do
59
+ before { mock(subject).dcell_nodes { [node, node2] } }
60
+
61
+ it "find closets node for :key" do
62
+ subject.node_for(:key).should == node
63
+ end
64
+
65
+ it "find closets node for :key_2" do
66
+ subject.node_for(:key22).should == node2
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,68 @@
1
+ require "spec_helper"
2
+
3
+ module DHT
4
+ describe Node do
5
+ let(:name) { "default" }
6
+ let(:address) { "127.0.0.1" }
7
+ let(:port) { 3000 }
8
+ let(:explorer) { false }
9
+ let(:options) { {:name => name, :host => address, :port => port, :explorer => explorer} }
10
+
11
+ subject { Node.new(options) }
12
+
13
+ describe "#configuration" do
14
+ it "returns configuration for DCell" do
15
+ node = Node.new
16
+ node.configuration[:id].should == name
17
+ node.configuration[:addr].should == "tcp://#{address}:#{port}"
18
+ node.configuration[:directory].should be_nil
19
+ end
20
+
21
+ context "custom name" do
22
+ let(:name) { "custom_name" }
23
+
24
+ it "returns custom node name for DCell" do
25
+ subject.configuration[:id].should == name
26
+ end
27
+ end
28
+
29
+ context "custom address" do
30
+ let(:address) { "google.com" }
31
+
32
+ it "returns custom address for DCell" do
33
+ subject.configuration[:addr].should == "tcp://#{address}:#{port}"
34
+ end
35
+ end
36
+
37
+ context "custom port" do
38
+ let(:port) { 9000 }
39
+
40
+ it "returns custom port for DCell" do
41
+ subject.configuration[:addr].should == "tcp://#{address}:#{port}"
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "#key" do
47
+ its(:key) { should == Key.new(Digest::SHA1.digest("#{name}:#{address}:#{port}")) }
48
+ end
49
+
50
+ describe "#start" do
51
+ fake_class(DCell)
52
+ fake(:service)
53
+
54
+ before do
55
+ stub(service).run { true }
56
+ stub(DHT::Service).new(:key => subject.key, :explorer => explorer) { service }
57
+ end
58
+
59
+ it "start DCell node" do
60
+ subject.start
61
+ end
62
+
63
+ it "start DHT::Service" do
64
+ service.run.should == true
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,30 @@
1
+ require "spec_helper"
2
+
3
+ module DHT
4
+ describe Service do
5
+ let(:key) { Key.for_content("example") }
6
+ let(:explorer) { true }
7
+
8
+ subject { Service.new(:explorer => explorer, :key => key) }
9
+
10
+ before do
11
+ stub(subject).create_storage
12
+ stub(subject).create_manager
13
+ stub(subject).create_explorer
14
+ end
15
+
16
+ it "enables services" do
17
+ subject.run
18
+ subject.should have_received.create_explorer
19
+ end
20
+
21
+ describe "disabled explorer" do
22
+ let(:explorer) { false }
23
+
24
+ it "does not enable explorer" do
25
+ subject.run
26
+ subject.should_not have_received.create_explorer
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ module DHT
4
+ describe Storage do
5
+ fake(:key)
6
+ subject { Storage.new(key) }
7
+
8
+ it "saves key and value to database" do
9
+ subject.store(:key, "value")
10
+
11
+ subject.database.keys.should include(:key)
12
+ subject.database.values.should include("value")
13
+ subject.database[:key].should == "value"
14
+ end
15
+
16
+ it "saves to database with #[]= method" do
17
+ subject[:key] = "value"
18
+
19
+ subject.database[:key].should == "value"
20
+ end
21
+
22
+ it "reads from database with #[] method" do
23
+ subject[:key] = "value"
24
+
25
+ subject[:key].should == "value"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe "integration specs" do
4
+ before(:all) do
5
+ Redis.new.flushall
6
+ @test_node = TestNode.new
7
+ @test_node.spawn
8
+ @hash = DHT::Hash.new
9
+ end
10
+
11
+ after(:all) do
12
+ @test_node.stop
13
+ end
14
+
15
+ it "recognize another node" do
16
+ @hash.manager.nodes.count.should == 2
17
+ end
18
+
19
+ it "saves key and value in current node" do
20
+ @hash[:key_100] = :value_100
21
+
22
+ @hash.storage.database.should include(:key_100 => :value_100)
23
+ @hash[:key_100].should == :value_100
24
+ end
25
+
26
+ it "saves key and value in another node" do
27
+ @hash[:key_101] = :value_101
28
+
29
+ @hash.storage.database.should_not include(:key_101 => :value_101)
30
+ @hash[:key_101].should == :value_101
31
+ end
32
+
33
+ it "replaces value in network" do
34
+ @hash[:key_101] = :value_101
35
+ @hash[:key_101] = :changed
36
+
37
+ @hash[:key_101].should == :changed
38
+ end
39
+
40
+
41
+ end
@@ -0,0 +1,15 @@
1
+ $LOAD_PATH << File.dirname(__FILE__) + '/..'
2
+
3
+ require 'coveralls'
4
+ Coveralls.wear!
5
+
6
+ require 'rspec'
7
+ require 'bogus/rspec'
8
+ require 'bbq/spawn'
9
+ require 'dht/hash'
10
+
11
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
12
+
13
+ Bogus.configure do |c|
14
+ c.search_modules << DHT
15
+ end
@@ -0,0 +1,15 @@
1
+ module Celluloid
2
+ class Method
3
+ def name
4
+ @proxy.method_missing(:method, @name).name
5
+ end
6
+
7
+ def parameters
8
+ @proxy.method_missing(:method, @name).parameters
9
+ end
10
+
11
+ def to_proc
12
+ @proxy.method_missing(:method, @name).to_proc
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ require 'bbq/spawn'
2
+
3
+ class TestNode
4
+ include Bbq::Spawn
5
+
6
+ def initialize(options = {})
7
+ @port = options.delete(:port) || "3002"
8
+ end
9
+
10
+ def spawn
11
+ orchestrator.start
12
+ end
13
+
14
+ def stop
15
+ orchestrator.stop
16
+ end
17
+
18
+ private
19
+
20
+ def executable
21
+ File.expand_path("../../../bin/dht_cell.rb", __FILE__)
22
+ end
23
+
24
+ def executor
25
+ Executor.new("bundle", "exec", "ruby", executable, "--port", @port, "--name", "node")
26
+ end
27
+
28
+ def orchestrator
29
+ @orchestrator ||= Orchestrator.new.tap do |orchestrator|
30
+ orchestrator.coordinate(executor, :host => "127.0.0.1", :port => @port)
31
+ end
32
+ end
33
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dht
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Piotr Niełacny
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: dcell
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Ruby DHT hash
31
+ email:
32
+ - piotr.nielacny@gmail.com
33
+ executables:
34
+ - dht_cell.rb
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - .coveralls.yml
39
+ - .gitignore
40
+ - .travis.yml
41
+ - Gemfile
42
+ - Gemfile.lock
43
+ - MIT-LICENSE
44
+ - README.md
45
+ - Rakefile
46
+ - bin/dht_cell.rb
47
+ - dht.gemspec
48
+ - lib/dht/hash.rb
49
+ - lib/dht/key.rb
50
+ - lib/dht/manager.rb
51
+ - lib/dht/node.rb
52
+ - lib/dht/service.rb
53
+ - lib/dht/storage.rb
54
+ - lib/dht/version.rb
55
+ - spec/dht/hash_spec.rb
56
+ - spec/dht/key_spec.rb
57
+ - spec/dht/manager_spec.rb
58
+ - spec/dht/node_spec.rb
59
+ - spec/dht/service_spec.rb
60
+ - spec/dht/storage_spec.rb
61
+ - spec/integration_spec.rb
62
+ - spec/spec_helper.rb
63
+ - spec/support/celluloid_method.rb
64
+ - spec/support/test_node.rb
65
+ homepage: https://github.com/LTe/dht
66
+ licenses: []
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: 1.9.3
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ segments:
84
+ - 0
85
+ hash: 4193095747413724244
86
+ requirements: []
87
+ rubyforge_project:
88
+ rubygems_version: 1.8.25
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Implementation of the Distributed Hash Table (DHT) in Ruby
92
+ test_files: []