aboutsummaryrefslogtreecommitdiff
path: root/gitswarmd
blob: e9926c86d6a606a52f6bfab1acd75f62f460a02f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/env node

var createTorrent = require('create-torrent')
var DHT = require('bittorrent-dht')
var glob = require('glob')
var fs = require('fs')
var net = require('net')
var Protocol = require('bittorrent-protocol')
var spawn = require('child_process').spawn
var ut_gitswarm = require('ut_gitswarm')
var ut_metadata = require('ut_metadata')
var WebTorrent = require('webtorrent')

function die (error) {
  console.error(error)
  process.exit(1)
}

var dht = new DHT({
  bootstrap: ['three.printf.net:6881']
})
dht.listen(6882)

var announcedRefs = {}

dht.on('ready', function () {
  // Spider all */.git dirs and announce all refs.
  var repos = glob.sync('*/.git/git-daemon-export-ok')
  repos.forEach(function (repo) {
    console.log('in repo ' + repo)
    repo = repo.replace(/git-daemon-export-ok$/, '')
    console.log(repo)
    var upload = spawn('git-upload-pack', ['--strict', repo])
    upload.stdout.on('data', function (line) {
      var lines = line.toString().split('\n')
      lines.forEach(function (line) {
        var arr = line.toString().split(' ')
        if (arr.length === 2) {
          var sha = arr[0].toString()
          // First four chars are git-upload-pack's length-of-line metadata.
          sha = sha.substring(4)
          var ref = arr[1].toString()
          if (ref.search(/^refs\/heads\//) !== -1 || ref.search(/^refs\/remotes\//) !== -1) {
            console.log('Announcing ' + sha + ' for ref ' + ref + ' on repo ' + repo)
            announcedRefs[sha] = repo
            console.log(announcedRefs)
            dht.announce(sha, 30000, function (err) {
              if (err !== null) {
                console.log('Announced ' + sha)
              }
            })
          }
        }
      })
    })
    upload.stdout.on('end', function () {
      console.log('end')
    })
    upload.on('exit', function (code) {
      if (code !== 0) {
        die('Failed: ' + code)
      }
    })
  })

  net.createServer(function (socket) {
    var wire = new Protocol()
    wire.use(ut_gitswarm())
    wire.use(ut_metadata())
    socket.pipe(wire).pipe(socket)
    wire.on('handshake', function (infoHash, peerId) {
      console.log('Received handshake for ' + infoHash)
      wire.handshake(new Buffer(infoHash), new Buffer(peerId))
    })
    wire.ut_gitswarm.on('generatePack', function (sha) {
      console.error('calling git pack-objects')
      var filename = sha + '.pack'
      var stream = fs.createWriteStream(filename)
      if (!announcedRefs[sha]) {
        console.error('Asked for an unknown sha!')
      }
      var directory = announcedRefs[sha]
      var pack = spawn('git', ['pack-objects', '--revs', '--thin', '--stdout', '--delta-base-offset'], {cwd: directory})
      pack.on('close', function (code) {
        if (code !== 0) {
          console.error('git pack-objects process exited with code ' + code)
        } else {
          console.error('Finished writing ' + filename)
          var webtorrent = new WebTorrent({
            dht: {bootstrap: ['three.printf.net:6882']},
            tracker: false
          })
          webtorrent.seed(filename, function onTorrent (torrent) {
            console.error(torrent.infoHash)
            wire.ut_gitswarm.sendTorrent(torrent.infoHash)
          })
        }
      })
      pack.stdout.pipe(stream)
      pack.stderr.on('data', function (data) {
        console.error(data.toString())
      })
      pack.on('exit', function () {
        console.log('exited')
      })
      pack.stdin.write(sha + '\n')
      pack.stdin.write('--not\n\n')
    })
  }).listen(30000)
})