Commit 62b4a27ac9eb2784595f2f9224d65c5db9ac5bd1
Add new bootstrap page
cel committed on 8/15/2018, 5:55:28 AMParent: 939ae205075004b45edf0eb46a9acb675baec4ac
Files changed
index.js | changed |
package.json | changed |
index.js | |||
---|---|---|---|
@@ -20,8 +20,13 @@ | |||
20 | 20 … | .replace(/</g, '<') | |
21 | 21 … | .replace(/>/g, '>') | |
22 | 22 … | } | |
23 | 23 … | ||
24 … | +function idToHex(id) { | ||
25 … | + var b64 = String(id).replace(/^[%#&]|\.[a-z0-9]*$/g, '') | ||
26 … | + return new Buffer(b64, 'base64').toString('hex') | ||
27 … | +} | ||
28 … | + | ||
24 | 29 … | function onceify(fn, self) { | |
25 | 30 … | var cbs = [], err, data | |
26 | 31 … | return function (cb) { | |
27 | 32 … | if (fn) { | |
@@ -469,8 +474,9 @@ | |||
469 | 474 … | } | |
470 | 475 … | pathname = m[3] | |
471 | 476 … | } | |
472 | 477 … | if (pathname === '/') return this.serveHome() | |
478 … | + if (pathname === '/bootstrap') return this.serveBootstrap() | ||
473 | 479 … | if (pathname === '/-/whoami') return this.serveWhoami() | |
474 | 480 … | if (pathname === '/-/ping') return this.respond(200, true) | |
475 | 481 … | if (pathname === '/-/user/org.couchdb.user:1') return this.serveUser1() | |
476 | 482 … | if ((m = /^\/-\/prebuild\/(.*)$/.exec(pathname))) return this.servePrebuild(m[1]) | |
@@ -486,22 +492,141 @@ | |||
486 | 492 … | Req.prototype.respondError = function (status, message) { | |
487 | 493 … | this.respond(status, {error: message}) | |
488 | 494 … | } | |
489 | 495 … | ||
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 … | + | ||
490 | 501 … | Req.prototype.serveHome = function () { | |
491 | 502 … | var self = this | |
492 | 503 … | self.res.writeHead(200, {'content-type': 'text/html'}) | |
493 | 504 … | var port = 8044 | |
494 | 505 … | self.res.end('<!doctype html><html><head><meta charset=utf-8>' + | |
495 | 506 … | '<title>' + escapeHTML(pkg.name) + '</title></head><body>' + | |
496 | 507 … | '<h1>' + escapeHTML(pkg.name) + '</h1>\n' + | |
508 … | + '<p><a href="/bootstrap">Bootstrap</a></p>\n' + | ||
497 | 509 … | '</body></html>') | |
498 | 510 … | } | |
499 | 511 … | ||
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 … | + | ||
500 | 625 … | Req.prototype.serveWhoami = function () { | |
501 | 626 … | var self = this | |
502 | 627 … | 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) | ||
504 | 629 … | self.respond(200, {username: feed.id}) | |
505 | 630 … | }) | |
506 | 631 … | } | |
507 | 632 … |
Built with git-ssb-web