distribustream 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,146 @@
1
+ #--
2
+ # Copyright (C) 2006-07 ClickCaster, Inc. (info@clickcaster.com)
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ #
17
+ # This source file is distributed as part of the
18
+ # DistribuStream file transfer system.
19
+ #
20
+ # See http://distribustream.org/
21
+ #++
22
+
23
+ require File.dirname(__FILE__) + '/transfer'
24
+
25
+ module PDTP
26
+ class Server
27
+ # Decision-making logic for initiating peer-to-peer transfers
28
+ class TransferManager
29
+ def initialize(connections, file_service)
30
+ @connections, @file_service = connections, file_service
31
+ @updated_clients = []
32
+ end
33
+
34
+ # Add client to list of ones needing updates
35
+ def process_client(client)
36
+ @updated_clients << client
37
+ end
38
+
39
+ # Creates new transfers for all clients that have been updated
40
+ def spawn_all_transfers
41
+ @updated_clients.each { |client| spawn_transfers_for_client(client) }
42
+ @updated_clients.clear
43
+ end
44
+
45
+ #########
46
+ protected
47
+ #########
48
+
49
+ # Spawns uploads and downloads for this client.
50
+ # Should be called every time there is a change that would affect
51
+ # what this client has or wants
52
+ def spawn_transfers_for_client(connection)
53
+ while connection.wants_download? do
54
+ break unless spawn_download_for_client(connection)
55
+ end
56
+
57
+ while connection.wants_upload? do
58
+ break unless spawn_upload_for_client(connection)
59
+ end
60
+ end
61
+
62
+ # Creates a single download for the specified client
63
+ # Returns true on success, false on failure
64
+ def spawn_download_for_client(connection)
65
+ feasible_peers = []
66
+
67
+ begin
68
+ url, chunkid = connection.chunk_info.high_priority_chunk
69
+ rescue
70
+ return false
71
+ end
72
+
73
+ @connections.each do |c2|
74
+ next if connection == c2
75
+ next unless c2.wants_upload?
76
+ if c2.chunk_info.provided?(url, chunkid)
77
+ feasible_peers << c2
78
+ break if feasible_peers.size > 5
79
+ end
80
+ end
81
+
82
+ # we now have a list of clients that have the requested chunk.
83
+ # pick one and start the transfer
84
+ if feasible_peers.size > 0
85
+ #FIXME base this on the trust model
86
+ giver = feasible_peers[rand(feasible_peers.size)]
87
+ return begin_transfer(connection,giver,url,chunkid)
88
+ #FIXME should we try again if begin_transfer fails?
89
+ end
90
+
91
+ false
92
+ end
93
+
94
+ # Creates a single upload for the specified client
95
+ # Returns true on success, false on failure
96
+ def spawn_upload_for_client(connection)
97
+ @connections.each do |c2|
98
+ next if connection == c2
99
+ next unless c2.wants_download?
100
+
101
+ begin
102
+ url, chunkid = c2.chunk_info.high_priority_chunk
103
+ rescue
104
+ next
105
+ end
106
+
107
+ if connection.chunk_info.provided?(url, chunkid)
108
+ return begin_transfer(c2, connection, url, chunkid)
109
+ end
110
+ end
111
+
112
+ false
113
+ end
114
+
115
+ # Creates a new transfer between two peers
116
+ # Returns true on success, or false if the specified transfer is already in progress
117
+ def begin_transfer(taker, giver, url, chunkid)
118
+ byte_range = @file_service.get_info(url).chunk_range(chunkid)
119
+ t = Transfer.new(taker, giver, url, chunkid, byte_range)
120
+
121
+ #make sure this transfer doesnt already exist
122
+ t1 = taker.transfers[t.transfer_id]
123
+ t2 = giver.transfers[t.transfer_id]
124
+ return false unless t1.nil? and t2.nil?
125
+
126
+ taker.chunk_info.transfer(url, chunkid..chunkid)
127
+ taker.transfers[t.transfer_id] = t
128
+ giver.transfers[t.transfer_id] = t
129
+
130
+ #send transfer message to the connector
131
+ addr, port = t.acceptor.get_peer_info
132
+
133
+ t.connector.send_message(:transfer,
134
+ :host => addr,
135
+ :port => t.acceptor.listen_port,
136
+ :method => t.connector == t.taker ? "get" : "put",
137
+ :url => url,
138
+ :range => byte_range,
139
+ :peer_id => t.acceptor.client_id
140
+ )
141
+
142
+ true
143
+ end
144
+ end
145
+ end
146
+ end
data/status/index.erb CHANGED
@@ -12,24 +12,38 @@
12
12
  </div>
