dht 0.0.1

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