diff options
Diffstat (limited to 'lib/serve.js')
-rw-r--r-- | lib/serve.js | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/lib/serve.js b/lib/serve.js index 8d3eeba..4e8c15d 100644 --- a/lib/serve.js +++ b/lib/serve.js @@ -119,6 +119,7 @@ Serve.prototype.go = function () { else if (data.action === 'publish') self.publishJSON(next) else if (data.action === 'vote') self.publishVote(next) else if (data.action === 'contact') self.publishContact(next) + else if (data.action === 'want-blobs') self.wantBlobs(next) else next() } @@ -172,6 +173,22 @@ Serve.prototype.publishContact = function (cb) { this.publish(content, cb) } +Serve.prototype.wantBlobs = function (cb) { + var self = this + if (!self.data.blob_ids) return cb() + var ids = self.data.blob_ids.split(',') + if (!ids.every(u.isRef)) return cb(new Error('bad blob ids ' + ids.join(','))) + var done = multicb({pluck: 1}) + ids.forEach(function (id) { + self.app.sbot.blobs.want(id, done()) + }) + done(function (err) { + if (err) return cb(err) + // self.note = h('div', 'wanted blobs: ' + ids.join(', ') + '.') + cb() + }) +} + Serve.prototype.publish = function (content, cb) { var self = this var done = multicb({pluck: 1, spread: true}) @@ -257,6 +274,7 @@ Serve.prototype.path = function (url) { case '/emoji': return this.emoji(m[2]) case '/contacts': return this.contacts(m[2]) case '/about': return this.about(m[2]) + case '/git': return this.git(m[2]) } return this.respond(404, 'Not found') } @@ -1063,6 +1081,20 @@ function catchHTMLError() { } } +function catchTextError() { + return function (read) { + var ended + return function (abort, cb) { + if (ended) return cb(ended) + read(abort, function (end, data) { + if (!end || end === true) return cb(end, data) + ended = true + cb(null, end.stack + '\n') + }) + } + } +} + function styles() { return fs.readFileSync(path.join(__dirname, '../static/styles.css'), 'utf8') } @@ -1117,6 +1149,7 @@ Serve.prototype.wrapPage = function (title, searchQ) { 'published ', self.app.render.msgLink(self.publishedMsg, done()) ) : '', + // self.note, content ))) done(cb) @@ -1245,6 +1278,65 @@ Serve.prototype.wrapUserFeed = function (isScrolled, id) { }) } +Serve.prototype.git = function (url) { + var m = /^\/?([^\/]*)\/?(.*)?$/.exec(url) + switch (m[1]) { + case 'commit': return this.gitCommit(m[2]) + case 'tag': return this.gitCommit(m[2]) + case 'raw': return this.gitRaw(m[2]) + default: return this.respond(404, 'Not found') + } +} + +Serve.prototype.gitRaw = function (rev) { + var self = this + if (!/[0-9a-f]{24}/.test(rev)) { + return pull( + pull.once('\'' + rev + '\' is not a git object id'), + self.respondSink(400, {'Content-Type': 'text/plain'}) + ) + } + + var headMsgId = self.query.head + pull( + self.app.git.readObject({ + id: rev, + headMsgId: headMsgId, + }), + catchTextError(), + self.respondSink(200, {'Content-type': 'text/plain'}) + ) +} + +Serve.prototype.gitCommit = function (rev) { + var self = this + if (!/[0-9a-f]{24}/.test(rev)) { + return pull( + ph('div.error', 'rev is not a git object id'), + self.wrapPage('git'), + self.respondSink(400) + ) + } + + self.app.git.getCommit({ + id: rev, + headMsgId: self.query.head, + }, function (err, commit) { + if (err && err.name === 'BlobNotFoundError') + return self.askWantBlobs(err.links) + if (err) return pull( + pull.once(u.renderError(err).outerHTML), + self.wrapPage('git object ' + rev), + self.respondSink(400) + ) + pull( + pull.once(h('pre', self.app.render.linkify(commit.body)).outerHTML), + self.wrapPage('git object ' + rev), + self.respondSink(200) + ) + }) +} + Serve.prototype.wrapPublic = function (opts) { var self = this return u.hyperwrap(function (thread, cb) { @@ -1260,6 +1352,31 @@ Serve.prototype.wrapPublic = function (opts) { }) } +Serve.prototype.askWantBlobs = function (links) { + var self = this + pull( + ph('form', {action: '', method: 'post'}, [ + ph('section', [ + ph('h3', 'Missing blobs'), + ph('p', 'The application needs these blobs to continue:'), + ph('table', links.map(u.toLink).map(function (link) { + if (!u.isRef(link.link)) return + return ph('tr', [ + ph('td', ph('code', link.link)), + ph('td', self.app.render.formatSize(link.size)), + ]) + })), + ph('input', {type: 'hidden', name: 'action', value: 'want-blobs'}), + ph('input', {type: 'hidden', name: 'blob_ids', + value: links.map(u.linkDest).join(',')}), + ph('p', ph('input', {type: 'submit', value: 'Want Blobs'})) + ]) + ]), + self.wrapPage('missing blobs'), + self.respondSink(409) + ) +} + Serve.prototype.wrapPrivate = function (opts) { var self = this return u.hyperwrap(function (thread, cb) { |