[Rubyfreenet] r9283 - in trunk/apps/rubyFreenet: . freenet f…

Top Page
Delete this message
Reply to this message
Author: sitharus
Date:  
To: rubyfreenet
Subject: [Rubyfreenet] r9283 - in trunk/apps/rubyFreenet: . freenet freenet/fcp freenet/tests
Author: sitharus
Date: 2006-06-18 03:57:50 +0000 (Sun, 18 Jun 2006)
New Revision: 9283

Added:
trunk/apps/rubyFreenet/Rakefile
trunk/apps/rubyFreenet/freenet/tests/
trunk/apps/rubyFreenet/freenet/tests/client_tests.rb
trunk/apps/rubyFreenet/freenet/tests/message_tests.rb
trunk/apps/rubyFreenet/freenet/tests/uri_tests.rb
Modified:
trunk/apps/rubyFreenet/freenet.rb
trunk/apps/rubyFreenet/freenet/exceptions.rb
trunk/apps/rubyFreenet/freenet/fcp/client.rb
trunk/apps/rubyFreenet/freenet/fcp/message.rb
trunk/apps/rubyFreenet/freenet/uri.rb
Log:
Major restructuring of files to make unit tests easier
Unit tests for Freenet::URI
Fixed Freenet::URI so it actually works
Altered synchronous library so all messages are still reported
Synchronous calls now require a block, exactly the same as for async calls



Added: trunk/apps/rubyFreenet/Rakefile
===================================================================
--- trunk/apps/rubyFreenet/Rakefile    2006-06-17 23:37:04 UTC (rev 9282)
+++ trunk/apps/rubyFreenet/Rakefile    2006-06-18 03:57:50 UTC (rev 9283)
@@ -0,0 +1,5 @@
+require 'freenet'
+task :test do
+ require 'test/unit'
+ require 'freenet/tests/uri_tests'
+end
\ No newline at end of file

Modified: trunk/apps/rubyFreenet/freenet/exceptions.rb
===================================================================
--- trunk/apps/rubyFreenet/freenet/exceptions.rb    2006-06-17 23:37:04 UTC (rev 9282)
+++ trunk/apps/rubyFreenet/freenet/exceptions.rb    2006-06-18 03:57:50 UTC (rev 9283)
@@ -1,5 +1,9 @@
module Freenet
# Raised if a URI can't be parsed or handled for some reason
- class URIError < Exception
+ class URIError < StandardError
end
+
+ # Raised if a feature isn't implemented by a URI, eg versioning for CHKs
+ class URIMethodNotImplementedError < StandardError
+ end
end
\ No newline at end of file

