Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

feat: add gateway route to daemon #968

Merged
merged 5 commits into from
Sep 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ dependencies:
pre:
- google-chrome --version
- curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- for v in $(curl http://archive.ubuntu.com/ubuntu/pool/main/n/nss/ | grep "href=" | grep "libnss3.*deb\"" -o | grep -o "libnss3.*deb" | grep "3.28" | grep "14.04"); do curl -L -o $v http://archive.ubuntu.com/ubuntu/pool/main/n/nss/$v; done && rm libnss3-tools*_i386.deb libnss3-dev*_i386.deb
- sudo dpkg -i google-chrome.deb || true
- sudo dpkg -i libnss3*.deb || true
- sudo apt-get update
- sudo apt-get install -f || true
- sudo dpkg -i libnss3*.deb
- sudo apt-get install -f
- sudo apt-get install --only-upgrade lsb-base
- sudo dpkg -i google-chrome.deb
Expand Down
2 changes: 1 addition & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const gulp = require('gulp')
const parallel = require('async/parallel')
const series = require('async/series')
const createTempRepo = require('./test/utils/create-repo-nodejs.js')
const HTTPAPI = require('./src/http-api')
const HTTPAPI = require('./src/http')
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense to call this http module now daemon

Copy link
Contributor

@ya7ya ya7ya Aug 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@diasdavid Yeah it does, but in go-ipfs it's http , so should we stick to the reference implementation ? I don't mind the rename though
go-ipfs

Edit: added link.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep http then :)

const leftPad = require('left-pad')

let nodes = []
Expand Down
24 changes: 14 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"test:unit:node": "gulp test:node",
"test:unit:node:core": "TEST=core npm run test:unit:node",
"test:unit:node:http": "TEST=http npm run test:unit:node",
"test:unit:node:gateway": "TEST=gateway npm run test:unit:node",
"test:unit:node:cli": "TEST=cli npm run test:unit:node",
"test:unit:browser": "gulp test:browser",
"test:interop": "npm run test:interop:node",
Expand Down Expand Up @@ -92,31 +93,33 @@
"async": "^2.5.0",
"bl": "^1.2.1",
"boom": "^5.2.0",
"cids": "~0.5.1",
"debug": "^3.0.1",
"cids": "^0.5.1",
"file-type": "^6.1.0",
"filesize": "^3.5.10",
"fsm-event": "^2.1.0",
"glob": "^7.1.2",
"hapi": "^16.5.2",
"hapi-set-header": "^1.0.2",
"hoek": "^4.2.0",
"ipfs-api": "^14.3.3",
"ipfs-api": "^14.3.4",
"ipfs-bitswap": "~0.17.2",
"ipfs-block": "~0.6.0",
"ipfs-block-service": "~0.12.0",
"ipfs-multipart": "~0.1.0",
"ipfs-repo": "~0.17.0",
"ipfs-unixfs": "~0.1.13",
"ipfs-unixfs-engine": "~0.22.3",
"ipfs-unixfs-engine": "~0.22.4",
"ipld-resolver": "~0.13.2",
"is-ipfs": "^0.3.0",
"is-stream": "^1.1.0",
"joi": "^10.6.0",
"libp2p": "~0.12.3",
"libp2p-floodsub": "~0.11.0",
"libp2p-kad-dht": "~0.5.0",
"libp2p-mdns": "~0.9.0",
"libp2p": "~0.12.4",
"libp2p-floodsub": "~0.11.1",
"libp2p-kad-dht": "~0.5.1",
"libp2p-mdns": "~0.9.1",
"libp2p-multiplex": "~0.5.0",
"libp2p-railing": "~0.7.0",
"libp2p-railing": "~0.7.1",
"libp2p-secio": "~0.8.1",
"libp2p-tcp": "~0.11.0",
"libp2p-webrtc-star": "~0.13.1",
Expand All @@ -126,13 +129,14 @@
"lodash.sortby": "^4.7.0",
"lodash.values": "^4.3.0",
"mafmt": "^3.0.1",
"mime-types": "^2.1.17",
"mkdirp": "~0.5.1",
"multiaddr": "^3.0.1",
"multihashes": "~0.4.9",
"once": "^1.4.0",
"path-exists": "^3.0.0",
"peer-book": "~0.5.0",
"peer-id": "~0.10.0",
"peer-book": "~0.5.1",
"peer-id": "~0.10.1",
"peer-info": "~0.11.0",
"promisify-es6": "^1.0.3",
"pull-file": "^1.0.0",
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/daemon.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const HttpAPI = require('../../http-api')
const HttpAPI = require('../../http')
const utils = require('../utils')
const print = utils.print

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
86 changes: 86 additions & 0 deletions src/http/gateway/dir-view/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
'use strict'

const filesize = require('filesize')

const mainStyle = require('./style')
const pathUtil = require('../utils/path')

function getParentDirectoryURL (originalParts) {
const parts = originalParts.slice()

if (parts.length > 1) {
parts.pop()
}

return [ '', 'ipfs' ].concat(parts).join('/')
}

