distribustream 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,8 @@
1
+ Version 0.2.1
2
+ * Switch HTTP client to use an EventMachine-based version, rather than net/http
3
+
4
+ * Added PDTP.version for retrieving version of the library
5
+
1
6
  Version 0.2.0
2
7
  * PDTP::Server and PDTP::Client now expose APIs intended for public consumption
3
8
  They may change slightly down the road, but will remain largely the same
data/README CHANGED
@@ -6,6 +6,11 @@ or live streaming media to be delivered at a fraction of the normal cost.
6
6
  This README covers the initial public release, known issues, and a general
7
7
  development roadmap.
8
8
 
9
+ Contents:
10
+ 1. Usage
11
+ 2. Known Issues
12
+ 3. Development Roadmap
13
+
9
14
  --
10
15
 
11
16
  Usage:
@@ -27,7 +32,7 @@ to identify as.
27
32
 
28
33
  Next, start the DistribuStream server:
29
34
 
30
- distribustream --conf myconfig.yml
35
+ dstream --conf myconfig.yml
31
36
 
32
37
  The DistribuStream server manages traffic on the peer network. It also handles
33
38
  the checksumming of files.
@@ -48,32 +53,19 @@ At this point your server is ready to go.
48
53
 
49
54
  To test your server, use the DistribuStream client:
50
55
 
51
- dsclient --url pdtp://myserver.url/file.ext
56
+ dsclient pdtp://myserver.url/file.ext
52
57
 
53
58
  This will download file.ext from your DistribuStream server.
54
59
 
55
- While you can't control the output filename at this point, the client supports
56
- non-seekable output such as pipes. To play streaming media as it downloads,
57
- you can:
60
+ The client also supports non-seekable output such as pipes. To play streaming
61
+ media as it downloads, you can:
58
62
 
59
- mkfifo file.ext
60
- dsclient --url pdtp://myserver.url/file.ext &
61
- mediaplayer file.ext
63
+ dsclient -o pdtp://myserver.url/file.ext | mediaplayer -
62
64
 
63
65
  --
64
66
 
65
67
  Known Issues:
66
68
 
67
- The client presently stores incoming data in a memory buffer. This causes
68
- the client to consume massive amounts of memory as the file downloads.
69
- Subsequent releases will fix this by improving the design of the memory
70
- buffer, moving to a disk-backed buffer and/or discarding some of the
71
- downloaded data after it's been played back.
72
-
73
- The protocol facilitates allowing clients to have a moving window of data
74
- in a stream, so they need not retain data which has already been displayed
75
- to the user.
76
-
77
69
  Seeds are presently not authenticated in any way, thus anyone can attach
78
70
  a seed and populate the server with any files of their choosing. However,
79
71
  since file checksumming is done by the server itself, this means that only
@@ -87,10 +79,6 @@ checksumming to the server <-> seed protocol.
87
79
 
88
80
  Development Roadmap:
89
81
 
90
- The immediate goal is to improve the performance of the client, which presently
91
- consumes far too much RAM for practical use with large media files. Another
92
- immediate goal is solving the above problems with seeds.
93
-
94
82
  DistribuStream uses an assemblage of various tools which do not work together
95
83
  particularly well. These include the EventMachine Ruby gem, which provides
96
84
  the I/O layer for the DistribuStream server, and the Mongrel web server, which
@@ -99,8 +87,17 @@ runs independently of EventMachine and uses threads.
99
87
  Initial work will focus on converting the existing implementation to a fully
100
88
  EventMachine-based approach which eliminates the use of threads.
101
89
 
102
- Subsequent work will focus on improving the APIs provided by the various
103
- components so that the client and server can both
90
+ Mid-term work will focus on improving the efficiency of peer-to-peer traffic
91
+ routing, by incorporating all of the following constraints:
92
+
93
+ 1. Does the potential "giver" peer have chunks the "taker" peer is requesting?
94
+ 2. Are the peers in the same prefix? (at least the same /16, if not the same /24)
95
+ 3. Are the peers firewalled? (the server could do a connect test as soon as a
96
+ client registers their listen port)
97
+ 4. What is the trust between peers? (the "random" connecting of untrusted peers
98
+ could be replaced by something that operates on the above two bits of data)
99
+ 5. Does the "giver" have enough bandwidth? (modeled over time)
100
+ 6. Are total inbound and outbound links minimized? (to improve TCP congestion)
104
101
 
