Class: TorrentManager

Inherits:
Object
  • Object
show all
Defined in:
lib/quartz_flow/torrent_manager.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(peerClient, torrentFileDir, monthlyResetDay) ⇒ TorrentManager

Returns a new instance of TorrentManager.



8
9
10
11
12
13
14
15
16
17
18
# File 'lib/quartz_flow/torrent_manager.rb', line 8

def initialize(peerClient, torrentFileDir, monthlyResetDay)
  @peerClient = peerClient
  @cachedTorrentData = nil
  @cachedAt = nil
  @cacheLifetime = 2
  @torrentFileDir = torrentFileDir
  @peerClientStopped = false
  @usageTracker = UsageTracker.new(monthlyResetDay)
  # Start a thread to keep track of usage.
  startUsageTrackerThread
end

Instance Attribute Details

#peerClientObject (readonly)

Returns the value of attribute peerClient.



20
21
22
# File 'lib/quartz_flow/torrent_manager.rb', line 20

def peerClient
  @peerClient
end

Instance Method Details

#applyTorrentSettings(infoHash) ⇒ Object

Update the torrent settings (upload rate limit, etc) from database values



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/quartz_flow/torrent_manager.rb', line 226

def applyTorrentSettings(infoHash)
  asciiInfoHash = QuartzTorrent::bytesToHex(infoHash)
  helper = SettingsHelper.new

  # Set limits based on per-torrent settings if they exist, otherwise to default global limits if they exist.
  uploadRateLimit = to_i(helper.get(:uploadRateLimit, :unfiltered, asciiInfoHash))
  uploadRateLimit = to_i(helper.get(:defaultUploadRateLimit, :unfiltered)) if ! uploadRateLimit

  downloadRateLimit = to_i(helper.get(:downloadRateLimit, :unfiltered, asciiInfoHash))
  downloadRateLimit = to_i(helper.get(:defaultDownloadRateLimit, :unfiltered)) if ! downloadRateLimit

  ratio = helper.get(:ratio, :filter, asciiInfoHash)
  ratio = helper.get(:defaultRatio, :filter) if ! ratio

  uploadDuration = helper.get(:uploadDuration, :unfiltered, asciiInfoHash)
  uploadDuration = helper.get(:defaultUploadDuration, :unfiltered) if ! uploadDuration
  uploadDuration = uploadDuration.to_i if uploadDuration

  @peerClient.setUploadRateLimit infoHash, uploadRateLimit
  @peerClient.setDownloadRateLimit infoHash, downloadRateLimit
  @peerClient.setUploadRatio infoHash, ratio
  @peerClient.setUploadDuration infoHash, uploadDuration
end

#currentPeriodUsage(periodType) ⇒ Object

Get the usage for the current period of the specified type. periodType should be one of :daily or :monthly.



252
253
254
# File 'lib/quartz_flow/torrent_manager.rb', line 252

def currentPeriodUsage(periodType)
  @usageTracker.currentUsage(periodType).value
end

#downloadTorrentFile(url) ⇒ Object

Download a .torrent file from a specified URL. Return the path to the downloaded .torrent file.



138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/quartz_flow/torrent_manager.rb', line 138

def downloadTorrentFile(url)
  # open-uri doesn't handle [ and ] properly
  encodedSourcePath = URI.escape(url, /[\[\]]/)

  path = nil
  open(encodedSourcePath) do |f|
    uriPath = f.base_uri.path
    raise "The file '#{uriPath}' doesn't have the .torrent extension" if uriPath !~ /.torrent$/
    path = @torrentFileDir + File::SEPARATOR + File.basename(uriPath)
    File.open(path, "w"){ |outfile| outfile.write(f.read) }
  end
  path
end

#loadMagnet(path) ⇒ Object

Load a magnet link in a file



160
161
162
163
164
# File 'lib/quartz_flow/torrent_manager.rb', line 160

def loadMagnet(path)
  raw = nil
  File.open(path, "r"){ |infile| raw = infile.read }
  QuartzTorrent::MagnetURI.new(raw)
end

#removeTorrent(infoHash, deleteFiles) ⇒ Object

Remove the specified torrent. Pass the infoHash as an ascii string, not binary.



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/quartz_flow/torrent_manager.rb', line 200

def removeTorrent(infoHash, deleteFiles)
  infoHashBytes = QuartzTorrent::hexToBytes(infoHash)
  @peerClient.removeTorrent infoHashBytes, deleteFiles

  # Remove torrent from torrent dir
  Dir.new(@torrentFileDir).each do |e|
    if e =~ /\.torrent$/
      path = @torrentFileDir + File::SEPARATOR + e
      metainfo = QuartzTorrent::Metainfo.createFromFile(path)
      if metainfo.infoHash == infoHashBytes
        FileUtils.rm path
        break
      end
    end
  end

  # Remove torrent settings
  helper = SettingsHelper.new
  helper.deleteForOwner infoHash
 
  # Remove magnet file if it exists
  magnetFile = @torrentFileDir + File::SEPARATOR + infoHash + ".magnet"
  FileUtils.rm magnetFile if File.exists?(magnetFile)
end

#simplifiedTorrentData(fields, where) ⇒ Object