13
13
  <center>
14
14
  <table border="0" cellpadding="0" cellspacing="0">
15
- <tr><th>Client</th><th>Transfers</th><th>Files</th></tr>
15
+ <tr>
16
+ <th>Client</th>
17
+ <th>Bandwidth</th>
18
+ <th>Transfers</th>
19
+ <th>Files</th>
20
+ </tr>
21
+
16
22
  <% each_peer do |peer| %>
17
- <tr class="row<%= cycle(' row_alternate', '') %>"><td>
18
- <%= peer_name(peer) %><br />
19
- <%= peer_address(peer) %>
20
- </td>
21
- <td>
22
- <% each_transfer(peer) do |transfer| %>
23
- <%= transfer_info(peer, transfer) %><br />
24
- <% end %>
25
- </td>
26
- <td>
27
- <% each_file(peer) do |file| %>
28
- <%= file_path(file) %>
29
- (<%= chunks_completed(file) %>/<%= chunks_active(file) %>,
30
- <%= percent_complete(file) %>%)<br />
31
- <% end %>
32
- </td></tr>
23
+ <tr class="row<%= cycle(' row_alternate', '') %>">
24
+ <td>
25
+ <%= peer_name(peer) %><br />
26
+ <%= peer_address(peer) %>
27
+ </td>
28
+ <td>
29
+ Upstream: <%= upstream_bandwidth(peer) %><br />
30
+ <% unless peer.file_service? %>
31
+ Downstream: <%= downstream_bandwidth(peer) %>
32
+ <% end %>
33
+ </td>
34
+ <td>
35
+ <% each_transfer(peer) do |transfer| %>
36
+ <%= transfer_info(peer, transfer) %><br />
37
+ <% end %>
38
+ </td>
39
+ <td>
40
+ <% each_file(peer) do |file| %>
41
+ <%= file_path(file) %>
42
+ (<%= chunks_completed(file) %>/<%= chunks_active(file) %>,
43
+ <%= percent_complete(file) %>%)<br />
44
+ <% end %>
45
+ </td>
46
+ </tr>
33
47
  <% end %>
34
48
  </table>
35
49
  </center>
@@ -38,5 +38,5 @@ td {
38
38
  }
39
39
 
40
40
  .row_alternate {
41
- background: #EEEEEE;
41
+ background: #E0E0E0;
42
42
  }
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.0
2
+ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: distribustream
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.4.1
7
- date: 2008-11-15 00:00:00 -07:00
6
+ version: 0.5.0
7
+ date: 2008-11-27 00:00:00 -07:00
8
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
9
  require_paths:
10
10
  - lib
@@ -33,43 +33,45 @@ authors:
33
33
  - James Sanders
34
34
  - Tom Stapleton
35
35
  files:
36
- - bin/dstream
37
36
  - bin/dsclient
37
+ - bin/dstream
38
38
  - lib/pdtp
39
- - lib/pdtp/server
40
- - lib/pdtp/common.rb
41
39
  - lib/pdtp/client