105
102
  Long-term goals include a move to UDP to reduce protocol latency and overhead
106
103
  as well as encrypting all traffic to ensure privacy and security of the
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
 
3
3
  GEMSPEC = Gem::Specification.new do |s|
4
4
  s.name = "distribustream"
5
- s.version = "0.2.0"
5
+ s.version = "0.2.1"
6
6
  s.date = "2008-10-22"
7
7
  s.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"
8
8
  s.email = "tony@clickcaster.com"
data/lib/pdtp/client.rb CHANGED
@@ -13,6 +13,7 @@ require 'eventmachine'
13
13
  require 'thread'
14
14
  require 'digest/md5'
15
15
 
16
+ require File.dirname(__FILE__) + '/common'
16
17
  require File.dirname(__FILE__) + '/client/connection'
17
18
  require File.dirname(__FILE__) + '/client/callbacks'
18
19
  require File.dirname(__FILE__) + '/client/file_service'
@@ -57,18 +57,20 @@ module PDTP
57
57
  message,
58
58
  @client.file_service
59
59
  )
60
+
61
+ transfer.run
60
62
 
61
- @@log.debug "TRANSFER STARTING"
63
+ #@@log.debug "TRANSFER STARTING"
62
64
 
63
65
  # Run each transfer in its own thread and notify the server upon completion
64
- Thread.new(transfer) do |t|
65
- begin
66
- t.run
67
- rescue Exception=>e
68
- @@log.info("Exception in dispatch_message: " + e.exception + "\n" + e.backtrace.join("\n"))
69
- end
70
- t.send_completed_message(t.hash)
71
- end
66
+ #Thread.new(transfer) do |t|
67
+ # begin
68
+ # t.run
69
+ # rescue Exception=>e
70
+ # @@log.info("Exception in dispatch_message: " + e.exception + "\n" + e.backtrace.join("\n"))
71
+ # end
72
+ # t.send_completed_message(t.hash)
73
+ #end
72
74
  when "tell_verify"
73
75
  # We are a listener, and asked for verification of a transfer from a server.
74
76
  # After asking for verification, we stopped running, and must be restarted
@@ -0,0 +1,114 @@
1
+ # $Id: httpclient.rb 518 2007-08-30 10:17:02Z blackhedd $
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 16 July 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+
26
+ # This version of HttpClient has been modified for use in DistribuStream
27
+ # Notable changes:
28
+ # - Moved into PDTP::Client namespace
29
+ # - HTTP/1.1 switched to HTTP/1.0
30
+ # - Introduced support for HTTP ranges
31
+ # - Support for X headers
32
+
33
+ module PDTP
34
+ class Client
35
+ class HttpClient < EventMachine::Protocols::HttpClient
36
+ # Override send_request to support the additional features we need
37
+ def send_request args
38
+ args[:verb] ||= args[:method] # Support :method as an alternative to :verb.
39
+ args[:verb] ||= :get # IS THIS A GOOD IDEA, to default to GET if nothing was specified?
40
+
41
+ verb = args[:verb].to_s.upcase
42
+ unless ["GET", "POST", "PUT", "DELETE", "HEAD"].include?(verb)
43
+ set_deferred_status :failed, {:status => 0} # TODO, not signalling the error type
44
+ return # NOTE THE EARLY RETURN, we're not sending any data.
45
+ end
46
+
47
+ request = args[:request] || "/"
48
+ unless request[0,1] == "/"
49
+ request = "/" + request
50
+ end
51
+
52
+ qs = args[:query_string] || ""
53
+ if qs.length > 0 and qs[0,1] != '?'
54
+ qs = "?" + qs
55
+ end
56
+
57
+ # Allow an override for the host header if it's not the connect-string.
58
+ port = args[:port]
59
+ host = args[:host_header] || "#{args[:host]}#{port}" || "_"
60
+
61
+ # POST items.
62
+ postcontenttype = args[:contenttype] || "application/octet-stream"
63
+ postcontent = args[:content] || ""
64
+ raise "oversized content in HTTP POST" if postcontent.length > MaxPostContentLength
65
+
66
+ # ESSENTIAL for the request's line-endings to be CRLF, not LF. Some servers misbehave otherwise.
67
+ # TODO: We ASSUME the caller wants to send a 1.1 request. May not be a good assumption.
68
+ req = [
69
+ "#{verb} #{request}#{qs} HTTP/1.1",
70
+ "Host: #{host}",
71
+ "User-Agent: #{args[:agent] || 'Ruby EventMachine'}"
72
+ ]
73
+
74
+ if verb == "POST" || verb == "PUT"
75
+ req << "Content-Type: #{postcontenttype}"
76
+ req << "Content-Length: #{postcontent.length}"
77
+ end
78
+
79
+ if args[:range]
80
+ # Convert the range to an array if it isn't one already
81
+ args[:range] = [args[:range]] unless args[:range].is_a?(Array)
82
+
83
+ # Transform it to a text string
84
+ range = args[:range].map { |v| v.is_a?(Range) ? "#{v.min}-#{v.max}" : (v >= 0 ? "#{v}-" : v.to_s) }.join(',')
85
+ req << "Range: bytes=#{range}"
86
+ end
87
+
88
+ if args[:headers]
89
+ headers = case args[:headers]
90
+ when Array then args[:headers]
91
+ when String then [args[:headers]]
92
+ else raise ArgumentError, "headers must be an array or string"
93
+ end
94
+
95
+ req += headers
96
+ end
97
+
98
+ # TODO, this cookie handler assumes it's getting a single, semicolon-delimited string.
99
+ # Eventually we will want to deal intelligently with arrays and hashes.
100
+ if args[:cookie]
101
+ req << "Cookie: #{args[:cookie]}"
102
+ end
103
+
104
+ req << ""
105
+ reqstring = req.map {|l| "#{l}\r\n"}.join
106
+ send_data reqstring
107
+
108
+ if verb == "POST" || verb == "PUT"
109
+ send_data postcontent
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -8,12 +8,15 @@
8
8
  # See http://distribustream.rubyforge.org/
