fargo 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|