Modified: trunk/apps/rubyFreenet/freenet/fcp/client.rb
===================================================================
--- trunk/apps/rubyFreenet/freenet/fcp/client.rb    2006-06-17 23:37:04 UTC (rev 9282)
+++ trunk/apps/rubyFreenet/freenet/fcp/client.rb    2006-06-18 03:57:50 UTC (rev 9283)
@@ -32,37 +32,41 @@
# Client names are unique to an application. If your application may have more than one
# instance per node then each instance must have a unique name. In the event of a name
# conflict FRED assumes that the original application has died and the new one is a replacement
- # and disconnects the oldest connection,
+ # and disconnects the oldest connection.
#
+ # Most methods take a block, this is called with each message received. The arguments are
+ # a status code, the request message and the response message. To break out of the response
+ # loop raise Freenet::FCP::RequestFinished and any futher responses from the node for the
+ # request will be ignored.
+ #
# require 'freenet/client'
# client = Freenet::FCP::Client.new('MyFreenetClient', '127.0.0.1', 9481)
- # file = client.get("KSK@???")
+ # file = client.get("KSK@???") do |status, request, response|
+ # case status
+ # when :finished
+ # puts response.data
+ # raise Freenet::FCP::RequestFinished.new
+ # when :failed
+ # puts "Request failed :("
+ # raise Freenet::FCP::RequestFinished.new
+ # end
+ # end
+ #
+ # See method details for possible status codes. All callbacks may get the following
+ # [:error] Freenet reported a ProtocolError
#
# === Asynchronous Use
#
- # There are two methods to asynchronous requests, both with their own merits
+ # Asynchronous is very similar to synchronous use, except the block is run in a separate thread
+ # each time it's called. Your application will need to be thread safe.
#
- # ==== Polling
- #
- # Polling is not implemented yet, but Messages will have a ResponseQueue where responses
- # can be read in order or recipt.
- #
- # ==== Callbacks
- #
- # FCP::Message can take a block to run as soon as a reply is received. These blocks run
- # in a separate thread, so they must be thread safe if they use variables outside their
- # scope. The block arguments are |status, message, response|, message is the original
- # message for reference purposes.
- #
# client.get("KSK@???") do |status, message, response|
# case status
# when :finished then puts response.data
# end
# end
+ # # The application will exit here unless you block somehow.
#
- # See method details for possible status codes. All callbacks may get the following
- # [:error] Freenet reported a ProtocolError
- #
# ==== Thread safety
#
# In callbacks the messages are locked before the callback runs. Always
@@ -132,10 +136,10 @@
# Generates a keypair for SSK use. If used synchronously it returns
# [InsertURI, RequestURI], otherwise extract InsertURI and RequestURI
# from response.items
- def generate_keypair(async = false, &callback)
+ def generate_keypair(block = true, &callback)
message = Message.new('GenerateSSK', nil, nil, callback)
- send(message, async)
- if async
+ send(message)
+ unless block
message
else
message.wait_for_response
@@ -145,9 +149,7 @@