42
- - lib/pdtp/common
43
- - lib/pdtp/client.rb
44
- - lib/pdtp/server.rb
45
- - lib/pdtp/server/file_service_protocol.rb
46
- - lib/pdtp/server/status_handler.rb
47
- - lib/pdtp/server/trust.rb
48
- - lib/pdtp/server/status_helper.rb
49
- - lib/pdtp/server/transfer.rb
50
- - lib/pdtp/server/client_info.rb
51
- - lib/pdtp/server/connection.rb
52
- - lib/pdtp/server/file_service.rb
53
- - lib/pdtp/server/dispatcher.rb
40
+ - lib/pdtp/client/callbacks.rb
41
+ - lib/pdtp/client/connection.rb
54
42
  - lib/pdtp/client/file_buffer.rb
43
+ - lib/pdtp/client/file_service.rb
55
44
  - lib/pdtp/client/http_client.rb
56
45
  - lib/pdtp/client/http_handler.rb
57
- - lib/pdtp/client/callbacks.rb
58
46
  - lib/pdtp/client/transfer.rb
59
- - lib/pdtp/client/connection.rb
60
- - lib/pdtp/client/file_service.rb
61
- - lib/pdtp/common/length_prefix_protocol.rb
47
+ - lib/pdtp/client.rb
48
+ - lib/pdtp/common
49
+ - lib/pdtp/common/file_service.rb
62
50
  - lib/pdtp/common/http_server.rb
51
+ - lib/pdtp/common/length_prefix_protocol.rb
63
52
  - lib/pdtp/common/protocol.rb
64
- - lib/pdtp/common/file_service.rb
65
- - conf/example.yml
53
+ - lib/pdtp/common.rb
54
+ - lib/pdtp/server
55
+ - lib/pdtp/server/bandwidth_estimator.rb
56
+ - lib/pdtp/server/chunk_info.rb
57
+ - lib/pdtp/server/connection.rb
58
+ - lib/pdtp/server/dispatcher.rb
59
+ - lib/pdtp/server/file_service.rb
60
+ - lib/pdtp/server/file_service_protocol.rb
61
+ - lib/pdtp/server/status_handler.rb
62
+ - lib/pdtp/server/status_helper.rb
63
+ - lib/pdtp/server/transfer.rb
64
+ - lib/pdtp/server/transfer_manager.rb
65
+ - lib/pdtp/server/trust.rb
66
+ - lib/pdtp/server.rb
66
67
  - conf/bigchunk.yml
67
68
  - conf/debug.yml
68
- - status/stylesheets
69
+ - conf/example.yml
69
70
  - status/images
71
+ - status/images/logo.png
70
72
  - status/index.erb
73
+ - status/stylesheets
71
74
  - status/stylesheets/style.css
72
- - status/images/logo.png
73
75
  - Rakefile
74
76
  - distribustream.gemspec
75
77
  - COPYING
@@ -79,10 +81,11 @@ files:
79
81
  test_files: []
80
82
 
81
83
  rdoc_options:
82
- - --exclude
83
- - definitions
84
- - --exclude
85
- - indexes
84
+ - --title
85
+ - PDTP
86
+ - --main
87
+ - README
88
+ - --line-numbers
86
89
  extra_rdoc_files:
87
90
  - COPYING
88
91
  - README
