Saturday, July 10, 2010

File Storage for torrent

Writing received data from bittorrent is a bit of a pain. As previously described, a block may end up split into a number of files.
When I first did this, my code for handling a received block was complex. The task of splitting the block into parts relevant for separate files was mixed with the task of writing to files. A tad harder to read and debug.
Now, it's possible to cleanly work out the file parts and write to them. The file storage component is really simple, with just 3 methods: preallocate, insert & extract. I'll post the code tomorrow, for now here's a demo of how it's used with the FileInfo component:


var infoService = Components.
classes["@wikiscraps.com/fileinfo;1"].
getService(Components.interfaces.btIBittorrentFileInfo);
var storageService = Components.
classes["@wikiscraps.com/storage/file;1"].
getService(Components.interfaces.btIBittorrentFileStorage);
var baseFolder = Components.classes["@mozilla.org/file/directory_service;1"].
getService(Components.interfaces.nsIProperties).
get("TmpD", Components.interfaces.nsILocalFile);
baseFolder.appendRelativePath("test");
// Fake block
var fakeBlock = "Baaaaaaaaaaa";
var fakeBlockOffset = 5;
// Fake info
var fakeInfo = {
files : [
{ length : 10, path : ["a"] },
{ length : 10, path : ["b"] },
{ length : 10, path : ["c"] },
{ length : 10, path : ["d"] },
{ length : 10, path : ["e"] }
]
};
// Add piece length later, because it has a space in it's key.
fakeInfo["piece length"] = 6;

// Okay, we've faked the state, now
// let's try to save the block to files!

var fileList = infoService.listFile(fakeInfo);
var fileParts = infoService.blockToFileParts(fakeInfo, fakeBlockOffset, fakeBlock.length);
var completedIndex = 0;
for (var i=0; i < fileParts.length; i++) {
storageService.insert(
baseFolder,
fileList[fileParts[i].index],
fileParts[i].offset,
fakeBlock.substr(completedIndex,fileParts[i].size));
completedIndex += fileParts[i].size;
}

Fairly clear, and much easier to run tests on. A few things ahead bother me. Wrapping the nsIBinaryInputStream to handle the Bittorrent wire protocol should be easy, though I can see foresee that handling the received messages will probably end up with a suboptimal structure. Writing the code to order block requests will be a pain, and I will thankfully separate that into it's own component.

No comments:

Post a Comment