9
9
  #++
10
10
 
11
- require File.dirname(__FILE__) + '/file_service'
12
11
  require "thread"
13
- require "net/http"
12
+ #require "net/http"
14
13
  require "uri"
15
14
  require "digest/sha2"
16
15
 
16
+ require File.dirname(__FILE__) + '/../common'
17
+ require File.dirname(__FILE__) + '/file_service'
18
+ require File.dirname(__FILE__) + '/http_client'
19
+
17
20
  module PDTP
18
21
  class Client
19
22
  module Transfer
@@ -33,10 +36,10 @@ module PDTP
33
36
 
34
37
  # Returns true if a server message matches this transfer
35
38
  def matches_message?(message)
36
- @peer == message["peer"] and
37
- @url == message["url"] and
39
+ @peer == message["peer"] and
40
+ @url == message["url"] and
38
41
  @byte_range == message["range"] and
39
- @peer_id == message["peer_id"]
42
+ @peer_id == message["peer_id"]
40
43
  end
41
44
 
42
45
  # Takes an HTTP range and returns a ruby Range object
@@ -177,50 +180,57 @@ module PDTP
177
180
  # Implements http transfer between two peers from the connector's (client) perspective
178
181
  class Connector < Base
179
182
  def initialize(connection, message, file_service)
180
- @file_service=file_service
181
- @peer,@port=message["host"],message["port"]
182
- @method = message["method"]
183
- @url=message["url"]
184
- @byte_range=message["range"]
185
- @peer_id=message["peer_id"]
186
- @connection=connection
183
+ @connection = connection
184
+ @file_service = file_service
185
+ @peer = message["host"]
186
+ @port = message["port"]
187
+ @method = message["method"]
188
+ @url = message["url"]
189
+ @byte_range = message["range"]
190
+ @peer_id = message["peer_id"]
187
191
  end
188
192
 
189
193
  # Perform the transfer
190
194
  def run
191
- hash=nil
192
-
193
- info=@file_service.get_info(@url)
195
+ info = @file_service.get_info(@url)
194
196
 
195
197
  #compute the vhost and path
196
198
  #FIXME work with ports
