aboutsummaryrefslogtreecommitdiff
path: root/git-remote-gittorrent
diff options
context:
space:
mode:
authorChris Ball <chris@printf.net>2015-05-27 16:54:10 -0400
committerChris Ball <chris@printf.net>2015-05-27 16:54:10 -0400
commitedf024a982457bc40862a66e4eda910ad4fff5b3 (patch)
treee7a8cc24cf87f0a7b48edf7d72fca8b475c647c9 /git-remote-gittorrent
parent59635ae30cb7982fbfad78aabe3f637b9e8adcae (diff)
Rename! gitswarm->gittorrent
Diffstat (limited to 'git-remote-gittorrent')
-rwxr-xr-xgit-remote-gittorrent132
1 files changed, 132 insertions, 0 deletions
diff --git a/git-remote-gittorrent b/git-remote-gittorrent
new file mode 100755
index 0000000..a8bcb9d
--- /dev/null
+++ b/git-remote-gittorrent
@@ -0,0 +1,132 @@
+#!/usr/bin/env node
+
+var Chalk = require('chalk')
+var DHT = require('bittorrent-dht')
+var exec = require('child_process').exec
+var fs = require('fs')
+var magnet = require('magnet-uri')
+var spawn = require('child_process').spawn
+var Swarm = require('bittorrent-swarm')
+var ut_gittorrent = require('ut_gittorrent')
+var WebTorrent = require('webtorrent')
+
+function die (error) {
+ console.error(error)
+ process.exit(1)
+}
+
+// Gotta enable color manually because stdout isn't a tty.
+var chalk = new Chalk.constructor({enabled: true});
+
+var dht = new DHT({
+ bootstrap: ['three.printf.net:6882']
+})
+
+var url = process.argv[3]
+var matches = url.match(/gittorrent:\/\/([a-f0-9]{40})\/(.*)/)
+if (matches) {
+ var key = matches[1]
+ var reponame = matches[2]
+ dht.on('ready', function () {
+ var val = new Buffer(key, 'hex')
+ dht.get(val, function (err, res) {
+ if (err) {
+ return console.error(err)
+ }
+ var json = res.v.toString()
+ var repos = JSON.parse(json)
+ console.warn('\nMutable key ' + chalk.green(key) + ' returned:\n' + chalk.yellow(json))
+ get_infohash(repos.repositories[reponame].master)
+ })
+ })
+} else {
+ url = url.replace(/^gittorrent:/i, 'git:')
+ exec('git ls-remote ' + url + ' HEAD', function (err, stdout, stderr) {
+ if (err !== null) {
+ die(err)
+ }
+ var lines = stdout.split('\n')
+ if (lines.length !== 2) {
+ die("Didn't get back a single HEAD ref: " + lines)
+ }
+ var line = lines[0].split('\t')
+ var ref = line[0]
+ var head = line[1]
+ if (head !== 'HEAD') {
+ die("Couldn't parse the ref line: " + ref, head)
+ }
+ if (ref.length !== 40) {
+ die('Was expecting a 40-byte sha: ' + ref)
+ }
+ dht.on('ready', function () {
+ get_infohash(ref)
+ })
+ })
+}
+
+function get_infohash (ref) {
+ // We use console.warn (stderr) because git ignores our writes to stdout.
+ console.warn('\nOkay, we want to get: ' + chalk.green(ref) + '\n')
+
+ process.stdin.setEncoding('utf8')
+ process.stdin.on('readable', function () {
+ var chunk = process.stdin.read()
+ if (chunk === 'capabilities\n') {
+ process.stdout.write('fetch\n\n')
+ }
+ if (chunk === 'list\n') {
+ process.stdout.write(ref + ' refs/heads/master\n\n')
+ }
+ })
+ process.stdout.on('error', function () {
+ // stdout was closed
+ })
+
+ var magnetUri = 'magnet:?xt=urn:btih:' + ref
+ var parsed = magnet(magnetUri)
+ dht.lookup(parsed.infoHash)
+
+ dht.on('peer', function (addr, hash, from) {
+ swarm.addPeer(addr)
+ })
+
+ var swarm = new Swarm(parsed.infoHash, 'cafebabecafebabecafecafebabecafebabecafe')
+ swarm.on('wire', function (wire, addr) {
+ console.warn('Adding swarm peer: ' + chalk.green(addr) + '\n')
+ wire.use(ut_gittorrent())
+ wire.ut_gittorrent.on('handshake', function () {
+ wire.ut_gittorrent.ask(parsed.infoHash)
+ })
+ wire.ut_gittorrent.on('receivedTorrent', function (infoHash) {
+ var client = new WebTorrent({
+ dht: {
+ bootstrap: ['three.printf.net:6882']
+ },
+ tracker: false
+ })
+ client.download(infoHash, function (torrent) {
+ console.warn('Downloading git pack with infohash: ' + chalk.green(infoHash) + '\n')
+ torrent.on('done', function (done) {
+ var filename = torrent.storage.path + '/' + torrent.files[0].path
+ var unpack = spawn('git', ['index-pack', '--stdin', '-v', '--fix-thin'])
+ var stream = fs.createReadStream(filename)
+ stream.on('open', function () {
+ stream.pipe(unpack.stdin)
+ })
+ unpack.stderr.pipe(process.stderr)
+ unpack.on('exit', function (code) {
+ var targetdir = process.env['GIT_DIR']
+ var stream = fs.createWriteStream(targetdir + '/refs/heads/master')
+ stream.once('open', function (fd) {
+ stream.write(ref + '\n')
+ stream.end()
+ // These writes are actually necessary for git to finish checkout.
+ process.stdout.write('\n\n')
+ process.exit()
+ })
+ })
+ })
+ })
+ })
+ })
+}