Class: DCI::Proxy::Downloader

Inherits:
Object
  • Object
show all
Includes:
Transfer
Defined in:
lib/dci/proxy/downloader.rb

Constant Summary

Constants included from Transfer

Transfer::BUFFER_SIZE

Instance Method Summary collapse

Methods included from Transfer

#connect_to_peer, #start_transfer, #transfer_chunk

Constructor Details

#initializeDownloader

Returns a new instance of Downloader.



15
16
17
18
19
# File 'lib/dci/proxy/downloader.rb', line 15

def initialize
	@lock = Mutex.new
	@queue = Queue.new
	@downloads = {}
end

Instance Method Details

#download(tth) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/dci/proxy/downloader.rb', line 60

def download tth
	data = $index.load_by_tth(tth) or fail 'invalid TTH'
	filename = "TTH/#{tth}"
	offset = 0
	size = data[:size]
	usernames = data[:locations].map{ |x,_| x }.uniq
	cache_id = 'tth:' + tth
	cache_fn = CFG['cache_dir'] + '/' + cache_id
	begin
		out = File.open(cache_fn, 'w')
		while offset < size
			s, len = nil, nil
			while !s
				s, len = connect_to_peer usernames, filename, offset
				sleep 10 unless s
			end
			n = transfer_chunk s, out, len
			offset += n
			log.warn "transfer aborted by peer at (#{offset}/#{size}), trying to resume" unless offset == size
		end
	rescue => e
		log.warn "transfer failed: #{e.class} #{e.message}"
		File.delete cache_fn
	ensure
		s.close unless !s || s.closed?
		out.close unless !out || out.closed?
	end
end

#enqueue(tth, username) ⇒ Object



21
22
23
24
25
26
27
28
29
30
# File 'lib/dci/proxy/downloader.rb', line 21

def enqueue tth, username
	@lock.synchronize do
		if @downloads.member? tth
			@downloads[tth].usernames << username
		else
			@downloads[tth] = Download.new tth, [username]
			@queue << tth
		end
	end
end

#runObject



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/dci/proxy/downloader.rb', line 44

def run
	while true
		tth = @queue.pop
		dl = @downloads[tth]
		log.info "downloading #{tth} for #{dl.usernames}"
		begin
			download tth
			log.info "finished #{tth}"
			dl.usernames.each { |x| $bot.cb_download_complete x, tth }
		rescue => e
			log.info "failed to download #{tth}: #{e.message}"
			dl.usernames.each { |x| $bot.cb_download_failed x, tth, e.message }
		end
	end
end

#unenqueue(tth, username) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
# File 'lib/dci/proxy/downloader.rb', line 32

def unenqueue tth, username
	@lock.synchronize do
		if @downloads.member? tth
			@downloads[tth].usernames.delete username
			if @queue.member?(tth) and @downloads[tth].usernames.empty?
				@queue.remove tth
				@downloads.remove tth
			end
		end
	end
end