@@ -1,154 +0,0 @@
1
- #--
2
- # Copyright (C) 2006-07 ClickCaster, Inc. (info@clickcaster.com)
3
- #
4
- # This program is free software: you can redistribute it and/or modify
5
- # it under the terms of the GNU General Public License as published by
6
- # the Free Software Foundation, either version 3 of the License, or
7
- # (at your option) any later version.
8
- #
9
- # This program is distributed in the hope that it will be useful,
10
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- # GNU General Public License for more details.
13
- #
14
- # You should have received a copy of the GNU General Public License
15
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
- #
17
- # This source file is distributed as part of the
18
- # DistribuStream file transfer system.
19
- #
20
- # See http://distribustream.org/
21
- #++
22
-
23
- require File.dirname(__FILE__) + '/trust'
24
-
25
- module PDTP
26
- class Server
27
- #stores information about a single connected client
28
- class ClientInfo
29
- attr_accessor :chunk_info, :trust
30
- attr_accessor :listen_port, :client_id
31
- attr_accessor :transfers
32
-
33
- def initialize
34
- @chunk_info=ChunkInfo.new
35
- @listen_port=6000 #default
36
- @trust=Trust.new
37
- @transfers=Hash.new
38
- end
39
-
40
- # returns true if this client wants the server to spawn a transfer for it
41
- def wants_download?
42
- transfer_state_allowed=5
43
- total_allowed=10
44
- transferring=0
45
- @transfers.each do |key, t|
46
- transferring=transferring+1 if t.verification_asked
47
- return false if transferring >= transfer_state_allowed
48
- end
49
-
50
- @transfers.size < total_allowed
51
- end
52
-
53
- #this could have a different definition, but it works fine to use wants_download?
54
- alias_method :wants_upload?, :wants_download?
55
-
56
- #returns a list of all the stalled transfers this client is a part of
57
- def get_stalled_transfers
58
- stalled=[]
59
- timeout=20.0
60
- now=Time.now
61
- @transfers.each do |key,t|
62
- #only delete if we are the acceptor to prevent race conditions
63
- next if t.acceptor.user_data != self
64
- if now-t.creation_time > timeout and not t.verification_asked
65
- stalled << t
66
- end
67
- end
68
- stalled
69
- end
70
- end
71
-
72
- #stores information about the chunks requested or provided by a client
73
- class ChunkInfo
74
- def initialize
75
- @files={}
76
- end
77
-
78
- #each chunk can either be provided, requested, transfer, or none
79
- def provide(filename,range); set(filename,range,:provided) ; end
80
- def unprovide(filename,range); set(filename,range, :none); end
81
- def request(filename,range); set(filename,range, :requested); end
82
- def unrequest(filename,range); set(filename,range, :none); end
83
- def transfer(filename,range); set(filename,range, :transfer); end
84
-
85
- def provided?(filename,chunk); get(filename,chunk) == :provided; end
86
- def requested?(filename,chunk); get(filename,chunk) == :requested; end
87
-
88
- #returns a high priority requested chunk
89
- def high_priority_chunk
90
- #right now return any chunk
91
- @files.each do |name,file|
92
- file.each_index do |i|
93
- return [name,i] if file[i]==:requested
94
- end
95
- end
96
-
97
- nil
98
- end
99
-
100
- #calls a block for each chunk of the specified type
101
- def each_chunk_of_type(type)
102
- @files.each do |name,file|
103
- file.each_index do |i|
104
- yield(name,i) if file[i]==type
105
- end
106
- end
107
- end
108
-
109
- class FileStats
110
- attr_accessor :file_chunks, :chunks_requested,:url
111
- attr_accessor :chunks_provided, :chunks_transferring
112
-
113
- def initialize
114
- @url=""
115
- @file_chunks=0
116
- @chunks_requested=0
117
- @chunks_provided=0
118
- @chunks_transferring=0
119
- end
120
- end
121
-
122
- #returns an array of FileStats objects for debug output
123
- def get_file_stats
124
- stats=[]
125
- @files.each do |name,file|
126
- fs=FileStats.new
127
- fs.file_chunks=file.size
128
- fs.url=name
129
- file.each do |chunk|
130
- fs.chunks_requested+=1 if chunk==:requested
131
- fs.chunks_provided+=1 if chunk==:provided
132
- fs.chunks_transferring+=1 if chunk==:transfer
133
- end
134
- stats << fs
135
- end
136
-
137
- stats
138
- end
139
-
140
- #########
141
- protected
142
- #########
143
-
144
- def get(filename,chunk)
145
- @files[filename][chunk] rescue :neither
146
- end
147
-
148
- def set(filename,range,state)
149
- chunks=@files[filename]||=Array.new
150
- range.each { |i| chunks[i]=state }
151
- end
152
- end
153
- end
154
- end