fargo 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,17 +1,20 @@
1
1
  module Fargo
2
2
  module Supports
3
3
  module Timeout
4
-
4
+
5
5
  def timeout_response timeout, succeed_subscription
6
6
  thread = Thread.current
7
- subscribed_block = lambda do |*args|
7
+
8
+ subscribed_block = lambda do |args|
8
9
  thread.wakeup if succeed_subscription.call(*args)
9
10
  end
10
11
 
11
- subscribe &subscribed_block
12
- yield
12
+ id = channel.subscribe subscribed_block
13
+
14
+ yield if block_given?
13
15
  sleep timeout
14
- unsubscribe &subscribed_block
16
+
17
+ channel.unsubscribe id
15
18
  end
16
19
 
17
20
  end
@@ -2,15 +2,15 @@ module Fargo
2
2
  module Supports
3
3
  module Uploads
4
4
  # TODO: write this module...
5
-
5
+
6
6
  def open_slots
7
7
  0
8
8
  end
9
-
9
+
10
10
  def share_size
11
- 5368709121 # 5 GB + 1 byte
11
+ 5368709121 # 5 GB + 1 byte
12
12
  end
13
-
13
+
14
14
  end
15
15
  end
16
- end
16
+ end
data/lib/fargo/utils.rb CHANGED
@@ -1,12 +1,13 @@
1
1
  module Fargo
2
2
  module Utils
3
-
3
+
4
4
  # Lord knows why they're doing this...
5
5
  def generate_key lock
6
6
  lock_bytes = lock.bytes.to_a
7
7
  bytes = []
8
8
  bytes << (lock_bytes[0] ^ lock_bytes[-1] ^ lock_bytes[-2] ^ 5)