function buildFilesList (path, links) {
const rows = links.map((link) => {
let row = [
`<div class="ipfs-icon ipfs-_blank">&nbsp;</div>`,
`<a href="${pathUtil.joinURLParts(path, link.name)}">${link.name}</a>`,
filesize(link.size)
]

row = row.map((cell) => `<td>${cell}</td>`).join('')

return `<tr>${row}</tr>`
})

return rows.join('')
}

function buildTable (path, links) {
const parts = pathUtil.splitPath(path)
const parentDirectoryURL = getParentDirectoryURL(parts)

return `
<table class="table table-striped">
<tbody>
<tr>
<td class="narrow">
<div class="ipfs-icon ipfs-_blank">&nbsp;</div>
</td>
<td class="padding">
<a href="${parentDirectoryURL}">..</a>
</td>
<td></td>
</tr>
${buildFilesList(path, links)}
</tbody>
</table>
`
}

function render (path, links) {
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>${path}</title>
<style>${mainStyle}</style>
</head>
<body>
<div id="header" class="row">
<div class="col-xs-2">
<div id="logo" class="ipfs-logo"></div>
</div>
</div>
<br>
<div class="col-xs-12">
<div class="panel panel-default">
<div class="panel-heading">
<strong>Index of ${path}</strong>
</div>
${buildTable(path, links)}
</div>
</div>
</body>
</html>
`
}

exports = module.exports
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems like a bad start to do htm templating using string manipulation. can we use an actual templating engine please?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to be only three "templates" here for the gateway, would be overkill to include a entire template engine for this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like a bad precedent, it starts with three templates, but always grows, so I would rather have something setup properly from the start

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @dignifiedquire, worst case scenario, if complexity doesn't grow and we don't need those templates, we can easily remove them and switch back to this style, which is better than having to rework a bunch of ad-hoc templates ;)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if complexity doesn't grow and we don't need those templates, we can easily remove them and switch back to this style

That's planning for something we don't know, rather than going with a simple solution that works now and migrate to something more complex once we really have the need for it. Three templates (in my mind) does not justify including a template engine.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be achieved as a separate PR

exports.render = render
16 changes: 16 additions & 0 deletions src/http/gateway/dir-view/style.js

Large diffs are not rendered by default.

110 changes: 110 additions & 0 deletions src/http/gateway/resolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
'use strict'

const mh = require('multihashes')
const promisify = require('promisify-es6')
const reduce = require('async/reduce')
const CID = require('cids')
const Unixfs = require('ipfs-unixfs')
const debug = require('debug')
const log = debug('jsipfs:http-gateway:resolver')
log.error = debug('jsipfs:http-gateway:resolver:error')

const dirView = require('./dir-view')
const pathUtil = require('./utils/path')

function getIndexFiles (links) {
const INDEX_HTML_FILES = [
'index.html',
'index.htm',
'index.shtml'
]

return links.filter((link) => INDEX_HTML_FILES.indexOf(link.name) !== -1)
}

const resolveDirectory = promisify((ipfs, path, multihash, callback) => {
mh.validate(mh.fromB58String(multihash))

ipfs.object.get(multihash, { enc: 'base58' }, (err, dagNode) => {
if (err) { return callback(err) }

const indexFiles = getIndexFiles(dagNode.links)

if (indexFiles.length > 0) {
return callback(null, indexFiles)
}

return callback(null, dirView.render(path, dagNode.links))
})
})

const resolveMultihash = promisify((ipfs, path, callback) => {
const parts = pathUtil.splitPath(path)
let firstMultihash = parts.shift()
let currentCid

reduce(parts, firstMultihash, (memo, item, next) => {
try {
currentCid = new CID(mh.fromB58String(memo))
} catch (err) {
return next(err)
}

log('memo: ', memo)
log('item: ', item)

ipfs.dag.get(currentCid, (err, result) => {
if (err) { return next(err) }

let dagNode = result.value
// find multihash of requested named-file in current dagNode's links
let multihashOfNextFile
let nextFileName = item

const links = dagNode.links

for (let link of links) {
if (link.name === nextFileName) {
// found multihash of requested named-file
multihashOfNextFile = mh.toB58String(link.multihash)
log('found multihash: ', multihashOfNextFile)
break
}
}

if (!multihashOfNextFile) {
return next(new Error(`no link named "${nextFileName}" under ${memo}`))
}

next(null, multihashOfNextFile)
})
}, (err, result) => {
if (err) { return callback(err) }

let cid
try {
cid = new CID(mh.fromB58String(result))
} catch (err) {
return callback(err)
}

ipfs.dag.get(cid, (err, dagResult) => {
if (err) return callback(err)

let dagDataObj = Unixfs.unmarshal(dagResult.value.data)
if (dagDataObj.type === 'directory') {
let isDirErr = new Error('This dag node is a directory')
// add memo (last multihash) as a fileName so it can be used by resolveDirectory
isDirErr.fileName = result
return callback(isDirErr)
}

callback(null, { multihash: result })
})
})
})

module.exports = {
resolveDirectory: resolveDirectory,
resolveMultihash: resolveMultihash
}
Loading