197
- uri=URI.split(@url)
198
- path=uri[5]
199
- vhost=uri[2]
200
-
201
- if @method == "get"
202
- req = Net::HTTP::Get.new(path)
203
- body = nil
204
- elsif @method == "put"
205
- req = Net::HTTP::Put.new(path)
206
- body = info.read(@byte_range)
207
- else
208
- raise HTTPException.new(405,"Invalid method: #{@method}")
199
+ uri = URI.parse(@url)
200
+
201
+ options = {
202
+ :method => @method,
203
+ :host => @peer,
204
+ :host_header => uri.host,
205
+ :port => @port,
206
+ :request => uri.path,
207
+ :range => @byte_range,
208
+ :agent => "DistribuStream #{PDTP::VERSION}",
209
+ :headers => "X-PDTP-Peer-Id: #{@connection.client.client_id}"
210
+ }
211
+
212
+ case @method
213
+ when 'get'
214
+ when 'put' then options[:content] = info.read(@byte_range)
215
+ else raise HTTPException.new(405, "Invalid method: #{@method}")
216
+ end
217
+
218
+ http = HttpClient.request options
219
+ http.callback do |response|
220
+ hash = nil
221
+
222
+ if @method == 'get' and response[:status] == 206
223
+ @@log.debug("Body Downloaded: url=#{@url} range=#{@byte_range} peer=#{@peer}:#{@port}")
224
+ info.write(@byte_range.first,response[:content])
225
+ hash = Digest::SHA256.hexdigest(response[:content]) rescue nil
226
+ elsif @method == 'put' and response[:status] == 200
227
+ @@log.debug("Body Uploaded: url=#{@url} range=#{@byte_range} peer=#{@peer}:#{@port}")
228
+ else
229
+ raise RuntimeError, "Invalid method/status combination: #{@method} #{response[:status]}"
230
+ end
231
+
232
+ send_completed_message hash
209
233
  end
210
-
211
- req.add_field("Range", "bytes=#{@byte_range.begin}-#{@byte_range.end}")
212
- req.add_field("Host",vhost)
213
- req.add_field("X-PDTP-Peer-Id", @connection.client.client_id)
214
- res = Net::HTTP.start(@peer,@port) {|http| http.request(req,body) }
215
-
216
- if res.code == '206' and @method == 'get'
217
- #we are the taker
218
- @@log.debug("Body Downloaded: url=#{@url} range=#{@byte_range} peer=#{@peer}:#{@port}")
219
- info.write(@byte_range.first,res.body)
220
- @hash=Digest::SHA256.hexdigest(res.body) rescue nil
221
- else
222
- raise "HTTP RESPONSE: code=#{res.code} body=#{res.body}"
223
- end
224
234
  end
225
235
  end
226
236
  end
@@ -0,0 +1,15 @@
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
+ # Namespace for all PDTP components
12
+ module PDTP
13
+ PDTP::VERSION = '0.2.1' unless defined? PDTP::VERSION
14
+ def self.version() VERSION end
15
+ end
@@ -30,7 +30,7 @@ CONFIG_TYPES = {
30
30
  :quiet => :bool,
31
31
  :chunk_size => :int,
32
32
  :request_url => :string
33
- }
33
+ } unless defined? CONFIG_TYPES
34
34
 
35
35
  #prints banner and loads config file
36
36
  def common_init(program_name, config = nil)
@@ -119,4 +119,4 @@ end
119
119
  #responds to config options that are used by both client and server
120
120
  def handle_config_options
121
121
  @@log.level=Logger::INFO if @@config[:quiet]
122
- end
122
+ end
@@ -12,58 +12,71 @@ require 'rubygems'
12
12
  require 'eventmachine'
13
13
 
14
14
  module PDTP
15
- # EventMachine connection adapter for sending and receiving frames with 16-bit length prefixes
16
- class Packet < EventMachine::Connection
17
- # Class for processing length prefixes in packet frames
15
+ # EventMachine connection adapter for length prefix framing
16
+ class LengthPrefixProtocol < EventMachine::Connection
17
+ # Class for processing size prefixes in packet frames
18
18
  class Prefix
19
- attr_reader :length
19
+ attr_reader :size, :data
20
20
 
21
- def initialize
22
- # Constant at 2 bytes, but expandable if we desire
23
- @length = 2
21
+ def initialize(size = 2)
22
+ unless size == 2 or size == 4
23
+ raise ArgumentError, 'only 2 or 4 byte prefixes are supported'
24
+ end
25
+
26
+ @size = size
24
27
  reset!
25
28
  end
26
29
 
30
+ # Has the entire prefix been read yet?
27
31
  def read?
28
- @length == @read
32
+ @size == @read
29
33
  end
30
34
 
35
+ # Append data to the prefix and return any extra
31
36
  def append(data)