# == Request a file from Freenet.
#
- # Synchronous requests will either get the response message or a RequestFailed exception
- #
- # Asyncronous requests get a lot more status information. The messages are:
+ # Applicable status messages:
# [:pending] The message is in Freenet's queue.
# [:progress] A SimpleProgress message has been recieved
# [:redirect] The node has found a redirect for the file. This is returned
@@ -171,9 +173,8 @@
# when :finished then puts response.data
# end
# end
- def get(uri, async=false, options=nil, &callback)
+ def get(uri, block=true, options=nil, &callback)
uri = uri.uri if uri.respond_to? :uri
- async = true if callback
options = {'IgnoreDS'=>false,
'DSOnly'=>false,
'Verbosity'=>0,
@@ -185,30 +186,8 @@
options['URI'] = uri
message = Message.new('ClientGet', nil, options, callback)
log(INFO, "#{message.identifier} GET queued")
- send(message, async)
- if async
- message
- else
- loop do
- message.wait_for_response
- puts "Got response: #{message.response.type}"
- message.lock
- case message.response.type
- when 'AllData'
- message.unlock
- return message.response
- when 'GetFailed','ProtocolError'
- message.unlock
- if message.response.items['Code'] == '27'
- get(message.response.items['RedirectURI'], true, options)
- else
- raise RequestFailed.new(message.response)
- end
- else
- message.unlock
- end
- end
- end
+ send(message)
+ block_message(message, block)
end

# === Put data in to freenet
@@ -232,9 +211,8 @@
#
# ==== Creating a redirect URI
# put('SSK@my-site-key/my-site/image.jpg', nil, false, 'UploadFrom'=>'redirect','TargetURI'=>'KSK@???')
- def put(uri, data=nil, async=false, options=nil, &callback)
+ def put(uri, data=nil, block=true, options=nil, &callback)
uri = uri.uri if uri.respond_to? :uri
- async = true if callback
options = {'Metadata.ContentType' => 'application/octet-stream',
'Verbosity' => 0,
'MaxRetries' => 10,
@@ -243,34 +221,16 @@
options['Persistence'] = 'connection' unless async
options['URI'] = uri
message = Message.new('ClientPut', data, options, callback)
- message.content-type = options['Metadata.ContentType']
+ message.content_type = options['Metadata.ContentType']
log(INFO, "#{message.identifier} PUT queued")
- send(message, async)
- if async
- message
- else
- loop do
- message.wait_for_response
- message.lock
- case message.response.type
- when 'PutSuccessful'
- message.unlock
- return message.response.items['URI']
- when 'PutFailed','ProtocolError'
- message.unlock
- raise RequestFailed.new(message.response)
- else
- message.unlock
- end
- end
- end
+ send(message)
+ block_message(message, block)
end

# Upload a directory to a key, either SSK or USK. This directory must be local to the
# node we're connecting to.
- def putdir(uri, dir, async=false, options=nil, &callback)
+ def putdir(uri, dir, block=true, options=nil, &callback)
uri = uri.uri if uri.respond_to? :uri
- async = true if callback
options = {'Verbosity' => 0,
'MaxRetries' => 10,
'PriorityClass' => 3,
@@ -281,28 +241,8 @@
options['URI'] = uri
message = Message.new('ClientPutDiskDir', nil, options, callback)
log(INFO, "#{message.identifier} PUTDIR queued")
- send(message, async)
- if async
- message
- else
- loop do
- message.wait_for_response
- message.lock
- case message.response.type
- when 'PutSuccessful'
- message.unlock
- return message.response.items['URI']
- when 'PutFailed','ProtocolError'
- message.unlock
- raise RequestFailed.new(message.response)
- when 'SimpleProgress'
- puts "T:#{message.response.items['Total']}/R:#{message.response.items['Required']}/F:#{message.response.items['Failed']}/FF:#{message.response.items['FatallyFailed']}/S:#{message.response.items['Succeeded']}/#{message.response.items['FinalizedTotal']}"
- message.unlock
- else
- message.unlock
- end
- end
- end
+ send(message)
+ block_message(message, block)
end

# Get the request status for a persistent request. Not useful in synchronous systems.
@@ -311,11 +251,32 @@
def request_status(identifier, global, async=false)
log(DEBUG, 'Requesting status')
message = Message.new('GetRequestStatus', nil, 'Identifier'=>identifier, 'Global'=>global)
- send(message, async)
+ send(message)
message.wait_for_response
end

+ # Private calls
private
+
+ def block_message(message, block)
+ unless block
+ message
+ else
+ loop do
+ begin
+ message.wait_for_response
+ message.lock
+ message.response.lock
+ callback(message.status, message, message.response)
+ message.response.unlock
+ message.unlock
+ rescue RequestFinished => e
+ message.unlock
+ end
+ end
+ end
+ end
+
# Send the ClientHello message to the FCP server.
def hello
log(DEBUG, 'Sending ClientHello')
@@ -336,8 +297,7 @@
# Queue the message for sending by the worker thread.
# [message] The FCP::Message to send to the server. You may retain object for later use, but
# it may block if it's in use.
- # param asynchronous Whether the reader should block until a response is received
- def send(message, asynchronous = false)
+ def send(message)
@message_queue << message
message
end
@@ -404,56 +364,29 @@
log(INFO, "#{message.identifier}: recieved #{message.type}")
original_message = @messages[message.identifier]
if original_message
+ status = message.status
original_message.reply = message
if original_message.callback?
thread = Thread.new do
original_message.lock
message.lock
- case message.type
- when 'SSKKeypair'
- original_message.callback(:keypair)
- when 'AllData'
- original_message.callback(:finished)
- when 'PersistentGet'
- original_message.callback(:pending)
- when 'SimpleProgress'
- original_message.callback(:progress)
- when 'ProtocolError'
- original_message.callback(:failed)
- when 'URIGenerated'
- original_message.callback(:uri_generated)
- when 'PutSuccessful'
- original_message.callback(:success)
- when 'PutFailed'
- original_message.callback(:failed)
- when 'ProtocolError'
- original_message.callback(:error)
- when 'DataFound'
- original_message.callback(:found)
+ original_message.callback(status)
+ case status
+ when :found
original_message.content_type = message.items['Metadata.ContentType']
if original_message.items['Persistence'] != 'connection' and not original_message.data_found
original_message.data_found = true
request_status(message.identifier, message.items['Global'] || false, true)
end
- when 'GetFailed'
- if message.items['RedirectURI']
- original_message.callback(:redirect)
- elsif message.items['Fatal'] == 'false'
- case message.items['Code']
- when '15' # Node overloaded. Wait then re-request. We can re-use the ID as GetFailed removes the ID from FRED
+ when :failed
+ if message.items['Fatal'] == 'false'
+ if message.items['Code'] == 15
if original_message.retries < 5
original_message.retries += 1
- original_message.callback(:retrying)
log(DEBUG, "Retrying #{original_message.items['URI']}")
get(original_message.items['URI'], true, original_message.items)
- else
- original_message.callback(:failed)
end
- else
- original_message.callback(:failed)
end
- else
- original_message.callback(:failed)
end
end
message.unlock

Modified: trunk/apps/rubyFreenet/freenet/fcp/message.rb
===================================================================
--- trunk/apps/rubyFreenet/freenet/fcp/message.rb    2006-06-17 23:37:04 UTC (rev 9282)
+++ trunk/apps/rubyFreenet/freenet/fcp/message.rb    2006-06-18 03:57:50 UTC (rev 9283)
@@ -90,6 +90,54 @@
Thread.stop
end

+ # Gets the status for this message. The key ones all apps need to handle are:
+ # [:finished] When a request has successfully finished
+ # [:redirect] The message has recieved a redirect internally
+ # This could be handled internally, I haven't decided yet.
+ # [:failed] The request has fatally failed
+ # [:error] An error in the FCP messages occured. This is caused by a bug in rubyFreenet
+ def status(message)
+ case message.type
+ when 'SSKKeypair'
+ original_message.callback(:keypair)
+ when 'AllData'
+ original_message.callback(:finished)
+ when 'PersistentGet'
+ original_message.callback(:pending)
+ when 'SimpleProgress'
+ original_message.callback(:progress)
+ when 'ProtocolError'
+ original_message.callback(:failed)
+ when 'URIGenerated'
+ original_message.callback(:uri_generated)
+ when 'PutSuccessful'
+ original_message.callback(:finished)
+ when 'PutFailed'
+ original_message.callback(:failed)
+ when 'ProtocolError'
+ original_message.callback(:error)
+ when 'DataFound'
+ original_message.callback(:found)
+ when 'GetFailed'
+ if message.items['RedirectURI']
+ original_message.callback(:redirect)
+ elsif message.items['Fatal'] == 'false'
+ case message.items['Code']
+ when '15' # Node overloaded. Wait then re-request. We can re-use the ID as GetFailed removes the ID from FRED
+ if original_message.retries < 5
+ original_message.callback(:retrying)
+ else
+ original_message.callback(:failed)
+ end
+ else
+ original_message.callback(:failed)
+ end
+ else
+ original_message.callback(:failed)
+ end
+ end
+ end
+
# Write this object to an FCP stream.
def write(stream)
stream.write(type+"\n")

Added: trunk/apps/rubyFreenet/freenet/tests/client_tests.rb
===================================================================
--- trunk/apps/rubyFreenet/freenet/tests/client_tests.rb    2006-06-17 23:37:04 UTC (rev 9282)
+++ trunk/apps/rubyFreenet/freenet/tests/client_tests.rb    2006-06-18 03:57:50 UTC (rev 9283)
@@ -0,0 +1,3 @@
+class ClientTests < Test::Unit::TestCase
+
+end
\ No newline at end of file

Added: trunk/apps/rubyFreenet/freenet/tests/message_tests.rb
===================================================================
--- trunk/apps/rubyFreenet/freenet/tests/message_tests.rb    2006-06-17 23:37:04 UTC (rev 9282)
+++ trunk/apps/rubyFreenet/freenet/tests/message_tests.rb    2006-06-18 03:57:50 UTC (rev 9283)
@@ -0,0 +1,12 @@
+class MessageTests < Test::Unit::TestCase
+ def test_write_message
+ m = Freenet::FCP::Message.new('TestMessage', nil, 'Item1' => 'Item1Value', 'Item2' => 'Item2Value')
+ s = StringIO.new
+ m.write(s)
+ assert_equal('TestMessage', s.readline)
+
+ end
+
+ def test_write_data
+ end
+end
\ No newline at end of file

Added: trunk/apps/rubyFreenet/freenet/tests/uri_tests.rb
===================================================================
--- trunk/apps/rubyFreenet/freenet/tests/uri_tests.rb    2006-06-17 23:37:04 UTC (rev 9282)
+++ trunk/apps/rubyFreenet/freenet/tests/uri_tests.rb    2006-06-18 03:57:50 UTC (rev 9283)
@@ -0,0 +1,103 @@
+require 'test/unit'
+
+class URITest < Test::Unit::TestCase
+ #def setup
+ #end
+
+ #def teardown
+ #end
+
+ def test_ksk_parsing
+ uri_text = 'KSK@test-site-1'
+ uri = Freenet::URI.new(uri_text)
+ assert_equal(uri.uri, 'KSK@test-site-1')
+ assert_equal(uri.type, 'KSK')
+ assert_equal(uri.key, 'test-site-1')
+ assert_raise(Freenet::URIMethodNotImplementedError) {uri.version = 1}
+ assert_raise(Freenet::URIMethodNotImplementedError) {uri.name = 'my-cool-freesite'}
+ assert_raise(Freenet::URIMethodNotImplementedError) {uri.path = 'my_path'}
+ assert_nil(uri.version)
+ assert_nil(uri.name)
+ assert_nil(uri.path)
+
+ end
+
+ def test_chk_parsing
+ uri_text = 'CHK@sdsdjfijvisjesjfsdjdskfsdlk,fdsknfdsfnoifhiw,dsskd/my-cool-pic.jpg'
+ uri = Freenet::URI.new(uri_text.dup)
+ assert_equal(uri.uri, uri_text)
+ assert_equal(uri.type, 'CHK')
+ assert_equal(uri.key, 'sdsdjfijvisjesjfsdjdskfsdlk,fdsknfdsfnoifhiw,dsskd')
+ assert_equal(uri.path, 'my-cool-pic.jpg')
+ assert_raise(Freenet::URIMethodNotImplementedError) {uri.version = 1}
+ assert_raise(Freenet::URIMethodNotImplementedError) {uri.name = 'my-cool-freesite'}
+ assert_nil(uri.version)
+ assert_nil(uri.name)
+ end
+
+ def test_usk_parsing
+ uri_text = 'USK@adasdsadfegffpokp,olkpojreihauwehfw/coolsite/4/mystuff.html'
+ uri = Freenet::URI.new(uri_text.dup)
+ assert_equal(uri_text, uri.uri)
+ assert_equal('USK', uri.type)
+ assert_equal('adasdsadfegffpokp,olkpojreihauwehfw', uri.key)
+ assert_equal('coolsite', uri.name)
+ assert_equal(4, uri.version)
+ assert_equal('mystuff.html', uri.path)
+
+ uri_text = 'USK@adasdsadfegffpokp,olkpojreihauwehfw/coolsite/-1/'
+ uri = Freenet::URI.new(uri_text.dup)
+ assert_equal(uri_text, uri.uri)
+ assert_equal(-1, uri.version)
+ assert_equal("", uri.path)
+ end
+
+ def test_ssk_parsing
+ uri_text = 'SSK@fsdmlkfmdsklf0344lk,lmfdsmvsskrngori3243/coolsite/page.html'
+ uri = Freenet::URI.new(uri_text.dup)
+ assert_equal(uri_text, uri.uri)
+ assert_equal('SSK', uri.type)
+ assert_equal('coolsite', uri.name)
+ assert_equal('page.html', uri.path)
+ assert_equal('fsdmlkfmdsklf0344lk,lmfdsmvsskrngori3243', uri.key)
+ assert_nil(uri.version)
+ end
+
+ def test_ssk_version_parsing
+ uri_text = 'SSK@fsdmlkfmdsklf0344lk,lmfdsmvsskrngori3243/coolsite-5/'
+ uri = Freenet::URI.new(uri_text.dup)
+ assert_equal(uri_text, uri.uri)
+ assert_equal('SSK', uri.type)
+ assert_equal('coolsite', uri.name)
+ assert_equal('', uri.path)
+ assert_equal('fsdmlkfmdsklf0344lk,lmfdsmvsskrngori3243', uri.key)
+ assert_equal(5, uri.version)
+ end
+
+ def test_part_merge
+ uri_text = 'SSK@1234,5678/coolsite/'
+ uri = Freenet::URI.new(uri_text.dup)
+ assert_equal(uri_text+'mypic.jpg', uri.merge('mypic.jpg'))
+ assert_equal(uri_text+'things/meh.html', uri.merge('things/meh.html'))
+ assert_equal('/stuff', uri.merge('/stuff'))
+ assert_equal(uri_text, uri.merge('../'))
+ assert_equal('CHK@123/thing.jpg', uri.merge('CHK@123/thing.jpg'))
+ assert_equal('freenet:CHK@123/thing.jpg', uri.merge('freenet:CHK@123/thing.jpg'))
+ uri.version = 3
+ assert_equal('SSK@1234,5678/coolsite-3/', uri.uri)
+ uri.key = '9876,54321'
+ assert_equal('SSK@9876,54321/coolsite-3/', uri.uri)
+ end
+
+ def test_path_merge
+ uri_base = 'SSK@1234,5678/coolsite/'
+ uri_text = uri_base+'subdir/place.html'
+ uri = Freenet::URI.new(uri_text.dup)
+ assert_equal(uri_base, uri.merge('../'))
+ assert_equal(uri_base+'index.html', uri.merge('../index.html'))
+ assert_equal(uri_base+'index.html', uri.merge('../../index.html'))
+ assert_equal(uri_base+'index.html', uri.merge('../../../index.html'))
+ assert_equal(uri_base+'subdir/coolpic.jpg', uri.merge('coolpic.jpg'))
+ assert_equal(uri_base+'subdir/coolpic.jpg', uri.merge('./coolpic.jpg'))
+ end
+end
\ No newline at end of file

Modified: trunk/apps/rubyFreenet/freenet/uri.rb
===================================================================
--- trunk/apps/rubyFreenet/freenet/uri.rb    2006-06-17 23:37:04 UTC (rev 9282)
+++ trunk/apps/rubyFreenet/freenet/uri.rb    2006-06-18 03:57:50 UTC (rev 9283)
@@ -1,4 +1,5 @@
require 'cgi'
+require 'uri'

module Freenet
# Represents a Freenet URI. Provides manipulation with awareness of the Freenet structure, such
@@ -7,7 +8,7 @@
# This could be completely wrong. Any criticism welcome
class URI
include Comparable
- attr_accessor :type, :site, :name, :path, :uri, :version
+ attr_accessor :type, :key, :name, :path, :uri, :version

# This can take a URI in following formats:
# /freenet:SSK@...
@@ -28,40 +29,72 @@

@uri = uri
@type = @uri.match(/^(?:[UKS]S|CH)K/)[0]
- @site = @uri.match(/^(?:[UKS]S|CH)K@([^\/]+)/)[1]
+ @key = @uri.match(/^(?:[UKS]S|CH)K@([^\/]+)/)[1]
case @type
- when 'KSK', 'CHK'
- @path = @uri.match(/(\/[^#\?]+)/)[1] if @uri =~ /\/[^#\?]+/
+ when 'CHK'
+ @path = @uri.match(/\/([^#\?]+)/)[1] if @uri =~ /\/[^#\?]+/
when 'SSK'
path = @uri.match(/(\/[^#\?]+)/)[1] if @uri =~ /\/[^#\?]+/
if path
- parts = @uri.match(%r{(/[^/]+?)(?:-([0-9]+))?(/.*)})
+ parts = @uri.match(%r{/([^/]+?)(?:-([0-9]+))?/(.*)})
@name = parts[1]
- @version = parts[2]
+ @version = parts[2].to_i if parts[2]
@path = parts[3]
end
when 'USK'
path = @uri.match(/(\/[^#\?]+)/)[1] if @uri =~ /\/[^#\?]+/
if path
- parts = @uri.match(%r{(/[^/]+?)(?:[/-](-?[0-9]+))(/?.*)})
+ parts = @uri.match(%r{/([^/]+?)[/-](-?[0-9]+)/?(.*)})
@name = parts[1]
- @version = parts[2]
+ @version = parts[2].to_i
@path = parts[3]
end
end
@anchor = @uri.match(/#(.+)/)[1] if @uri =~ /#.+/
@query_string = @uri.match(/\?([^#]+)/)[1] if @uri =~ /\?/
end
+
+ def name=(name)
+ raise URIMethodNotImplementedError.new if ['KSK', 'CHK'].include? @type
+ @name = name
+ end
+
+ def version=(version)
+ raise URIMethodNotImplementedError.new if ['KSK', 'CHK'].include? @type
+ @version = version
+ end
+
+ def site
+ self.key
+ end
+
+ def site=(site)
+ self.key=(site)
+ end
+
+ def path=(path)
+ raise URIMethodNotImplementedError.new if ['KSK'].include? @type
+ @path = path
+ end
+
+ def next_version
+ raise URIMethodNotImplementedError.new if ['KSK', 'CHK'].include? @type
+ u = self.dup
+ u.version = @version+1
+ u
+ end

# Return a URI that can be fed to Freenet
def uri
case @type
- when 'KSK','CHK'
- "#{@type}@#{@site}#{@path}"
+ when 'KSK'
+ "#{@type}@#{@key}"
+ when 'CHK'
+ "#{@type}@#{@key}/#{@path}"
when 'USK'
- "#{@type}@#{@site}#{@name}#{'/'+@version.to_s if @version}#{"?#{@query_string}" if @query_string}#{@path}#{"##{@anchor}" if @anchor}"
+ "#{@type}@#{@key}/#{@name}/#{@version.to_s}/#{@path}#{"?#{@query_string}" if @query_string}#{"##{@anchor}" if @anchor}"
when 'SSK'
- "#{@type}@#{@site}#{@name}#{'-'+@version.to_s if @version}#{"?#{@query_string}" if @query_string}#{@path}#{"##{@anchor}" if @anchor}"
+ "#{@type}@#{@key}/#{@name}#{'-'+@version.to_s if @version}/#{@path}#{"?#{@query_string}" if @query_string}#{"##{@anchor}" if @anchor}"
end
end

@@ -69,13 +102,13 @@
# to do what a browser would
# uri.merge("image.jpg")
def merge(uri)
- if uri =~ /^\//
+ if uri =~ /^\// or uri =~ /^freenet:/ or uri =~ /^(?:[UKS]S|CH)K/
return uri
end
uri = uri.strip
begin
uri = URI.new(uri) unless uri.respond_to? :uri
- if uri.site == @site
+ if uri.key == @key
return merge_uri(uri)
else
return uri.uri
@@ -91,9 +124,9 @@
case @type
when 'KSK','CHK' #No point merging paths for this type...
when 'USK'
- "#{@type}@#{@site}#{@name}#{'/'+@version.to_s if @version}#{merge_paths(@path, uri)}"
+ "#{@type}@#{@key}/#{@name}#{'/'+@version.to_s if @version}/#{merge_paths(@path, uri)}"
when 'SSK'
- "#{@type}@#{@site}#{@name}#{'-'+@version.to_s if @version}#{merge_paths(@path, uri)}"
+ "#{@type}@#{@key}/#{@name}#{'-'+@version.to_s if @version}/#{merge_paths(@path, uri)}"
end
end
end
@@ -106,7 +139,7 @@
#
# This may be completely wrong. Please tell me if it is.
def root?
- case @site
+ case @key
when /^CHK/ then true
when /^KSK/ then true
when /^SSK/ then @path == %r{/[^/]/}
@@ -117,23 +150,24 @@
end

def <=>(other)
- if other.site == @site
+ if other.key == @key
other.path <=> @path
else
- other.site <=> @site
+ other.key <=> @key
end
end

private

def merge_uri(uri)
- return uri.uri if uri.type != @type or uri.site != @site
+ return uri.uri if uri.type != @type or uri.key != @key
+ return uri.uri if ['KSK','CHK'].include? uri.type or ['KSK','CHK'].include? @type
version = uri.version > @version ? uri.version : version
name = uri.name
path = merge_paths(@path, uri.path)
uri = URI.new
uri.type = @type
- uri.site = @site
+ uri.key = @key
uri.version = version
uri.name = name
uri.path = path
@@ -141,28 +175,15 @@
end

def merge_paths(old_path, new_path)
- case new_path
- when /^\.\.\//
- unless old_path =~ /\/$/
- old_path = old_path.gsub(/\/[^\/]+$/, '')
- end
- old_path = old_path.gsub(/\/[^\/]+$/,'/')
- new_path = new_path.gsub(/^\.\.\//, '')
- return merge_paths(old_path, new_path)
- when /^\.\//
- unless old_path =~ /\/$/
- old_path = old_path.gsub(/\/[^\/]+$/, '/')
- end
- new_path = new_path.gsub(/\.\//,'')
- return "#{old_path}#{new_path}"
- when /^\//
- return new_path
- else
- unless old_path =~ /\/$/
- old_path = old_path.gsub(/\/[^\/]+$/, '/')
- end
- return "#{old_path}#{new_path}"
+ old_parts = old_path.split('/')
+ old_parts.pop unless old_path =~ %r{/$}
+ new_parts = new_path.split('/')
+ while new_parts[0] == '..'
+ old_parts.pop
+ new_parts.shift
end
+ new_parts.shift while new_parts[0] == '.'
+ return (old_parts+new_parts).join('/')
end
end
end
\ No newline at end of file

Modified: trunk/apps/rubyFreenet/freenet.rb
===================================================================
--- trunk/apps/rubyFreenet/freenet.rb    2006-06-17 23:37:04 UTC (rev 9282)
+++ trunk/apps/rubyFreenet/freenet.rb    2006-06-18 03:57:50 UTC (rev 9283)
@@ -2,30 +2,4 @@
require 'freenet/exceptions'
require 'freenet/uri'
require 'freenet/fcp'
-require 'thread'
-
-if $0 == __FILE__
- client = Freenet::FCP::Client.new
- index_url = "USK@PFeLTa1si2Ml5sDeUy7eDhPso6TPdmw-2gWfQ4Jg02w,3ocfrqgUMVWA2PeorZx40TW0c-FiIOL-TWKQHoDbVdE,AQABAAE/Index/34/"
- puts client.get(index_url).data
-
- # As an async request is threaded off we need a mutex to prevent this from exiting early.
- # I have a feeling I'm missing something here
- #semaphore = Mutex.new
- #thread = Thread.new do
- # semaphore.lock
- # client.get(index_url, true) do |status, message, response|
- # case status
- # when :finished
- # puts "Request finished"
- # puts response.data
- # semaphore.unlock
- # when :pending
- # end
- # end
- #end
- #semaphore.lock
- #semaphore.unlock
- #thread.join
- client.disconnect
-end
\ No newline at end of file
+require 'thread'
\ No newline at end of file