distribustream 0.1.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.
- data/CHANGES +2 -0
- data/COPYING +674 -0
- data/README +107 -0
- data/Rakefile +44 -0
- data/bin/distribustream +60 -0
- data/bin/dsclient +43 -0
- data/bin/dsseed +103 -0
- data/conf/bigchunk.yml +18 -0
- data/conf/debug.yml +18 -0
- data/conf/example.yml +18 -0
- data/distribustream.gemspec +20 -0
- data/lib/pdtp/client.rb +195 -0
- data/lib/pdtp/client/file_buffer.rb +128 -0
- data/lib/pdtp/client/file_buffer_spec.rb +154 -0
- data/lib/pdtp/client/file_service.rb +60 -0
- data/lib/pdtp/client/protocol.rb +66 -0
- data/lib/pdtp/client/transfer.rb +229 -0
- data/lib/pdtp/common/common_init.rb +122 -0
- data/lib/pdtp/common/file_service.rb +69 -0
- data/lib/pdtp/common/file_service_spec.rb +91 -0
- data/lib/pdtp/common/protocol.rb +346 -0
- data/lib/pdtp/common/protocol_spec.rb +68 -0
- data/lib/pdtp/server.rb +368 -0
- data/lib/pdtp/server/client_info.rb +140 -0
- data/lib/pdtp/server/file_service.rb +89 -0
- data/lib/pdtp/server/transfer.rb +62 -0
- data/lib/pdtp/server/trust.rb +88 -0
- data/lib/pdtp/server/trust_spec.rb +40 -0
- metadata +114 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (C) 2006-07 ClickCaster, Inc. (info@clickcaster.com)
|
3
|
+
# All rights reserved. See COPYING for permissions.
|
4
|
+
#
|
5
|
+
# This source file is distributed as part of the
|
6
|
+
# DistribuStream file transfer system.
|
7
|
+
#
|
8
|
+
# See http://distribustream.rubyforge.org/
|
9
|
+
#++
|
10
|
+
|
11
|
+
require "uri"
|
12
|
+
require "pathname"
|
13
|
+
require "digest/sha2"
|
14
|
+
require File.dirname(__FILE__) + '/../common/file_service.rb'
|
15
|
+
|
16
|
+
module PDTP
|
17
|
+
class Server
|
18
|
+
#The server specific file utilities
|
19
|
+
class FileInfo < PDTP::FileInfo
|
20
|
+
attr_accessor :path
|
21
|
+
|
22
|
+
#Return a raw string of chunk data. The range parameter is local to this chunk
|
23
|
+
#and zero based
|
24
|
+
def chunk_data(chunkid, range = nil)
|
25
|
+
begin
|
26
|
+
range = 0..chunk_size(chunkid) - 1 if range.nil? # full range of chunk if range isnt specified
|
27
|
+
raise if range.first < 0 or range.last >= chunk_size(chunkid)
|
28
|
+
start = range.first + chunkid * @base_chunk_size
|
29
|
+
size = range.last-range.first + 1
|
30
|
+
file = open @path
|
31
|
+
file.pos = start
|
32
|
+
file.read size
|
33
|
+
rescue nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
#reads the specified byte range from the file and returns it as a string
|
38
|
+
def read(range)
|
39
|
+
#puts "READING: range=#{range}"
|
40
|
+
begin
|
41
|
+
file = open @path
|
42
|
+
file.pos = range.first
|
43
|
+
file.read range.last - range.first + 1
|
44
|
+
rescue nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
#The file service provides utilities for determining various information about files.
|
50
|
+
class FileService < PDTP::FileService
|
51
|
+
attr_accessor :root,:default_chunk_size
|
52
|
+
|
53
|
+
def initialize
|
54
|
+
@root = ''
|
55
|
+
@default_chunk_size = 512
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_info(url)
|
59
|
+
begin
|
60
|
+
host = URI.split(url)[2]
|
61
|
+
#FIXME we should check host against a list of known hosts here
|
62
|
+
info = FileInfo.new
|
63
|
+
info.streaming = false
|
64
|
+
info.base_chunk_size = @default_chunk_size
|
65
|
+
info.path = get_local_path(url)
|
66
|
+
raise if File.directory?(info.path)
|
67
|
+
info.file_size = File.size?(info.path)
|
68
|
+
return nil if info.file_size == 0 or info.file_size.nil?
|
69
|
+
rescue
|
70
|
+
return nil
|
71
|
+
end
|
72
|
+
|
73
|
+
info
|
74
|
+
end
|
75
|
+
|
76
|
+
#returns the path of this file on the local filesystem
|
77
|
+
def get_local_path(url)
|
78
|
+
path = URI.split(url)[5]
|
79
|
+
path = path[1..path.size-1] #remove leading /
|
80
|
+
(Pathname.new(@root) + path).to_s
|
81
|
+
end
|
82
|
+
|
83
|
+
#returns the SHA256 hash of the specified chunk
|
84
|
+
def get_chunk_hash(url,chunk_id)
|
85
|
+
Digest::SHA256.hexdigest(get_info(url).chunk_data(chunk_id)) rescue nil
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (C) 2006-07 ClickCaster, Inc. (info@clickcaster.com)
|
3
|
+
# All rights reserved. See COPYING for permissions.
|
4
|
+
#
|
5
|
+
# This source file is distributed as part of the
|
6
|
+
# DistribuStream file transfer system.
|
7
|
+
#
|
8
|
+
# See http://distribustream.rubyforge.org/
|
9
|
+
#++
|
10
|
+
|
11
|
+
module PDTP
|
12
|
+
class Server
|
13
|
+
#stores information for the server about a specific transfer
|
14
|
+
class Transfer
|
15
|
+
attr_reader :taker, :giver, :url, :chunkid
|
16
|
+
attr_reader :connector, :acceptor, :byte_range
|
17
|
+
attr_accessor :transfer_id
|
18
|
+
attr_accessor :creation_time
|
19
|
+
attr_accessor :verification_asked
|
20
|
+
|
21
|
+
def initialize(taker,giver,url,chunkid,byte_range,connector_receives=true)
|
22
|
+
@taker,@giver,@url,@chunkid,@byte_range=taker,giver,url,chunkid,byte_range
|
23
|
+
|
24
|
+
@verification_asked = false
|
25
|
+
@creation_time = Time.now
|
26
|
+
if connector_receives
|
27
|
+
@connector=@taker
|
28
|
+
@acceptor=@giver
|
29
|
+
else
|
30
|
+
@connector=@giver
|
31
|
+
@acceptor=@taker
|
32
|
+
end
|
33
|
+
|
34
|
+
recompute_transfer_id
|
35
|
+
end
|
36
|
+
|
37
|
+
#calculates the transfer id for this transfer based on the local data
|
38
|
+
def recompute_transfer_id
|
39
|
+
id1=connector.user_data.client_id
|
40
|
+
id2=acceptor.user_data.client_id
|
41
|
+
@transfer_id=Transfer::gen_transfer_id(id1,id2,@url,@byte_range)
|
42
|
+
end
|
43
|
+
|
44
|
+
#generates a transfer id based on 2 client ids, a url, and a byte range
|
45
|
+
def self.gen_transfer_id(id1,id2,url,byte_range)
|
46
|
+
a = id1<id2 ? id1 : id2
|
47
|
+
b = id1<id2 ? id2 : id1
|
48
|
+
"#{a}$#{b}$#{url}$#{byte_range}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
"taker=#{@taker}, giver=#{@giver}, connector=#{@connector}, acceptor=#{@acceptor}, url=#{@url}, chunk_id=#{@chunkid} range=#{@byte_range}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def debug_str
|
56
|
+
str = ''
|
57
|
+
str << "to_s=#{to_s}"
|
58
|
+
str << " taker_id=#{@taker.user_data.client_id} giver_id=#{@giver.user_data.client_id}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (C) 2006-07 ClickCaster, Inc. (info@clickcaster.com)
|
3
|
+
# All rights reserved. See COPYING for permissions.
|
4
|
+
#
|
5
|
+
# This source file is distributed as part of the
|
6
|
+
# DistribuStream file transfer system.
|
7
|
+
#
|
8
|
+
# See http://distribustream.rubyforge.org/
|
9
|
+
#++
|
10
|
+
|
11
|
+
module PDTP
|
12
|
+
#maintains trust information for a single client
|
13
|
+
class Trust
|
14
|
+
#struct for storing a single trust relationship
|
15
|
+
class Edge
|
16
|
+
attr_accessor :trust, :success, :transfers
|
17
|
+
|
18
|
+
def initialize(trust = 1.0, success = 1.0, transfers = 1.0)
|
19
|
+
@trust = trust
|
20
|
+
@success = success
|
21
|
+
@transfers = transfers
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :outgoing, :implicit
|
26
|
+
|
27
|
+
def initialize(incoming = {}, outgoing = {}, implicit = {})
|
28
|
+
@incoming = incoming
|
29
|
+
@outgoing = outgoing
|
30
|
+
@implicit = implicit
|
31
|
+
end
|
32
|
+
|
33
|
+
#I have successfully downloaded a chunk from 'node'
|
34
|
+
def success(node)
|
35
|
+
if @outgoing[node].nil?
|
36
|
+
@outgoing[node] = Edge.new
|
37
|
+
else
|
38
|
+
@outgoing[node].success += 1.0
|
39
|
+
@outgoing[node].transfers += 1.0
|
40
|
+
end
|
41
|
+
normalize
|
42
|
+
end
|
43
|
+
|
44
|
+
#I have failed to download a chunk from 'node'
|
45
|
+
def failure(node)
|
46
|
+
@outgoing[node] = Edge.new if @outgoing[node].nil?
|
47
|
+
@outgoing[node].transfers += 1.0
|
48
|
+
normalize
|
49
|
+
end
|
50
|
+
|
51
|
+
#returns a number from 0 to 1 saying how much I trust 'node'
|
52
|
+
def weight(node)
|
53
|
+
return @outgoing[node].trust unless @outgoing[node].nil?
|
54
|
+
return @implicit[node].trust unless @implicit[node].nil?
|
55
|
+
0
|
56
|
+
end
|
57
|
+
|
58
|
+
# brings all trust values between 0 and 1
|
59
|
+
def normalize
|
60
|
+
total_success = 0
|
61
|
+
total_transfers = 0
|
62
|
+
|
63
|
+
@outgoing.each do |_, link|
|
64
|
+
total_success += link.success
|
65
|
+
total_transfers += link.transfers
|
66
|
+
end
|
67
|
+
|
68
|
+
@outgoing.each { |_, link| link.trust = link.success / total_transfers }
|
69
|
+
@outgoing.each do |target, link|
|
70
|
+
[target.outgoing, target.implicit].each do |links|
|
71
|
+
links.each do |nextlinkedge|
|
72
|
+
nextlinktarget = nextlinkedge[0]
|
73
|
+
nextlink = nextlinkedge[1]
|
74
|
+
next unless outgoing[nextlinktarget].nil?
|
75
|
+
|
76
|
+
if implicit[nextlinktarget].nil? || implicit[nextlinktarget].trust < (link.trust * nextlink.trust)
|
77
|
+
implicit[nextlinktarget] = Edge.new(
|
78
|
+
link.trust * nextlink.trust,
|
79
|
+
nextlink.success,
|
80
|
+
nextlink.transfers
|
81
|
+
)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (C) 2006-07 ClickCaster, Inc. (info@clickcaster.com)
|
3
|
+
# All rights reserved. See COPYING for permissions.
|
4
|
+
#
|
5
|
+
# This source file is distributed as part of the
|
6
|
+
# DistribuStream file transfer system.
|
7
|
+
#
|
8
|
+
# See http://distribustream.rubyforge.org/
|
9
|
+
#++
|
10
|
+
|
11
|
+
require File.dirname(__FILE__) + '/trust'
|
12
|
+
|
13
|
+
describe 'A new trust node' do
|
14
|
+
before(:each) do
|
15
|
+
@node = PDTP::Trust.new
|
16
|
+
@other = PDTP::Trust.new
|
17
|
+
@distant = PDTP::Trust.new
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should be empty' do
|
21
|
+
@node.outgoing.should be_empty
|
22
|
+
@node.implicit.should be_empty
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should trust a node after a good transfer' do
|
26
|
+
@node.success(@other)
|
27
|
+
@node.outgoing.should_not be_empty
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should normalize trusts across outgoing edges' do
|
31
|
+
@node.success(@other)
|
32
|
+
trust = @node.weight(@other)
|
33
|
+
|
34
|
+
@node.success(@distant)
|
35
|
+
@node.outgoing.size.should == 2
|
36
|
+
|
37
|
+
@node.weight(@other).should < trust
|
38
|
+
(@node.weight(@other) + @node.weight(@distant)).should be_close(1.0, 0.00001)
|
39
|
+
end
|
40
|
+
end
|
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.0
|
3
|
+
specification_version: 1
|
4
|
+
name: distribustream
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2008-10-11 00:00:00 -06:00
|
8
|
+
summary: DistribuStream is a fully open peercasting system allowing on-demand or live streaming media to be delivered at a fraction of the normal cost
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: tony@clickcaster.com
|
12
|
+
homepage: http://distribustream.rubyforge.org
|
13
|
+
rubyforge_project: distribustream
|
14
|
+
description:
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Tony Arcieri
|
31
|
+
- Ashvin Mysore
|
32
|
+
- Galen Pahlke
|
33
|
+
- James Sanders
|
34
|
+
- Tom Stapleton
|
35
|
+
files:
|
36
|
+
- bin/distribustream
|
37
|
+
- bin/dsclient
|
38
|
+
- bin/dsseed
|
39
|
+
- lib/pdtp
|
40
|
+
- lib/pdtp/client
|
41
|
+
- lib/pdtp/client.rb
|
42
|
+
- lib/pdtp/common
|
43
|
+
- lib/pdtp/server
|
44
|
+
- lib/pdtp/server.rb
|
45
|
+
- lib/pdtp/client/file_buffer.rb
|
46
|
+
- lib/pdtp/client/file_buffer_spec.rb
|
47
|
+
- lib/pdtp/client/file_service.rb
|
48
|
+
- lib/pdtp/client/protocol.rb
|
49
|
+
- lib/pdtp/client/transfer.rb
|
50
|
+
- lib/pdtp/common/common_init.rb
|
51
|
+
- lib/pdtp/common/file_service.rb
|
52
|
+
- lib/pdtp/common/file_service_spec.rb
|
53
|
+
- lib/pdtp/common/protocol.rb
|
54
|
+
- lib/pdtp/common/protocol_spec.rb
|
55
|
+
- lib/pdtp/server/client_info.rb
|
56
|
+
- lib/pdtp/server/file_service.rb
|
57
|
+
- lib/pdtp/server/transfer.rb
|
58
|
+
- lib/pdtp/server/trust.rb
|
59
|
+
- lib/pdtp/server/trust_spec.rb
|
60
|
+
- conf/bigchunk.yml
|
61
|
+
- conf/debug.yml
|
62
|
+
- conf/example.yml
|
63
|
+
- Rakefile
|
64
|
+
- distribustream.gemspec
|
65
|
+
- COPYING
|
66
|
+
- README
|
67
|
+
- CHANGES
|
68
|
+
test_files: []
|
69
|
+
|
70
|
+
rdoc_options:
|
71
|
+
- --exclude
|
72
|
+
- definitions
|
73
|
+
- --exclude
|
74
|
+
- indexes
|
75
|
+
extra_rdoc_files:
|
76
|
+
- COPYING
|
77
|
+
- README
|
78
|
+
- CHANGES
|
79
|
+
executables:
|
80
|
+
- distribustream
|
81
|
+
- dsseed
|
82
|
+
- dsclient
|
83
|
+
extensions: []
|
84
|
+
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
dependencies:
|
88
|
+
- !ruby/object:Gem::Dependency
|
89
|
+
name: eventmachine
|
90
|
+
version_requirement:
|
91
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 0.9.0
|
96
|
+
version:
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: mongrel
|
99
|
+
version_requirement:
|
100
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: 1.0.1
|
105
|
+
version:
|
106
|
+
- !ruby/object:Gem::Dependency
|
107
|
+
name: json
|
108
|
+
version_requirement:
|
109
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: 1.1.0
|
114
|
+
version:
|