Return the torrent data as a hash. If ‘fields` is non-null, then only those fields are returned. If `where` is non-null, it should be a hash of fields for which the values must match to be returned.



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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/quartz_flow/torrent_manager.rb', line 61

def simplifiedTorrentData(fields, where)
  result = {}

  fieldsHash = {}
  fields.each{ |e| fieldsHash[e] = true } if fields

  if where
    w = {}
    where.each do |k,v|
      w[k.to_sym] = v
    end
    where = w
  end

  torrentData.each do |k,d|
    h = d.to_h

    asciiInfoHash = QuartzTorrent::bytesToHex(h[:infoHash])
    h[:infoHash] = asciiInfoHash
    h[:downloadRate] = QuartzTorrent::Formatter.formatSpeed(h[:downloadRate])
    h[:uploadRate] = QuartzTorrent::Formatter.formatSpeed(h[:uploadRate])
    h[:downloadRateDataOnly] = QuartzTorrent::Formatter.formatSpeed(h[:downloadRateDataOnly])
    h[:uploadRateDataOnly] = QuartzTorrent::Formatter.formatSpeed(h[:uploadRateDataOnly])
    h[:dataLength] = QuartzTorrent::Formatter.formatSize(h[:dataLength])
    h[:completedBytes] = QuartzTorrent::Formatter.formatSize(h[:completedBytes])
    # Sort peers
    h[:peers].sort! do |a,b|
      c = (b[:uploadRate].to_i <=> a[:uploadRate].to_i)
      c = (b[:downloadRate].to_i <=> a[:downloadRate].to_i) if c == 0
      c
    end
    # Format peer rates
    h[:peers].each do |p| 
      p[:uploadRate] = QuartzTorrent::Formatter.formatSpeed(p[:uploadRate])
      p[:downloadRate] = QuartzTorrent::Formatter.formatSpeed(p[:downloadRate])
    end
    if h[:info] 
      h[:info][:files].each do |file|
        file[:length] = QuartzTorrent::Formatter.formatSize(file[:length])
      end
    end
    h[:uploadRateLimit] = QuartzTorrent::Formatter.formatSpeed(h[:uploadRateLimit])
    h[:downloadRateLimit] = QuartzTorrent::Formatter.formatSize(h[:downloadRateLimit])
    h[:bytesUploaded] = QuartzTorrent::Formatter.formatSize(h[:bytesUploaded])
    h[:uploadDuration] = QuartzTorrent::Formatter.formatTime(h[:uploadDuration]) if h[:uploadDuration]

    h[:completePieces] = d.completePieceBitfield ? d.completePieceBitfield.countSet : 0
    h[:totalPieces] = d.completePieceBitfield ? d.completePieceBitfield.length : 0

    if where
      matches = true
      where.each do |k,v|
        if h[k] != v
          matches = false
          break
        end
      end
      next if ! matches
    end

    if fields
      newHash = {}
      h.each do |k,v|
        if fieldsHash.has_key?(k)
          newHash[k] = v
        end
      end
      h = newHash
    end

    result[asciiInfoHash] = h
  end
  result
end

#startExistingTorrentsObject

Start torrents that already exist in the torrent file directory



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/quartz_flow/torrent_manager.rb', line 37

def startExistingTorrents
  Dir.new(@torrentFileDir).each do |e|
    path = @torrentFileDir + File::SEPARATOR + e
    if e =~ /\.torrent$/
      puts "Starting .torrent '#{path}'"
      begin
        startTorrentFile(path)
      rescue
        puts "  Starting .torrent '#{path}' failed: #{$!}"
      end
    elsif e =~ /\.magnet$/   
      magnet = loadMagnet(path)
      puts "Starting magnet '#{magnet.raw}'"
      begin
        startMagnet magnet
      rescue
        puts "  Starting magnet '#{magnet.raw}' failed: #{$!}"
      end
    end
  end
end

#startMagnet(magnet) ⇒ Object

Start running the magnet



193
194
195
196
197
# File 'lib/quartz_flow/torrent_manager.rb', line 193

def startMagnet(magnet)
  startTorrent do
    @peerClient.addTorrentByMagnetURI(magnet)
  end
end

#startTorrentFile(path) ⇒ Object

Start running the torrent specified by the .torrent file given in path.



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/quartz_flow/torrent_manager.rb', line 176

def startTorrentFile(path)
  startTorrent do
    begin
      metainfo = QuartzTorrent::Metainfo.createFromFile(path)
      @peerClient.addTorrentByMetainfo(metainfo)
    rescue BEncode::DecodeError
      # Delete the file
      begin
        FileUtils.rm path
      rescue
      end
      raise $!
    end
  end
end

#stopPeerClientObject



31
32
33
34
# File 'lib/quartz_flow/torrent_manager.rb', line 31

def stopPeerClient
  @peerClient.stop
  @peerClientStopped = true
end

#storeMagnet(magnet) ⇒ Object

Store a magnet link in a file in the torrent file directory.



153
154
155
156
157
# File 'lib/quartz_flow/torrent_manager.rb', line 153

def storeMagnet(magnet)
  asciiInfoHash = QuartzTorrent::bytesToHex(magnet.btInfoHash)
  path = @torrentFileDir + File::SEPARATOR + asciiInfoHash + ".magnet"
  File.open(path, "w"){ |outfile| outfile.write(magnet.raw) }
end

#storeUploadedTorrentFile(path, name) ⇒ Object

Store an uploaded .torrent file in the torrent directory. Return the path to the final .torrent file.



168
169
170
171
172
173
# File 'lib/quartz_flow/torrent_manager.rb', line 168

def storeUploadedTorrentFile(path, name)
  name += ".torrent" if name !~ /\.torrent$/
  dpath = @torrentFileDir + File::SEPARATOR + name
  FileUtils.mv path, dpath
  dpath
end

#torrentData(infoHash = nil) ⇒ Object



22
23
24
25
26
27
28
29
# File 'lib/quartz_flow/torrent_manager.rb', line 22

def torrentData(infoHash = nil)
  if (! @cachedTorrentData || Time.new - @cachedAt > @cacheLifetime) && ! @peerClientStopped
    @cachedTorrentData = @peerClient.torrentData
    @cachedAt = Time.new
  end
  
  @cachedTorrentData
end