32
- toread = @length - @read
37
+ toread = @size - @read
33
38
  new_data = data[0..(toread - 1)]
34
39
 
35
40
  @data << new_data
36
- @read += new_data.size
37
- return nil unless @read == @length
41
+ @read += new_data.length
42
+ return nil unless @read == @size
38
43
 
39
- @size = @data.unpack('n').first
40
- result = data[toread..data.size]
44
+ @length = @data.unpack(@size == 2 ? 'n' : 'N').first
45
+ result = data[toread..data.length]
41
46
 
42
47
  return nil if result.nil? or result.empty?
43
48
  result
44
49
  end
45
50
 
46
- def size
47
- return false unless read?
48
- @size
51
+ # Length of the payload extracted from the prefix
52
+ def length
53
+ raise RuntimeError, 'length called before prefix extracted' unless read?
54
+ @length
49
55
  end
50
56
 
51
57
  def reset!
52
- @size = nil
58
+ @length = nil
53
59
  @read = 0
54
60
  @data = ''
55
61
  end
56
62
  end
57
63
 
58
- def initialize(*args)
64
+ def initialize *args
59
65
  super
66
+
60
67
  @prefix = Prefix.new
61
68
  @buffer = ''
62
69
  end
63
70
 
71
+ def prefix_size=(size)
72
+ data = @prefix.data << @buffer
73
+ @prefix = Prefix.new size
74
+ receive_data data
75
+ end
76
+
64
77
  # Callback for processing incoming frames
65
78
  def receive_data(data)
66
- # Read data and append it to the length prefix unless it's already been read
79
+ # Read data and append it to the size prefix unless it's already been read
67
80
  data = @prefix.append(data) unless @prefix.read?
68
81
  return if data.nil?
69
82
 
@@ -71,14 +84,16 @@ module PDTP
71
84
  @buffer << data
72
85
 
73
86
  # Don't do anything until we receive the specified amount of data
74
- return unless @buffer.size >= @prefix.size
87
+ return unless @buffer.length >= @prefix.length
75
88
 
76
89
  # Extract the specified amount of data and process it
77
- data = @buffer[0..(@prefix.size - 1)]
78
- receive_packet data
90
+ data = @buffer[0..(@prefix.length - 1)]
79
91
 
80
92
  # Store any remaining data
81
- remainder = @buffer[@prefix.size..@buffer.size]
93
+ remainder = @buffer[@prefix.length..@buffer.length]
94
+
95
+ # Invoke receive_packet and allow the user to process the data
96
+ receive_packet data
82
97
 
83
98
  # Reset the prefix and buffer since we've received a whole frame
84
99
  @prefix.reset!
@@ -95,12 +110,10 @@ module PDTP
95
110
  def receive_packet(packet)
96
111
  end
97
112
 
98
- # Send a packet with a specified length prefix
113
+ # Send a packet with a specified size prefix
99
114
  def send_packet(data)
100
- length = data.size
101
- raise ArgumentError, 'oversize packet' if length >= 256**@prefix.length
102
-
103
- send_data [length].pack('n') << data
115
+ raise ArgumentError, 'packet too long for prefix length' if data.size >= 256**@prefix.size
116
+ send_data [data.size].pack(@prefix.size == 2 ? 'n' : 'N') << data
104
117
  end
105
118
  end
106
- end
119
+ end
@@ -19,10 +19,10 @@ rescue LoadError
19
19
  require 'json'
20
20
  end
21
21
 
22
- require File.dirname(__FILE__) + '/packet.rb'
22
+ require File.dirname(__FILE__) + '/length_prefix_protocol.rb'
23
23
 
24
24
  module PDTP
25
- PROTOCOL_DEBUG=true
25
+ PDTP::PROTOCOL_DEBUG = true unless defined? PDTP::PROTOCOL_DEBUG
26
26
 
27
27
  class ProtocolError < Exception
28
28
  end
@@ -31,7 +31,7 @@ module PDTP
31
31
  end
32
32
 
33
33
  # EventMachine handler class for the PDTP protocol
34
- class Protocol < PDTP::Packet
34
+ class Protocol < PDTP::LengthPrefixProtocol
35
35
  @@num_connections = 0
36
36
  @@message_params = nil
37
37
  @connection_open = false
@@ -40,10 +40,10 @@ module PDTP
40
40
  @connection_open
41
41
  end
42
42
 
43
- def initialize(data)
43
+ def initialize *args
44
44
  user_data = nil