9
- (1..lock.length-1).each{ |i|
9
+
10
+ (1..lock.length-1).each{ |i|
10
11
  bytes << (lock_bytes[i] ^ lock_bytes[i - 1])
11
12
  }
12
13
 
@@ -14,7 +15,7 @@ module Fargo
14
15
  bytes.each{ |b| key << encode_char(((b << 4) | (b >> 4)) & 0xff) }
15
16
  key
16
17
  end
17
-
18
+
18
19
  # Generates a lock between 80 and 134 random characters, and a pk of 16
19
20
  # random characters. At least in theory, other clients were doing exactly
20
21
  # this, so I just mirrored them.
@@ -22,7 +23,7 @@ module Fargo
22
23
  lock = 'EXTENDEDPROTOCOL'
23
24
  [lock + ('ABC' * 6), 'ABCD' * 4]
24
25
  end
25
-
26
+
26
27
  # Watch out for those special ones...
27
28
  def encode_char c
28
29
  if [0, 5, 36, 96, 124, 126].include? c
data/lib/fargo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Fargo
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/fargo.rb CHANGED
@@ -1,26 +1,26 @@
1
- require 'socket'
2
1
  require 'fileutils'
2
+ require 'eventmachine'
3
3
  require 'active_support/dependencies/autoload'
4
4
  require 'active_support/core_ext/module/attribute_accessors'
5
5
  require 'active_support/buffered_logger'
6
6
  require 'active_support/concern'
7
+ require 'active_support/configurable'
7
8
 
8
9
  module Fargo
9
10
  extend ActiveSupport::Autoload
10
11
 
11
12
  class ConnectionException < RuntimeError; end
12
-
13
+
13
14
  mattr_accessor:logger
14
15
  self.logger = ActiveSupport::BufferedLogger.new STDOUT
15
16
 
16
- autoload :Utils
17
- autoload :Publisher
17
+ autoload :Utils
18
18
  autoload :Parser
19
- autoload :Server
20
19
  autoload :Client
21
20
  autoload :Search
22
21
  autoload :SearchResult
23
22
  autoload :VERSION
23
+ autoload :TTH
24
24
 
25
25
  module Supports
26
26
  extend ActiveSupport::Autoload
@@ -35,14 +35,12 @@ module Fargo
35
35
  autoload :FileList
36
36
  end
37
37
 
38
- module Connection
38
+ module Protocol
39
39
  extend ActiveSupport::Autoload
40
40
 
41
- autoload :Base
41
+ autoload :DC
42
42
  autoload :Download
43
43
  autoload :Hub
44
- autoload :Search
45
- autoload :Upload
46
44
  end
47
45
 
48
- end
46
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fargo
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Alex Crichton
@@ -15,11 +15,25 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-09-22 00:00:00 -04:00
18
+ date: 2010-09-27 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 3
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ requirement: *id001
32
+ type: :runtime
33
+ name: eventmachine
34
+ prerelease: false
35
+ - !ruby/object:Gem::Dependency
36
+ version_requirements: &id002 !ruby/object:Gem::Requirement
23
37
  none: false
24
38
  requirements:
25
39
  - - ">="
@@ -30,12 +44,12 @@ dependencies:
30
44
  - 0
31
45
  - 0
32
46
  version: 3.0.0
33
- requirement: *id001
47
+ requirement: *id002
34
48
  type: :runtime
35
49
  name: activesupport
36
50
  prerelease: false
37
51
  - !ruby/object:Gem::Dependency
38
- version_requirements: &id002 !ruby/object:Gem::Requirement
52
+ version_requirements: &id003 !ruby/object:Gem::Requirement
39
53
  none: false
40
54
  requirements:
41
55
  - - ">="
@@ -44,12 +58,12 @@ dependencies:
44
58
  segments:
45
59
  - 0
46
60
  version: "0"
47
- requirement: *id002
61
+ requirement: *id003
48
62
  type: :runtime
49
63
  name: libxml-ruby
50
64
  prerelease: false
51
65
  - !ruby/object:Gem::Dependency
52
- version_requirements: &id003 !ruby/object:Gem::Requirement
66
+ version_requirements: &id004 !ruby/object:Gem::Requirement
53
67
  none: false
54
68
  requirements:
55
69
  - - ">="
@@ -58,7 +72,7 @@ dependencies:
58
72
  segments:
59
73
  - 0
60
74
  version: "0"
61
- requirement: *id003
75
+ requirement: *id004
62
76
  type: :runtime
63
77
  name: bzip2-ruby
64
78
  prerelease: false
@@ -66,23 +80,30 @@ description: Direct Connect (DC) Client implemented in pure Ruby
66
80
  email: alex@alexcrichton.com
67
81
  executables: []
68
82
 
69
- extensions: []
70
-
83
+ extensions:
84
+ - ext/fargo/extconf.rb
71
85
  extra_rdoc_files: []
72
86
 
73
87
  files:
88
+ - ext/fargo/base32.c
89
+ - ext/fargo/base32.h
90
+ - ext/fargo/extconf.rb
91
+ - ext/fargo/fargo_tth.c
92
+ - ext/fargo/sboxes.c
93
+ - ext/fargo/tiger.c
94
+ - ext/fargo/tiger.h
95
+ - ext/fargo/tigertree.c
96
+ - ext/fargo/tigertree.h
97
+ - ext/fargo/tth.c
98
+ - ext/fargo/tth.h
74
99
  - lib/fargo.rb
75
100
  - lib/fargo/client.rb
76
- - lib/fargo/connection/base.rb
77
- - lib/fargo/connection/download.rb
78
- - lib/fargo/connection/hub.rb
79
- - lib/fargo/connection/search.rb
80
- - lib/fargo/connection/upload.rb
81
101
  - lib/fargo/parser.rb
82
- - lib/fargo/publisher.rb
102
+ - lib/fargo/protocol/dc.rb
103
+ - lib/fargo/protocol/download.rb
104
+ - lib/fargo/protocol/hub.rb
83
105
  - lib/fargo/search.rb
84
106
  - lib/fargo/search_result.rb
85
- - lib/fargo/server.rb
86
107
  - lib/fargo/supports/chat.rb
87
108
  - lib/fargo/supports/downloads.rb
88
109
  - lib/fargo/supports/file_list.rb
@@ -102,6 +123,7 @@ rdoc_options:
102
123
  - --charset=UTF-8
103
124
  require_paths:
104
125
  - lib
126
+ - ext
105
127
  required_ruby_version: !ruby/object:Gem::Requirement
106
128
  none: false
107
129
  requirements:
@@ -1,126 +0,0 @@
1
- require 'active_support/configurable'
2
- require 'active_support/callbacks'
3
-
4
- module Fargo
5
- class ConnectionError < RuntimeError; end
6
-
7
- module Connection
8
- class Base
9
-
10
- include ActiveSupport::Configurable
11
- include ActiveSupport::Callbacks
12
- include Fargo::Publisher
13
-
14
- attr_accessor :socket
15
- define_callbacks :listen
16
-
17
- def initialize client
18
- @outgoing = Queue.new
19
- @client = client
20
- config.quit_on_disconnect = true
21
- end
22
-
23
- def connect
24
- Fargo.logger.info(
25
- "#{self}: Opening connection with #{config.address}, #{config.port}"
26
- )
27
-
28
- open_socket
29
- listen
30
-
31
- connection_type = self.class.name.split('::').last.downcase
32
- @client.publish :"#{connection_type}_connection_opened"
33
- end
34
-
35
- def receive
36
- raise 'Implement me!'
37
- end
38
-
39
- def open_socket
40
- @socket ||= TCPSocket.open config.address, config.port
41
- rescue Errno::ECONNREFUSED
42
- raise Fargo::ConnectionError.new "Couldn't open a connection to #{config.address}:#{config.port}"
43
- end
44
-
45
- def connected?
46
- !@socket.nil? && !@socket.closed?
47
- end
48
-
49
- def listen
50
- return unless @threads.nil? || @threads.size == 0
51
-
52
- run_callbacks :listen do
53
- @threads = []
54
- @looping = true
55
-
56
- # Start a thread to read the socket
57
- @threads << Thread.start { read_data while @looping }
58
-
59
- # Start a thread to send information from the queue
60
- @threads << Thread.start { write_data @outgoing.pop while @looping }
61
-
62
- @threads.each { |t| t.abort_on_exception = true }
63
- end
64
- end
65
-
66
- def disconnect
67
- Fargo.logger.debug "#{self}: Disconnecting connection"
68
-
69
- write "$Quit #{@client.config.nick}" if config.quit_on_disconnect
70
-
71
- @looping = false
72
-
73
- if @threads
74
- @threads.each{ |t| t.exit unless t == Thread.current }
75
- @threads.clear
76
- end
77
-
78
- if @socket
79
- begin
80
- @socket.close
81
- rescue => e
82
- Fargo.logger.error "Error closing socket: #{e}"
83
- end
84
- end
85
-
86
- @socket = nil
87
- @outgoing.clear
88
-
89
- connection_type = self.class.name.split('::').last.downcase
90
- @client.publish :"#{connection_type}_disconnected"
91
- end
92
-
93
- def write string
94
- string << '|' unless string.end_with?('|')
95
- @outgoing << string # append this to the queue of things to be written
96
- true
97
- end
98
-
99
- private
100
-
101
- def read_data
102
- data = @socket.gets '|'
103
- raise ConnectionError.new('Received nil data!') if data.nil?
104
-
105
- Fargo.logger.debug "#{self} Received: #{data.inspect}"
106
- receive data.chomp('|')
107
- rescue => e
108
- unless @socket.closed?
109
- Fargo.logger.warn "#{self}: Error reading data, going away: #{e}"
110
- disconnect
111
- end
112
- end
113
-
114
- def write_data data
115
- Fargo.logger.debug "#{self} Sending: #{data.inspect}"
116
- @socket << data
117
- rescue => e
118
- unless @socket.closed?
119
- Fargo.logger.warn "#{self}: Error writing data, going away: #{e}"
120
- disconnect
121
- end
122
- end
123
-
124
- end
125
- end
126
- end
@@ -1,120 +0,0 @@
1
- module Fargo
2
- module Connection
3
- class Hub < Base
4
-
5
- include Fargo::Utils
6
- include Fargo::Parser
7
-
8
- attr_reader :hubname
9
-
10
- configure do |config|
11
- config.address = '127.0.0.1'
12
- config.port = 7314
13
- end
14
-
15
- # See <http://www.teamfair.info/DC-Protocol.htm> for specifics on
16
- # the DC protocol
17
- def receive data
18
- message = parse_message data
19
-
20
- case message[:type]
21
- when :lock
22
- @validated = false
23
- write "$Key #{generate_key message[:lock]}"
24
- when :hubname
25
- @hubname = message[:name]
26
- write "$ValidateNick #{@client.config.nick}" unless @validated
27
- when :getpass
28
- write "$MyPass #{@client.password}"
29
- when :badpass, :hubfull
30
- Fargo.logger.warn "Disconnecting because of: #{message.inspect}"
31
- disconnect
32
- when :hello
33
- if message[:who] == @client.config.nick
34
- Fargo.logger.info "Connected to DC Hub #{@hubname} (#{config.address}:#{config.port})"
35
- @validated = true
36
-
37
- write '$Version 1,0091'
38
- write '$GetNickList'
39
- write "$MyINFO $ALL #{@client.config.nick} " +
40
- "#{@client.description}$ $#{@client.config.speed || 'DSL'}" +
41
- "#{@status || 1.chr}$#{@client.config.email}" +
42
- "$#{@client.share_size}$"
43
- end
44
-
45
- when :connect_to_me
46
- if !@client.nicks.include?(message[:nick])
47
- Fargo.logger.info "Invalid connect_to_me request from: #{message[:nick]}"
48
- return
49
- end
50
-
51
- @client_connections ||= []
52
-
53
- connection = Fargo::Connection::Download.new @client
54
- connection.config.address = message[:address]
55
- connection.config.port = message[:port]
56
- # we're going to initiate the download
57
- connection.config.first = true
58
-
59
- # proxy all messages from them back to the client and delete the
60
- # connection if necessary
61
- connection.subscribe { |*args|
62
- @client.publish *args
63
- @client_connections.delete connection unless connection.connected?
64
- }
65
-
66
- # establish the connection. This will also listen for data to be
67
- # read/written
68
- connection.connect
69
-
70
- # keep track of who we're downloading from
71
- @client_connections << connection
72
-
73
- when :search
74
- # Make sure we received a valid search request
75
- if message[:searcher].nil? || !@client.nicks.include?(message[:searcher])
76
- Fargo.logger.info "Invalid search request: #{message.inspect}"
77
- return
78
- end
79
-
80
- # Let the client handle the results
81
- @results = @client.search_files message
82
-
83
- # Send all the results to the peer. Take care of active/passive
84
- # connections
85
- @results.each { |r|
86
- if message[:address]
87
- r.active_send @client.config.nick, message[:ip], message[:port]
88
- else
89
- write "$SR #{@client.config.nick} #{r}"
90
- end
91
- }
92
-
93
- when :revconnect
94
- # TODO: Don't send RevConnectToMe when we're passive and
95
- # receiving is passive
96
- if @client.config.passive
97
- write "$RevConnectToMe #{@client.config.nick} #{message[:who]}"
98
- else
99
- write "$ConnectToMe #{@client.config.nick} #{@client.config.address}:#{@client.config.extport}"
100
- end
101
-
102
- # proxy this message on up the stack if we don't handle it
103
- else
104
- @client.publish message[:type], message
105
-
106
- end
107
- end
108
-
109
- def disconnect
110
- if @client_connections
111
- @client_connections.each &:disconnect
112
- @client_connections.clear
113
- end
114
-
115
- super
116
- end
117
-
118
- end # Hub
119
- end # Connection
120
- end # Fargo
@@ -1,19 +0,0 @@
1
- module Fargo
2
- module Connection
3
- class Search < Base
4
-
5
- # maybe do something special here at some point?
6
- # this is currently just receiving the search result packets over UDP
7
- # and fowarding them to the client who will handle them. This doesn't
8
- # explicitly disconnect because I'm not sure if multiple results
9
- # are sent. This connection will close itself because there will
10
- # be a read error I think...
11
- def receive data
12
- message = parse_message data
13
-
14
- @client.publish message[:type], message
15
- end
16
-
17
- end
18
- end
19
- end
@@ -1,85 +0,0 @@
1
- # TODO: actually get this class to work in some fashion
2
- module Fargo
3
- module Connection
4
- class Upload < Base
5
-
6
- include Fargo::Utils
7
- include Fargo::Parser
8
-
9
- def post_listen
10
- @lock, @pk = generate_lock
11
- write "$MyNick #{self[:nick]}|$Lock #{@lock} Pk=#{@pk}"
12
- @handshake_step = 0
13
- end
14
-
15
- def supports
16
- "$Supports BZList TTHL TTHF" # ???
17
- end
18
-
19
- def receive data
20
- message = parse_message data
21
- publish message[:type], message
22
- case message[:type]
23
- when :mynick
24
- if @handshake_step == 0
25
- @remote_nick = message[:nick]
26
- @handshake_step = 1
27
- else
28
- disconnect
29
- end
30
- when :lock
31
- if @handshake_step == 1
32
- @remote_lock = message[:lock]
33
- @handshake_step = 2
34
- else
35
- disconnect
36
- end
37
- when :supports
38
- if @handshake_step == 2
39
- @remote_extensions = message[:extensions]
40
- @handshake_step = 3
41
- else
42
- disconnect
43
- end
44
- when :direction
45
- if @handshake_step == 3 && message[:direction] == 'download'
46
- @handshake_step = 4
47
- @client_num = message[:number]
48
- else
49
- disconnect
50
- end
51
- when :key
52
- if @handshake_step == 4 && generate_key(@lock) == message[:key]
53
- write supports
54
- write "$Direction Download #{@my_num = rand 10000}"
55
- write "$Key #{generate_key @remote_lock}"
56
- @handshake_step = 5
57
- else
58
- disconnect
59
- end
60
- when :get
61
- if @handshake_step == 5
62
- @filepath = message[:path]
63
- @offset = message[:offset]
64
- write "$FileLength #{file_length}"
65
- @handshake_step = 5
66
- else
67
- disconnect
68
- end
69
- when :send
70
- write_chunk if @handshake_step == 5
71
-
72
- else
73
- # Fargo.logger.warn "Ignoring `#{data}'\n"
74
- end
75
- end
76
-
77
- def write_chunk
78
- end
79
-
80
- def file_length
81
- end
82
-
83
- end
84
- end
85
- end
@@ -1,42 +0,0 @@
1
- module Fargo
2
- module Publisher
3
-
4
- attr_reader :subscribers
5
-
6
- def subscribe &subscriber
7
- raise RuntimeError.new('Need a subscription block!') if subscriber.nil?
8
-
9
- Fargo.logger.debug "#{self}: subscribing #{subscriber}"
10
- (@subscribers ||= []) << subscriber
11
- end
12
-
13
- def subscribed_to?
14
- @subscribers && @subscribers.size > 0
15
- end
16
-
17
- def unsubscribe &subscriber
18
- raise RuntimeError.new('Need a subscription block!') if subscriber.nil?
19
-
20
- Fargo.logger.debug "#{self}: unsubscribing #{subscriber}"
21
- (@subscribers ||= []).delete subscriber
22
- end
23
-
24
- def publish message_type, hash = {}
25
- @subscribers ||= []
26
-
27
- to_remove = []
28
-
29
- @subscribers.each do |subscriber|
30
- begin
31
- subscriber.call message_type, hash
32
- rescue => e
33
- Fargo.logger.warn "#{self}: error publishing to: #{subscriber}! #{e}"
34
- to_remove << subscriber
35
- end
36
- end
37
-
38
- @subscribers -= to_remove
39
- end
40
-
41
- end
42
- end