git ssb

3+

cel / ssb-npm-registry



Commit 62b4a27ac9eb2784595f2f9224d65c5db9ac5bd1

Add new bootstrap page

cel committed on 8/15/2018, 5:55:28 AM
Parent: 939ae205075004b45edf0eb46a9acb675baec4ac

Files changed

index.jschanged
package.jsonchanged
index.jsView
@@ -20,8 +20,13 @@
2020 .replace(/</g, '&lt;')
2121 .replace(/>/g, '&gt;')
2222 }
2323
24 +function idToHex(id) {
25 + var b64 = String(id).replace(/^[%#&]|\.[a-z0-9]*$/g, '')
26 + return new Buffer(b64, 'base64').toString('hex')
27 +}
28 +
2429 function onceify(fn, self) {
2530 var cbs = [], err, data
2631 return function (cb) {
2732 if (fn) {
@@ -469,8 +474,9 @@
469474 }
470475 pathname = m[3]
471476 }
472477 if (pathname === '/') return this.serveHome()
478 + if (pathname === '/bootstrap') return this.serveBootstrap()
473479 if (pathname === '/-/whoami') return this.serveWhoami()
474480 if (pathname === '/-/ping') return this.respond(200, true)
475481 if (pathname === '/-/user/org.couchdb.user:1') return this.serveUser1()
476482 if ((m = /^\/-\/prebuild\/(.*)$/.exec(pathname))) return this.servePrebuild(m[1])
@@ -486,22 +492,141 @@
486492 Req.prototype.respondError = function (status, message) {
487493 this.respond(status, {error: message})
488494 }
489495
496 +Req.prototype.respondErrorStr = function (status, err) {
497 + this.res.writeHead(status, {'content-type': 'text/plain'})
498 + this.res.end(err.stack || err)
499 +}
500 +
490501 Req.prototype.serveHome = function () {
491502 var self = this
492503 self.res.writeHead(200, {'content-type': 'text/html'})
493504 var port = 8044
494505 self.res.end('<!doctype html><html><head><meta charset=utf-8>' +
495506 '<title>' + escapeHTML(pkg.name) + '</title></head><body>' +
496507 '<h1>' + escapeHTML(pkg.name) + '</h1>\n' +
508 + '<p><a href="/bootstrap">Bootstrap</a></p>\n' +
497509 '</body></html>')
498510 }
499511
512 +Req.prototype.getMsgIdForBlobMention = function (blobId, feedId, cb) {
513 + var self = this
514 + pull(
515 + self.server.sbot.links({
516 + source: feedId,
517 + dest: blobId,
518 + rel: 'mentions',
519 + values: true,
520 + }),
521 + pull.filter(function (msg) {
522 + var c = msg && msg.value && msg.value.content
523 + return c.type === 'npm-packages'
524 + }),
525 + pull.collect(function (err, msgs) {
526 + if (err) return cb(err)
527 + if (msgs.length === 0) return cb(new Error('Unable to find message id for mention ' + blobId + ' ' + feedId))
528 + if (msgs.length > 1) console.warn('Warning: multiple messages mentioning blob id ' + blobId + ' ' + feedId)
529 + // TODO: make a smarter decision about which message id to use
530 + cb(null, msgs.pop().key)
531 + })
532 + )
533 +}
534 +
535 +Req.prototype.resolvePkg = function (pkgSpec, cb) {
536 + var m = /(.[^@]*)(?:@(.*))?/.exec(pkgSpec)
537 + if (!m) return cb(new Error('unable to parse spec: \'' + pkgSpec + '\''))
538 + var self = this
539 + var pkgName = m[1]
540 + var spec = m[2] || '*'
541 + var versions = {}
542 + var distTags = {}
543 + pull(
544 + self.getMentions({$prefix: 'npm:' + pkgName + ':'}),
545 + pull.drain(function (mention) {
546 + var data = decodeName(mention.name)
547 + if (!data.version) return
548 + if (data.distTag) {
549 + distTags[data.distTag] = data.version
550 + }
551 + versions[data.version] = {
552 + author: mention.author,
553 + name: pkgName,
554 + version: data.version,
555 + blobId: mention.link
556 + }
557 + }, function (err) {
558 + if (err) return cb(err)
559 + var version = distTags[spec]
560 + || semver.maxSatisfying(Object.keys(versions), spec)
561 + var item = versions[version]
562 + if (!item) return cb(new Error('Version not found: ' + name + '@' + spec))
563 + self.getMsgIdForBlobMention(item.blobId, item.author, function (err, id) {
564 + if (err) return cb(err)
565 + item.msgId = id
566 + cb(null, item)
567 + })
568 + })
569 + )
570 +}
571 +
572 +Req.prototype.resolvePkgs = function (specs, cb) {
573 + var done = multicb({pluck: 1})
574 + var self = this
575 + specs.forEach(function (spec) {
576 + self.resolvePkg(spec, done())
577 + })
578 + done(cb)
579 +}
580 +
581 +Req.prototype.serveBootstrap = function () {
582 + var self = this
583 + var pkgs = self.server.npmConfig.defaultPkgs || ['scuttlebot', 'ssb-npm', 'git-ssb']
584 + var ssbNpmRegistryName = require('./package.json').name
585 + var ssbNpmRegistryVersion = require('./package.json').version
586 + var ssbNpmRegistrySpec = ssbNpmRegistryName + '@^' + ssbNpmRegistryVersion
587 + var done = multicb({pluck: 1, spread: true})
588 + self.resolvePkg(ssbNpmRegistrySpec, done())
589 + self.resolvePkgs(pkgs, done())
590 + done(function (err, ssbNpmRegistryPkgInfo, pkgsInfo) {
591 + if (err) return self.respondErrorStr(500, err.stack || err)
592 + if (!ssbNpmRegistryPkgInfo) return self.respondErrorStr(500, 'Missing ssb-npm-registry package')
593 + var ssbNpmRegistryBlobId = ssbNpmRegistryPkgInfo.blobId
594 + var ssbNpmRegistryBlobHex = idToHex(ssbNpmRegistryBlobId)
595 + var pkgMsgs = pkgsInfo.map(function (info) { return info.msgId })
596 + var globalPkgs = pkgsInfo.map(function (info) {
597 + return info.name + '@' + info.version
598 + }).join(' ')
599 + var npmCmd = 'npm install -g ' + globalPkgs
600 +
601 + var pkgTmpText = '/tmp/' + ssbNpmRegistryName + '.tar.gz'
602 + var host = String(self.req.headers.host).replace(/:[0-9]*$/, '') || self.req.socket.localAddress
603 + var httpHost = /^[^\[]:.*:.*:/.test(host) ? '[' + host + ']' : host
604 + var wsLink = 'http://' + httpHost + ':' + self.server.wsPort + '/'
605 + var tarballLink = wsLink + 'blobs/get/' + ssbNpmRegistryBlobId
606 +
607 + var script =
608 + 'wget \'' + tarballLink + '\' -O ' + pkgTmpText + ' &&\n' +
609 + 'echo ' + ssbNpmRegistryBlobHex + ' ' + pkgTmpText + ' | sha256sum -c &&\n' +
610 + 'mkdir -p ~/.ssb/node_modules && cd ~/.ssb/node_modules &&\n' +
611 + 'tar xzf ' + pkgTmpText + ' &&\n' +
612 + 'mv package ' + ssbNpmRegistryName + ' &&\n' +
613 + ssbNpmRegistryName + '/bootstrap/bin.js --ws-url ' + wsLink + ' \\\n' +
614 + pkgMsgs.map(function (id) {
615 + return ' --branch ' + id + ' \\\n'
616 + }).join('') +
617 + ' -- ' + npmCmd + ' &&\n' +
618 + 'sbot server'
619 +
620 + self.res.writeHead(200, {'Content-type': 'text/plain'})
621 + self.res.end(script)
622 + })
623 +}
624 +
500625 Req.prototype.serveWhoami = function () {
501626 var self = this
502627 self.server.sbot.whoami(function (err, feed) {
503- if (err) return self.respondError(err.stack || err)
628 + if (err) return self.respondError(500, err.stack || err)
504629 self.respond(200, {username: feed.id})
505630 })
506631 }
507632
package.jsonView
@@ -25,8 +25,9 @@
2525 "asyncmemo",
2626 "hashlru",
2727 "multicb",
2828 "pull-cat",
29 + "pull-file",
2930 "pull-hash",
3031 "pull-stream",
3132 "semver",
3233 "stream-to-pull-stream",

Built with git-ssb-web