Author: sitharus
Date: 2006-06-10 08:12:10 +0000 (Sat, 10 Jun 2006)
New Revision: 9122
Added:
trunk/apps/rubyFreenet/rsite/createsite
trunk/apps/rubyFreenet/rsite/updatesites
Modified:
trunk/apps/rubyFreenet/freenet/fcp/client.rb
trunk/apps/rubyFreenet/freenet/fcp/message.rb
trunk/apps/rubyFreenet/freenet/uri.rb
trunk/apps/rubyFreenet/rsite/rsite.rb
Log:
Tidied up Mutex use to stop excessive CPU use. Performance will suffer slightly.
Added some scripts to show freesite management and insertion
Modified: trunk/apps/rubyFreenet/freenet/fcp/client.rb
===================================================================
--- trunk/apps/rubyFreenet/freenet/fcp/client.rb 2006-06-10 03:18:04 UTC
(rev 9121)
+++ trunk/apps/rubyFreenet/freenet/fcp/client.rb 2006-06-10 08:12:10 UTC
(rev 9122)
@@ -87,7 +87,6 @@
@messages = {}
@running = false
@lock = Mutex.new
- @logger_mutex = Mutex.new
@logger = Logger.new('FCPClientLog','daily')
@message_queue = Queue.new
connect
@@ -139,6 +138,7 @@
if async
message
else
+ message.wait_for_response
[message.response.items['InsertURI'],
message.response.items['RequestURI']]
end
end
@@ -189,12 +189,13 @@
message
else
loop do
+ message.wait_for_response
message.lock
case message.response.type
when 'AllData'
message.unlock
return message.response
- when 'GetFailed'
+ when 'GetFailed','ProtocolError'
message.unlock
raise RequestFailed.new(message.response)
else
@@ -242,12 +243,13 @@
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'
+ when 'PutFailed','ProtocolError'
message.unlock
raise RequestFailed.new(message.response)
else
@@ -276,12 +278,13 @@
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'
+ when 'PutFailed','ProtocolError'
message.unlock
raise RequestFailed.new(message.response)
else
@@ -298,6 +301,7 @@
log(DEBUG, 'Requesting status')
message = Message.new('GetRequestStatus', nil,
'Identifier'=>identifier, 'Global'=>global)
send(message, async)
+ message.wait_for_response
end
private
@@ -306,15 +310,16 @@
log(DEBUG, 'Sending ClientHello')
message = Message.new('ClientHello', nil, 'Name'=>@client_name,
'ExpectedVersion'=>'2.0')
send(message)
+ message.wait_for_response
log(DEBUG, "Got NodeHello - Freenet
#{message.response.items['Version']}")
if message.response.items['Testnet'] == 'true'
log(WARN, "Connected to Testnet, you have no anonymity!")
end
end
- # Logger utility method
+ # Logger utility method. Logger should be thread-safe
def log(severity, message)
- @logger_mutex.synchronize {@logger.add(severity, message)}
+ @logger.add(severity, message)
end
# Queue the message for sending by the worker thread.
@@ -324,9 +329,7 @@
def send(message, asynchronous = false)
log(DEBUG, "Queuing #{message.type} - #{message.identifier}")
@message_queue << message
- unless asynchronous
- return message.wait_for_response
- end
+ message
end
# Worker thread, loops every second or so and checks for new messages to
send then messages
@@ -334,20 +337,29 @@
def socket_thread
@callback_threads = []
loop do
+ # Join threads. Wait 0.1 seconds for each thread.
@callback_threads.each do |thread|
begin
- thread.join(0.1)
+ @callback_threads.delete(thread) if thread.join(0.1)
rescue RequestFinished=>e
@messages.delete(e.message)
rescue Exception=>e
puts "Callback exception #{e}"
end
end
- @lock.synchronize do
- if @running == false
- @socket.close
- Thread.exit
+
+ @messages.each do |k, m|
+ begin
+ m.try_lock
+ rescue
end
+ end
+
+ # I'm assuming that setting @running is atomic. There shouldn't be a
race
+ # condition here as this thread will never set @running.
+ if @running == false
+ @socket.close
+ Thread.exit
end
begin
while message = @message_queue.pop(true)
@@ -355,8 +367,9 @@
end
rescue ThreadError => e
end
-
- if select([@socket], nil, nil, 1)
+
+ # Wait two seconds for communication, shouldn't slow down too much
and should save CPU.
+ if select([@socket], nil, nil, 2)
message = read_message
dispatch_message(message)
end
@@ -375,6 +388,7 @@
if message.identifier
original_message = @messages[message.identifier]
if original_message
+ original_message.unlock
original_message.reply = message
thread = Thread.new do
original_message.lock
@@ -449,6 +463,7 @@
raise FCPConnectionError.new('Socket does not exist') unless @socket
log(DEBUG, "Sending #{message.type} #{message.identifier}")
@messages[message.identifier] ||= message
+ message.lock
unless message.load_only
log(DEBUG, "W: #{message.type}")
@socket.write(message.type+"\n")
Modified: trunk/apps/rubyFreenet/freenet/fcp/message.rb
===================================================================
--- trunk/apps/rubyFreenet/freenet/fcp/message.rb 2006-06-10 03:18:04 UTC
(rev 9121)
+++ trunk/apps/rubyFreenet/freenet/fcp/message.rb 2006-06-10 08:12:10 UTC
(rev 9122)
@@ -36,11 +36,19 @@
end
# Lock the object. Call before using in async situations
- def lock; @mutex.lock; end
+ def lock(delay = 5)
+ until @mutex.try_lock
+ sleep(delay)
+ end
+ end
# Unlock. Call after using asychronously
def unlock; @mutex.unlock; end
+ def locked?; @mutex.locked?; end
+
+ def try_lock; @mutex.try_lock; end
+
# Dispatch the callback. Private to FCP::Client
def callback(status)
@callback.call(status, self, @response) unless @callback.nil?
@@ -59,10 +67,10 @@
# called from any thread.
def wait_for_response
until @response
- sleep(3)
+ sleep(5)
+ next if locked?
lock
unlock
- Thread.pass
end
end
end
Modified: trunk/apps/rubyFreenet/freenet/uri.rb
===================================================================
--- trunk/apps/rubyFreenet/freenet/uri.rb 2006-06-10 03:18:04 UTC (rev
9121)
+++ trunk/apps/rubyFreenet/freenet/uri.rb 2006-06-10 08:12:10 UTC (rev
9122)
@@ -5,7 +5,7 @@
# This could be completely wrong. Any criticism welcome
class URI
include Comparable
- attr_accessor :type, :site, :path, :uri, :version
+ attr_accessor :type, :site, :name, :path, :uri, :version
# This can take a URI in following formats:
# /freenet:SSK at ...
@@ -25,14 +25,40 @@
@uri = uri
@type = @uri.match(/^(?:[UKS]S|CH)K/)[0]
@site = @uri.match(/^(?:[UKS]S|CH)K@([^\/]+)/)[1]
- @path = @uri.match(/(\/[^#\?]+)/)[1] if @uri =~ /\/[^#\?]+/
+ case @type
+ when 'KSK', 'CHK'
+ @path = @uri.match(/(\/[^#\?]+)/)[1] if @uri =~ /\/[^#\?]+/
+ when 'SSK'
+ path = @uri.match(/(\/[^#\?]+)/)[1] if @uri =~ /\/[^#\?]+/
+ if path
+ parts = @uri.match(%r{(/[^/]+?)(?:-([0-9]+))?/(.*)})
+ @name = parts[1]
+ @version = parts[2]
+ @path = parts[3]
+ end
+ when 'USK'
+ path = @uri.match(/(\/[^#\?]+)/)[1] if @uri =~ /\/[^#\?]+/
+ if path
+ parts = @uri.match(%r{(/[^/]+?)(?:[/-]([0-9]+))?/(.*)})
+ @name = parts[1]
+ @version = parts[2]
+ @path = parts[3]
+ end
+ end
@anchor = @uri.match(/#(.+)/)[1] if @uri =~ /#.+/
@query_string = @uri.match(/\?([^#]+)/)[1] if @uri =~ /\?/
end
# Return a URI that can be fed to Freenet
def uri
- "#{@type}@#{@site}#{@path}#{'/'+ at version.to_s if
@version}#{"?#{@query_string}" if @query_string}#{"##{@anchor}" if @anchor}"
+ case @type
+ when 'KSK','CHK'
+ "#{@type}@#{@site}#{@path}"
+ when 'USK'
+ "#{@type}@#{@site}#{@path}#{'/'+ at version.to_s if
@version}#{"?#{@query_string}" if @query_string}#{"##{@anchor}" if @anchor}"
+ when 'SSK'
+ "#{@type}@#{@site}#{@path}#{'-'+ at version.to_s if
@version}#{"?#{@query_string}" if @query_string}#{"##{@anchor}" if @anchor}"
+ end
end
# Merge in a URI or a URI fragment and provide the finished URI. Attempts
@@ -57,7 +83,7 @@
# Returns true if we're at the 'base' page of a URI using the following:
# - KSKs and CHKs only have one file, so always the base
- # - SSKs have a 'base', eg SSK at .../mysite/
+ # - SSKs have a 'base', eg SSK at .../mysite-2/
# - USKs start with /sitename and end with /revision or -revision, though
the latter
# is technically wrong.
#
Added: trunk/apps/rubyFreenet/rsite/createsite
===================================================================
--- trunk/apps/rubyFreenet/rsite/createsite 2006-06-10 03:18:04 UTC (rev
9121)
+++ trunk/apps/rubyFreenet/rsite/createsite 2006-06-10 08:12:10 UTC (rev
9122)
@@ -0,0 +1,79 @@
+#!/usr/bin/ruby
+# == Create Site
+#
+# Creates a new freesite to be managed by rsite
+#
+# === Usage
+#
+# ./createsite [OPTIONS] ... SITE_DIRECTORY
+#
+# All arguments except SITE_DIRECTORY are optional
+#
+# -h, --help:
+# Display this message
+#
+# -n, --name:
+# The name of the freesite, used in the URL, such as SSK at .../name/,
defaults to the end of SITE_DIRECTORY.
+# Stick to a-zA-Z0-9_- for characters
+#
+# -t, --type:
+# The type of site to insert, either USK or SSK, defaults to USK
+#
+# -k, --keys:
+# The keys if already generated, in the format [INSERT_KEY;REQUEST_KEY],
without the SSK@ bit
+#
+# -v, --version:
+# The initial version of the site to insert, defaults to 1
+#
+# SITE_DIRECTORY is the path to the base of the site to insert, eg, ~/my_flog
+
+require 'rsite'
+require 'getoptlong'
+require 'rdoc/usage'
+
+opts = GetoptLong.new(
+ ['--type', '-t', GetoptLong::REQUIRED_ARGUMENT],
+ ['--name', '-n', GetoptLong::REQUIRED_ARGUMENT],
+ ['--help', '-h', GetoptLong::NO_ARGUMENT],
+ ['--keys', '-k', GetoptLong::REQUIRED_ARGUMENT],
+ ['--version', '-v', GetoptLong::REQUIRED_ARGUMENT]
+)
+
+type = 'USK'
+keys = nil
+version = 1
+name = nil
+
+opts.each do |opt, value|
+ case opt
+ when '--type':
+ unless ['USK','SSK'].include? value
+ puts "Type \"#{value}\" isn't recognised, please use USK or SSK"
+ exit 0
+ end
+ type = value
+ when '--name'
+ if value =~ /[^a-zA-Z0-9_-]/
+ puts "Name should consist of A-Z, 0-9, _ and - only"
+ exit 0
+ end
+ name = value
+ when '--keys' # Don't check keys, I have no idea how to.
+ keys = value.split(';')
+ when '--version'
+ version = value.to_i
+ when '--help'
+ RDoc::usage
+ exit 0
+ end
+end
+
+if ARGV.length != 1
+ puts "Missing dir argument (try --help)"
+ exit 0
+end
+
+dir = File.expand_path(ARGV.shift)
+name ||= basename(dir)
+
+Freenet::Site.add_site(:name=>name, :keys=>keys, :version=>version,
:type=>type, :dir=>dir)
\ No newline at end of file
Modified: trunk/apps/rubyFreenet/rsite/rsite.rb
===================================================================
--- trunk/apps/rubyFreenet/rsite/rsite.rb 2006-06-10 03:18:04 UTC (rev
9121)
+++ trunk/apps/rubyFreenet/rsite/rsite.rb 2006-06-10 08:12:10 UTC (rev
9122)
@@ -1,15 +1,57 @@
$:.push('../')
require 'freenet'
+require 'yaml'
module Freenet
class Site
- attr_accessor :version, :client, :keys, :name
- def self.load(file)
- Marshal.load(IO.read(file))
+ STORE_PATH = File.expand_path("~/.rubyFreenetSites")
+ def self.add_site(site)
+ existing_sites = load_sites
+ site = site.to_hash if site.respond_to? :to_hash
+ existing_sites << site
+ save_sites(existing_sites)
end
+ def self.save_sites(sites)
+ sites = sites.collect do |s|
+ if s.respond_to? :to_hash
+ s.to_hash
+ else
+ s
+ end
+ end
+ File.open(STORE_PATH, 'w') do |f|
+ f.flock(File::LOCK_EX)
+ YAML.dump(sites, f)
+ f.flock(File::LOCK_UN)
+ end
+ end
+
+ def self.load_sites
+ if File.exists? STORE_PATH
+ sites = []
+ File.open(STORE_PATH) do |f|
+ f.flock(File::LOCK_EX)
+ sites = YAML.load(f)
+ f.flock(File::LOCK_UN)
+ end
+ sites ||= []
+ sites.collect do |s|
+ site = Site.new(s[:type], s[:dir], s[:name])
+ site.keys = s[:keys] if s[:keys]
+ site.version = s[:version]
+ site.last_update = s[:last_update]
+ site
+ end
+ else
+ []
+ end
+ end
+
+ attr_accessor :version, :client, :keys, :name, :last_update
+
def initialize(type, path, name)
- raise SiteError.new('Invalid type') unless
['USK','SSK','CHK','KSK'].include? type
+ raise SiteError.new("Invalid type: #{type}") unless
['USK','SSK','CHK','KSK'].include? type
@path, @type, @name = path, type, name
@version = ''
end
@@ -18,6 +60,10 @@
@client = Freenet::FCP::Client.new()
end
+ def disconnect
+ @client.disconnect
+ end
+
def generate_key
@keys = @client.generate_keypair
end
@@ -36,10 +82,11 @@
@uri ||= Freenet::URI.new(@keys[0])
@uri.type = @type
@uri.path = "/#{@name}"
- @uri.version ||= 0
+ @uri.version ||= @version
@uri.version += 1
- puts "Insert key: #{@uri.uri}\nRequest key: #{@uri.uri}"
- @client.putdir(@uri, path)
+ @last_update = File.mtime(path)
+ uri = @client.putdir(@uri, path)
+ uri
end
# Insert a single file. You probably want a CHK for this, use it to insert
@@ -73,11 +120,13 @@
end
end
- def save(file)
- client = @client
- @client = nil
- File.open(file, 'w') {|f| f.write(Marshal.dump(self))}
- @client = client
+ def to_hash
+ {:type=>@type,
+ :name=>@name,
+ :version=>@version,
+ :dir=>@path,
+ :keys=>@keys,
+ :last_update=>@last_update}
end
end
Added: trunk/apps/rubyFreenet/rsite/updatesites
===================================================================
--- trunk/apps/rubyFreenet/rsite/updatesites 2006-06-10 03:18:04 UTC (rev
9121)
+++ trunk/apps/rubyFreenet/rsite/updatesites 2006-06-10 08:12:10 UTC (rev
9122)
@@ -0,0 +1,14 @@
+#!/usr/bin/ruby
+
+require 'rsite'
+require 'getoptlong'
+require 'rdoc/usage'
+
+sites = Freenet::Site.load_sites
+sites.each do |site|
+ site.connect
+ puts site.insert_site
+ site.disconnect
+end
+
+Freenet::Site.save_sites(sites)
\ No newline at end of file