fargo 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +49 -1
- data/bin/fargo +5 -0
- data/ext/fargo/base32.c +0 -25
- data/ext/fargo/base32.h +0 -8
- data/ext/fargo/tiger.c +0 -24
- data/ext/fargo/tiger.h +0 -8
- data/ext/fargo/tigertree.c +0 -36
- data/ext/fargo/tigertree.h +0 -6
- data/ext/fargo/tth.h +0 -8
- data/ext/readline/extconf.rb +9 -0
- data/ext/readline/fargo_cli.c +28 -0
- data/ext/readline/screen.c +77 -0
- data/ext/readline/screen.h +3 -0
- data/lib/fargo.rb +3 -1
- data/lib/fargo/cli.rb +84 -0
- data/lib/fargo/cli/completion.rb +41 -0
- data/lib/fargo/cli/downloads.rb +57 -0
- data/lib/fargo/cli/help.rb +80 -0
- data/lib/fargo/cli/info.rb +55 -0
- data/lib/fargo/cli/logging.rb +87 -0
- data/lib/fargo/cli/nick_browser.rb +159 -0
- data/lib/fargo/cli/searches.rb +63 -0
- data/lib/fargo/cli/stats.rb +16 -0
- data/lib/fargo/client.rb +33 -8
- data/lib/fargo/ext/irb.rb +33 -0
- data/lib/fargo/ext/readline.rb +18 -0
- data/lib/fargo/ext/struct.rb +7 -0
- data/lib/fargo/protocol/peer_download.rb +7 -4
- data/lib/fargo/supports/chat.rb +15 -0
- data/lib/fargo/supports/downloads.rb +5 -1
- data/lib/fargo/supports/local_file_list.rb +42 -36
- data/lib/fargo/supports/remote_file_list.rb +9 -7
- data/lib/fargo/supports/searches.rb +6 -0
- data/lib/fargo/version.rb +1 -1
- data/spec/fargo/protocol/hub_spec.rb +1 -1
- data/spec/fargo/protocol/peer_upload_spec.rb +1 -1
- data/spec/fargo/search_spec.rb +6 -1
- data/spec/fargo/supports/chat_spec.rb +7 -0
- data/spec/fargo/supports/local_file_list_spec.rb +32 -1
- data/spec/spec_helper.rb +6 -3
- metadata +65 -26
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
|
3
|
+
module Fargo
|
4
|
+
module CLI
|
5
|
+
module Searches
|
6
|
+
delegate :search, :to => :client
|
7
|
+
|
8
|
+
def setup_console
|
9
|
+
super
|
10
|
+
|
11
|
+
add_completion(/^results\s+[^\s]+$/){ client.searches }
|
12
|
+
|
13
|
+
add_logger(:search_result) do |message|
|
14
|
+
obj = client.search_objects.detect{ |s| s.matches? message }
|
15
|
+
if obj
|
16
|
+
"New search result for: #{obj.query.inspect}"
|
17
|
+
else
|
18
|
+
'New search result'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def results str = nil, opts = {}
|
24
|
+
str ||= client.searches.last
|
25
|
+
results = client.search_results(str)
|
26
|
+
|
27
|
+
if results.nil?
|
28
|
+
puts "No search results for: #{str.inspect}!"
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
results = results.map{ |r| r.dup }
|
33
|
+
|
34
|
+
results.each_with_index{ |r, i|
|
35
|
+
r[:file] = r[:file].gsub("\\", '/')
|
36
|
+
r[:file] = File.basename(r[:file]) unless opts[:full]
|
37
|
+
r[:index] = i
|
38
|
+
}
|
39
|
+
|
40
|
+
max_nick_size = results.map{ |r| r[:nick].size }.max
|
41
|
+
|
42
|
+
if opts[:sort] == 'size'
|
43
|
+
results = results.sort_by{ |r| r[:size] }
|
44
|
+
elsif !opts[:sort].nil?
|
45
|
+
puts "Unknown sort value: #{opts[:sort]}"
|
46
|
+
results = []
|
47
|
+
end
|
48
|
+
|
49
|
+
if opts[:grep]
|
50
|
+
results = results.select{ |r| r[:file].match opts[:grep] }
|
51
|
+
end
|
52
|
+
|
53
|
+
results.each do |r|
|
54
|
+
printf "%3d: %#{max_nick_size}s %9s -- %s\n", r[:index],
|
55
|
+
r[:nick], humanize_bytes(r[:size]), r[:file]
|
56
|
+
end
|
57
|
+
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Fargo
|
2
|
+
module CLI
|
3
|
+
module Stats
|
4
|
+
|
5
|
+
def status
|
6
|
+
puts "User count: #{client.nicks.size}"
|
7
|
+
puts "Shared Directories:"
|
8
|
+
client.shared_directories.each do |dir|
|
9
|
+
puts "\t#{dir}"
|
10
|
+
end
|
11
|
+
puts "Sharing: #{humanize_bytes(client.share_size)}"
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/fargo/client.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'socket'
|
2
|
+
require 'base64'
|
2
3
|
require 'active_support/core_ext/object/try'
|
3
4
|
require 'active_support/callbacks'
|
5
|
+
require 'active_support/configurable'
|
6
|
+
require 'em-websocket'
|
4
7
|
|
5
8
|
module Fargo
|
6
9
|
class Client
|
@@ -22,14 +25,17 @@ module Fargo
|
|
22
25
|
|
23
26
|
configure do |config|
|
24
27
|
config.download_dir = '/tmp/fargo/downloads'
|
25
|
-
config.config_dir = '
|
26
|
-
config.address =
|
28
|
+
config.config_dir = ENV['HOME'] + '/.fargo'
|
29
|
+
config.address =
|
30
|
+
(IPSocket.getaddress(Socket.gethostname) rescue '0.0.0.0')
|
27
31
|
config.passive = false
|
28
32
|
config.nick = 'fargo'
|
29
33
|
config.hub_address = '127.0.0.1'
|
30
34
|
config.hub_port = 7314
|
31
35
|
config.active_port = 7315
|
32
36
|
config.search_port = 7316
|
37
|
+
config.websocket_port = 9091
|
38
|
+
config.websocket_host = '127.0.0.1'
|
33
39
|
config.download_slots = 4
|
34
40
|
config.upload_slots = 4
|
35
41
|
config.password = ''
|
@@ -49,15 +55,15 @@ module Fargo
|
|
49
55
|
@channel.subscribe do |type, hash|
|
50
56
|
Fargo.logger.debug "Channel received: #{type} - #{hash.inspect}"
|
51
57
|
end
|
58
|
+
|
59
|
+
config_file = config.config_dir + '/config'
|
60
|
+
if File.exists? config_file
|
61
|
+
eval File.read(config_file)
|
62
|
+
end
|
52
63
|
end
|
53
64
|
end
|
54
65
|
|
55
66
|
def connect
|
56
|
-
EventMachine.error_handler{ |e|
|
57
|
-
Fargo.logger.debug "Error raised during event loop: #{e.message}"
|
58
|
-
Fargo.logger.debug e.backtrace.join("\n")
|
59
|
-
}
|
60
|
-
|
61
67
|
run_callbacks :connect do
|
62
68
|
EventMachine.connect config.hub_address, config.hub_port,
|
63
69
|
Protocol::Hub do |conn|
|
@@ -77,10 +83,29 @@ module Fargo
|
|
77
83
|
end
|
78
84
|
end
|
79
85
|
end
|
86
|
+
|
87
|
+
start_websocket_service
|
88
|
+
end
|
89
|
+
|
90
|
+
def start_websocket_service
|
91
|
+
EventMachine.start_server(config.websocket_host, config.websocket_port,
|
92
|
+
EventMachine::WebSocket::Connection, {}) do |ws|
|
93
|
+
ws.onopen {
|
94
|
+
Fargo.logger.debug('ws connected')
|
95
|
+
|
96
|
+
sid = channel.subscribe do |type, hash|
|
97
|
+
if type != :download_opened
|
98
|
+
ws.send Base64.encode64(Marshal.dump([type, hash]))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
ws.onclose{ channel.unsubscribe sid }
|
103
|
+
}
|
104
|
+
end
|
80
105
|
end
|
81
106
|
|
82
107
|
def connected?
|
83
|
-
EventMachine.reactor_running?
|
108
|
+
EventMachine.reactor_running? && !hub.error?
|
84
109
|
end
|
85
110
|
|
86
111
|
def disconnect
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'irb'
|
2
|
+
|
3
|
+
# See url below for where this came from
|
4
|
+
# http://jameskilton.com/2009/04/02/embedding-irb-into-your-ruby-application/
|
5
|
+
module IRB
|
6
|
+
def self.start_session(binding)
|
7
|
+
unless @__initialized
|
8
|
+
args = ARGV
|
9
|
+
ARGV.replace(ARGV.dup)
|
10
|
+
IRB.setup(nil)
|
11
|
+
ARGV.replace(args)
|
12
|
+
@__initialized = true
|
13
|
+
end
|
14
|
+
|
15
|
+
workspace = WorkSpace.new(binding)
|
16
|
+
|
17
|
+
irb = Irb.new(workspace)
|
18
|
+
|
19
|
+
trap('SIGINT') do
|
20
|
+
irb.signal_handle
|
21
|
+
end
|
22
|
+
|
23
|
+
@CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
|
24
|
+
@CONF[:MAIN_CONTEXT] = irb.context
|
25
|
+
@CONF[:PROMPT][@CONF[:PROMPT_MODE]][:RETURN].replace ''
|
26
|
+
|
27
|
+
yield if block_given?
|
28
|
+
|
29
|
+
catch(:IRB_EXIT) do
|
30
|
+
irb.eval_input
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'readline'
|
2
|
+
|
3
|
+
if Readline::VERSION =~ /editline/i
|
4
|
+
$stderr.puts "Sorry, fargo CLI requires a ruby compiled against the actual"
|
5
|
+
$stderr.puts "Readline library. Your version is: '#{Readline::VERSION}'"
|
6
|
+
exit 1
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'readline/extra_utils'
|
10
|
+
|
11
|
+
module Readline
|
12
|
+
def self.above_prompt
|
13
|
+
Readline.clear_rl
|
14
|
+
yield
|
15
|
+
ensure
|
16
|
+
Readline.restore
|
17
|
+
end
|
18
|
+
end
|
@@ -21,12 +21,14 @@ module Fargo
|
|
21
21
|
download_finished!
|
22
22
|
else
|
23
23
|
percent = @recvd.to_f / @length
|
24
|
+
@download.percent = percent
|
25
|
+
|
24
26
|
if percent - @last_published > 0.05
|
25
27
|
@file.flush
|
26
28
|
@client.channel << [:download_progress, {:percent => percent,
|
27
29
|
:file => download_path,
|
28
30
|
:nick => @other_nick,
|
29
|
-
:download => @download,
|
31
|
+
:download => @download.to_h,
|
30
32
|
:size => @recvd,
|
31
33
|
:compressed => @zlib}]
|
32
34
|
|
@@ -61,7 +63,8 @@ module Fargo
|
|
61
63
|
end
|
62
64
|
|
63
65
|
@client.channel << [:download_started, {:file => download_path,
|
64
|
-
:download => @download,
|
66
|
+
:download => @download.to_h,
|
67
|
+
:length => @length,
|
65
68
|
:nick => @other_nick}]
|
66
69
|
else
|
67
70
|
error "Premature disconnect when #{message[:type]} received"
|
@@ -157,7 +160,7 @@ module Fargo
|
|
157
160
|
reset_download
|
158
161
|
|
159
162
|
@client.channel << [:download_failed, opts.merge(:nick => @other_nick,
|
160
|
-
:download => download,
|
163
|
+
:download => download.to_h,
|
161
164
|
:file => path,
|
162
165
|
:last_error => msg)]
|
163
166
|
end
|
@@ -172,7 +175,7 @@ module Fargo
|
|
172
175
|
reset_download
|
173
176
|
|
174
177
|
@client.channel << [:download_finished,
|
175
|
-
{:file => path, :download => download, :nick => @other_nick}]
|
178
|
+
{:file => path, :download => download.to_h, :nick => @other_nick}]
|
176
179
|
|
177
180
|
close_connection_after_writing if download.file_list?
|
178
181
|
end
|
data/lib/fargo/supports/chat.rb
CHANGED
@@ -5,6 +5,7 @@ module Fargo
|
|
5
5
|
|
6
6
|
included do
|
7
7
|
set_callback :initialization, :after, :initialize_chats
|
8
|
+
set_callback :connect, :after, :periodically_remove_chats
|
8
9
|
end
|
9
10
|
|
10
11
|
def messages
|
@@ -15,8 +16,22 @@ module Fargo
|
|
15
16
|
@chats[nick]
|
16
17
|
end
|
17
18
|
|
19
|
+
def send_chat text
|
20
|
+
hub.send_data "<#{config.nick}> #{text}|"
|
21
|
+
end
|
22
|
+
|
18
23
|
protected
|
19
24
|
|
25
|
+
def periodically_remove_chats
|
26
|
+
EventMachine.add_periodic_timer 60 do
|
27
|
+
@public_chats = @public_chats[0..100]
|
28
|
+
|
29
|
+
@chats.each_pair do |k, v|
|
30
|
+
@chats[k] = v[0..100]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
20
35
|
def initialize_chats
|
21
36
|
@public_chats = []
|
22
37
|
@chats = Hash.new{ |h, k| h[k] = [] }
|
@@ -19,7 +19,11 @@ module Fargo
|
|
19
19
|
:failed_downloads, :trying, :timed_out
|
20
20
|
|
21
21
|
def has_download_slot?
|
22
|
-
|
22
|
+
open_download_slots > 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def open_download_slots
|
26
|
+
config.download_slots - @trying.size - @current_downloads.size
|
23
27
|
end
|
24
28
|
|
25
29
|
def clear_failed_downloads
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'bzip2'
|
2
|
-
require '
|
2
|
+
require 'nokogiri'
|
3
3
|
require 'active_support/core_ext/module/synchronization'
|
4
4
|
|
5
5
|
module Fargo
|
@@ -8,7 +8,7 @@ module Fargo
|
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
include TTH
|
10
10
|
|
11
|
-
attr_reader :local_file_list
|
11
|
+
attr_reader :local_file_list, :shared_directories
|
12
12
|
|
13
13
|
included do
|
14
14
|
set_callback :initialization, :after, :initialize_upload_lists
|
@@ -16,17 +16,14 @@ module Fargo
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def share_directory dir
|
19
|
-
|
19
|
+
shared_directories << dir unless shared_directories.include? dir
|
20
20
|
|
21
|
-
|
22
|
-
EventMachine.defer {
|
21
|
+
EventMachine.schedule { # Make sure we run in the reactor
|
22
|
+
EventMachine.defer { # This takes awhile so don't block the reactor
|
23
23
|
update_tth dir
|
24
24
|
write_file_list
|
25
25
|
}
|
26
|
-
|
27
|
-
update_tth dir
|
28
|
-
write_file_list
|
29
|
-
end
|
26
|
+
}
|
30
27
|
end
|
31
28
|
|
32
29
|
def share_size
|
@@ -38,11 +35,11 @@ module Fargo
|
|
38
35
|
end
|
39
36
|
|
40
37
|
def local_listings
|
41
|
-
collect_local_listings
|
38
|
+
collect_local_listings local_file_list, [], nil
|
42
39
|
end
|
43
40
|
|
44
41
|
def search_local_listings search
|
45
|
-
collect_local_listings
|
42
|
+
collect_local_listings local_file_list, [], search
|
46
43
|
end
|
47
44
|
|
48
45
|
def listing_for query
|
@@ -56,6 +53,10 @@ module Fargo
|
|
56
53
|
|
57
54
|
protected
|
58
55
|
|
56
|
+
def cache_file_list_path
|
57
|
+
File.join config.config_dir, 'file_cache'
|
58
|
+
end
|
59
|
+
|
59
60
|
def collect_local_listings hash, arr, search
|
60
61
|
hash.each_pair do |k, v|
|
61
62
|
if v.is_a?(Listing)
|
@@ -69,18 +70,24 @@ module Fargo
|
|
69
70
|
end
|
70
71
|
|
71
72
|
def write_file_list
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
73
|
+
builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
|
74
|
+
attrs = ActiveSupport::OrderedHash.new
|
75
|
+
attrs[:Base] = '/'
|
76
|
+
attrs[:Version] = '1'
|
77
|
+
attrs[:Generator] = "fargo #{VERSION}"
|
78
|
+
xml.FileListing(attrs) {
|
79
|
+
create_entities local_file_list, xml
|
80
|
+
}
|
81
|
+
end
|
79
82
|
|
80
83
|
FileUtils.mkdir_p config.config_dir
|
81
84
|
Bzip2::Writer.open(local_file_list_path, 'w') do |f|
|
82
|
-
f <<
|
85
|
+
f << builder.to_xml
|
83
86
|
end
|
87
|
+
|
88
|
+
File.open(cache_file_list_path, 'w'){ |f|
|
89
|
+
f << Marshal.dump([local_file_list, shared_directories, share_size])
|
90
|
+
}
|
84
91
|
end
|
85
92
|
|
86
93
|
def update_tth root, directory = nil, hash = nil
|
@@ -89,7 +96,7 @@ module Fargo
|
|
89
96
|
root = File.dirname(root)
|
90
97
|
end
|
91
98
|
|
92
|
-
hash ||= (
|
99
|
+
hash ||= (local_file_list[File.basename(directory)] ||= {})
|
93
100
|
|
94
101
|
Pathname.glob(directory + '/*').each do |path|
|
95
102
|
if path.directory?
|
@@ -125,27 +132,24 @@ module Fargo
|
|
125
132
|
|
126
133
|
synchronize :update_tth, :with => :@update_lock
|
127
134
|
|
128
|
-
def create_entities entity,
|
135
|
+
def create_entities entity, xml
|
129
136
|
entity.each_pair do |k, v|
|
130
137
|
if v.is_a? Hash
|
131
|
-
|
132
|
-
dir['Name'] = k
|
133
|
-
create_entities v, dir
|
134
|
-
node << dir
|
138
|
+
xml.Directory(:Name => k) { create_entities v, xml }
|
135
139
|
else
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
140
|
+
# Make sure they always show up in this order
|
141
|
+
attrs = ActiveSupport::OrderedHash.new
|
142
|
+
attrs[:Name] = k
|
143
|
+
attrs[:Size] = v.size.to_s
|
144
|
+
attrs[:TTH] = v.tth
|
145
|
+
xml.File attrs
|
142
146
|
end
|
143
147
|
end
|
144
148
|
end
|
145
149
|
|
146
150
|
def schedule_update
|
147
151
|
EventMachine::Timer.new(60) do
|
148
|
-
|
152
|
+
shared_directories.each{ |d| update_tth d }
|
149
153
|
|
150
154
|
write_file_list
|
151
155
|
schedule_update
|
@@ -153,10 +157,12 @@ module Fargo
|
|
153
157
|
end
|
154
158
|
|
155
159
|
def initialize_upload_lists
|
156
|
-
@shared_directories =
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
+
@local_file_list, @shared_directories, @share_size = begin
|
161
|
+
Marshal.load File.read(cache_file_list_path)
|
162
|
+
rescue
|
163
|
+
[{}, [], 0]
|
164
|
+
end
|
165
|
+
@update_lock = Mutex.new
|
160
166
|
end
|
161
167
|
|
162
168
|
end
|