45
45
  @mutex = Mutex.new
46
- super data
46
+ super
47
47
  end
48
48
 
49
49
  #called by EventMachine after a connection has been established
@@ -67,8 +67,8 @@ module PDTP
67
67
  #close a connection, but first send the specified error message
68
68
  def error_close_connection(error)
69
69
  if PROTOCOL_DEBUG
70
- send_message :protocol_error, :message => msg
71
- close_connection(true) # close after writing
70
+ send_message :protocol_error, :message => error
71
+ close_connection true # close after writing
72
72
  else
73
73
  close_connection
74
74
  end
@@ -105,7 +105,7 @@ module PDTP
105
105
  end
106
106
  end
107
107
 
108
- RANGENAMES = %w{chunk_range range byte_range}
108
+ PDTP::RANGENAMES = %w{chunk_range range byte_range} unless defined? PDTP::RANGENAMES
109
109
 
110
110
  #converts Ruby Range classes in the message to PDTP protocol hashes with min and max
111
111
  # 0..-1 => nil (entire file)
@@ -333,4 +333,4 @@ module PDTP
333
333
  mp
334
334
  end
335
335
  end
336
- end
336
+ end
data/lib/pdtp/server.rb CHANGED
@@ -12,6 +12,7 @@ require 'rubygems'
12
12
  require 'eventmachine'
13
13
  require 'mongrel'
14
14
 
15
+ require File.dirname(__FILE__) + '/common'
15
16
  require File.dirname(__FILE__) + '/server/dispatcher'
16
17
  require File.dirname(__FILE__) + '/server/file_service'
17
18
  require File.dirname(__FILE__) + '/server/connection'
@@ -24,14 +24,14 @@ module PDTP
24
24
  class Protocol < PDTP::Client::Connection
25
25
  attr_reader :client, :connection, :file_service, :client_id, :transfers, :lock
26
26
 
27
- def initialize(data)
27
+ def initialize *args
28
28
  @transfers = []
29
29
  @lock = Mutex.new
30
30
  @client = self
31
31
  @connection = self
32
32
  @client_id = Digest::MD5.hexdigest "#{Time.now.to_f}#{$$}"
33
33
 
34
- super data
34
+ super
35
35
  end
36
36
 
37
37
  # Called after a connection to the server has been established
@@ -113,4 +113,4 @@ module PDTP
113
113
  end
114
114
  end
115
115
  end
116
- end
116
+ end
metadata CHANGED
@@ -1,9 +1,9 @@
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.2.0
6
+ version: 0.2.1
7
7
  date: 2008-10-22 00:00:00 -06: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:
@@ -38,20 +38,21 @@ files:
38
38
  - bin/dstream
39
39
  - lib/pdtp
40
40
  - lib/pdtp/client
41
- - lib/pdtp/client.rb
42
- - lib/pdtp/common
43
- - lib/pdtp/server
44
- - lib/pdtp/server.rb
45
41
  - lib/pdtp/client/callbacks.rb
46
42
  - lib/pdtp/client/connection.rb
47
43
  - lib/pdtp/client/file_buffer.rb
48
44
  - lib/pdtp/client/file_service.rb
45
+ - lib/pdtp/client/http_client.rb
49
46
  - lib/pdtp/client/http_handler.rb
50
47
  - lib/pdtp/client/transfer.rb
48
+ - lib/pdtp/client.rb
49
+ - lib/pdtp/common
51
50
  - lib/pdtp/common/common_init.rb
52
51
  - lib/pdtp/common/file_service.rb
53
- - lib/pdtp/common/packet.rb
52
+ - lib/pdtp/common/length_prefix_protocol.rb
54
53
  - lib/pdtp/common/protocol.rb
54
+ - lib/pdtp/common.rb
55
+ - lib/pdtp/server
55
56
  - lib/pdtp/server/client_info.rb
56
57
  - lib/pdtp/server/connection.rb
57
58
  - lib/pdtp/server/dispatcher.rb
@@ -60,6 +61,7 @@ files:
60
61
  - lib/pdtp/server/stats_handler.rb
61
62
  - lib/pdtp/server/transfer.rb
62
63
  - lib/pdtp/server/trust.rb
64
+ - lib/pdtp/server.rb
63
65
  - conf/bigchunk.yml
64
66
  - conf/debug.yml
65
67
  - conf/example.yml