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

Commit 695a536

Browse files
committed
Merge pull request #227 from ipfs/cat/http
WIP http cat
2 parents 217574f + 7ad4396 commit 695a536

File tree

14 files changed

+228
-31
lines changed

14 files changed

+228
-31
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
"ipfs-merkle-dag": "^0.6.0",
7171
"ipfs-multipart": "^0.1.0",
7272
"ipfs-repo": "^0.8.0",
73-
"ipfs-unixfs-engine": "^0.6.1",
73+
"ipfs-unixfs-engine": "^0.8.0",
7474
"joi": "^8.0.5",
7575
"libp2p-ipfs": "^0.5.0",
7676
"libp2p-ipfs-browser": "^0.4.0",
@@ -122,4 +122,4 @@
122122
"kumavis <[email protected]>",
123123
"nginnever <[email protected]>"
124124
]
125-
}
125+
}

src/cli/commands/cat.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/cli/commands/files/cat.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,22 @@ module.exports = Command.extend({
2222
if (err) {
2323
throw err
2424
}
25+
if (utils.isDaemonOn()) {
26+
ipfs.cat(path, (err, res) => {
27+
if (err) {
28+
throw err
29+
}
30+
console.log(res.toString())
31+
})
32+
return
33+
}
2534
ipfs.files.cat(path, (err, res) => {
2635
if (err) {
2736
throw (err)
2837
}
29-
if (res) {
30-
res.on('file', (data) => {
31-
data.stream.pipe(process.stdout)
32-
})
33-
}
38+
res.on('data', (data) => {
39+
data.stream.pipe(process.stdout)
40+
})
3441
})
3542
})
3643
}

src/cli/commands/files/get.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ module.exports = Command.extend({
8484
if (err) {
8585
throw err
8686
}
87-
result.on('file', fileHandler(result, dir))
87+
result.on('data', fileHandler(result, dir))
8888
})
8989
})
9090
}

src/cli/commands/get.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/core/ipfs/files.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ module.exports = function files (self) {
4444
if (data.type === 'directory') {
4545
callback('This dag node is a directory', null)
4646
} else {
47-
const exportEvent = Exporter(hash, self._dagS)
48-
callback(null, exportEvent)
47+
const exportStream = Exporter(hash, self._dagS)
48+
callback(null, exportStream)
4949
}
5050
})
5151
},

src/http-api/resources/files.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
'use strict'
2+
3+
const bs58 = require('bs58')
4+
const debug = require('debug')
5+
const log = debug('http-api:files')
6+
log.error = debug('http-api:files:error')
7+
8+
exports = module.exports
9+
10+
// common pre request handler that parses the args and returns `key` which is assigned to `request.pre.args`
11+
exports.parseKey = (request, reply) => {
12+
if (!request.query.arg) {
13+
return reply("Argument 'key' is required").code(400).takeover()
14+
}
15+
16+
try {
17+
return reply({
18+
key: new Buffer(bs58.decode(request.query.arg))
19+
})
20+
} catch (err) {
21+
log.error(err)
22+
return reply({
23+
Message: 'invalid ipfs ref path',
24+
Code: 0
25+
}).code(500).takeover()
26+
}
27+
}
28+
29+
exports.cat = {
30+
// uses common parseKey method that returns a `key`
31+
parseArgs: exports.parseKey,
32+
33+
// main route handler which is called after the above `parseArgs`, but only if the args were valid
34+
handler: (request, reply) => {
35+
const key = request.pre.args.key
36+
37+
request.server.app.ipfs.files.cat(key, (err, stream) => {
38+
if (err) {
39+
log.error(err)
40+
return reply({
41+
Message: 'Failed to cat file: ' + err,
42+
Code: 0
43+
}).code(500)
44+
}
45+
stream.on('data', (data) => {
46+
return reply(data.stream)
47+
})
48+
})
49+
}
50+
}

src/http-api/resources/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ exports.config = require('./config')
99
exports.block = require('./block')
1010
exports.swarm = require('./swarm')
1111
exports.bitswap = require('./bitswap')
12+
exports.files = require('./files')

src/http-api/routes/files.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
'use strict'
2+
3+
const resources = require('./../resources')
4+
5+
module.exports = (server) => {
6+
const api = server.select('API')
7+
8+
api.route({
9+
method: '*',
10+
path: '/api/v0/cat',
11+
config: {
12+
pre: [
13+
{ method: resources.files.cat.parseArgs, assign: 'args' }
14+
],
15+
handler: resources.files.cat.handler
16+
}
17+
})
18+
}

src/http-api/routes/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ module.exports = (server) => {
1010
require('./config')(server)
1111
require('./swarm')(server)
1212
require('./bitswap')(server)
13+
require('./files')(server)
1314
}

test/cli-tests/test-commands.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ describe('commands', () => {
1010
.run((err, stdout, exitcode) => {
1111
expect(err).to.not.exist
1212
expect(exitcode).to.equal(0)
13-
expect(stdout.length).to.equal(50)
13+
expect(stdout.length).to.equal(48)
1414
done()
1515
})
1616
})

test/cli-tests/test-files.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/* eslint-env mocha */
2+
'use strict'
3+
4+
const expect = require('chai').expect
5+
const nexpect = require('nexpect')
6+
const HttpAPI = require('../../src/http-api')
7+
const repoPath = require('./index').repoPath
8+
const _ = require('lodash')
9+
10+
describe('files', () => {
11+
const env = _.clone(process.env)
12+
env.IPFS_PATH = repoPath
13+
14+
describe('api offline', () => {
15+
it('cat', (done) => {
16+
nexpect.spawn('node', [process.cwd() + '/src/cli/bin.js', 'files', 'cat', 'QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o'], {env})
17+
.run((err, stdout, exitcode) => {
18+
expect(err).to.not.exist
19+
expect(exitcode).to.equal(0)
20+
done()
21+
})
22+
})
23+
})
24+
25+
describe('api running', () => {
26+
let httpAPI
27+
28+
before((done) => {
29+
httpAPI = new HttpAPI(repoPath)
30+
httpAPI.start((err) => {
31+
expect(err).to.not.exist
32+
done()
33+
})
34+
})
35+
36+
after((done) => {
37+
httpAPI.stop((err) => {
38+
expect(err).to.not.exist
39+
done()
40+
})
41+
})
42+
43+
it('cat', (done) => {
44+
nexpect.spawn('node', [process.cwd() + '/src/cli/bin.js', 'files', 'cat', 'QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o'], {env})
45+
.run((err, stdout, exitcode) => {
46+
expect(err).to.not.exist
47+
expect(exitcode).to.equal(0)
48+
done()
49+
})
50+
})
51+
})
52+
})

test/core-tests/test-files.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ describe('files', () => {
3737
const hash = 'QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o'
3838
ipfs.files.cat(hash, (err, res) => {
3939
expect(err).to.not.exist
40-
res.on('file', (data) => {
40+
res.on('data', (data) => {
4141
data.stream.pipe(bl((err, bldata) => {
4242
expect(err).to.not.exist
4343
expect(bldata.toString()).to.equal('hello world\n')
@@ -52,7 +52,7 @@ describe('files', () => {
5252
const hash = 'QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o'
5353
ipfs.files.get(hash, (err, res) => {
5454
expect(err).to.not.exist
55-
res.on('file', (data) => {
55+
res.on('data', (data) => {
5656
data.stream.pipe(bl((err, bldata) => {
5757
expect(err).to.not.exist
5858
expect(bldata.toString()).to.equal('hello world\n')

test/http-api-tests/test-files.js

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/* eslint-env mocha */
2+
'use strict'
3+
4+
const expect = require('chai').expect
5+
const APIctl = require('ipfs-api')
6+
7+
module.exports = (httpAPI) => {
8+
describe('files', () => {
9+
describe('api', () => {
10+
let api
11+
12+
it('api', () => {
13+
api = httpAPI.server.select('API')
14+
})
15+
16+
describe('/files/cat', () => {
17+
it('returns 400 for request without argument', (done) => {
18+
api.inject({
19+
method: 'GET',
20+
url: '/api/v0/cat'
21+
}, (res) => {
22+
expect(res.statusCode).to.equal(400)
23+
expect(res.result).to.be.a('string')
24+
done()
25+
})
26+
})
27+
28+
it('returns 500 for request with invalid argument', (done) => {
29+
api.inject({
30+
method: 'GET',
31+
url: '/api/v0/cat?arg=invalid'
32+
}, (res) => {
33+
expect(res.statusCode).to.equal(500)
34+
expect(res.result.Message).to.be.a('string')
35+
done()
36+
})
37+
})
38+
39+
it('returns a buffer', (done) => {
40+
api.inject({
41+
method: 'GET',
42+
url: '/api/v0/cat?arg=QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o'
43+
}, (res) => {
44+
expect(res.statusCode).to.equal(200)
45+
expect(res.rawPayload).to.deep.equal(new Buffer('hello world' + '\n'))
46+
expect(res.payload).to.equal('hello world' + '\n')
47+
done()
48+
})
49+
})
50+
})
51+
})
52+
53+
describe('using js-ipfs-api', () => {
54+
var ctl
55+
56+
it('start IPFS API ctl', (done) => {
57+
ctl = APIctl('/ip4/127.0.0.1/tcp/6001')
58+
done()
59+
})
60+
61+
describe('ipfs.cat', () => {
62+
it('returns error for request without argument', (done) => {
63+
ctl.cat(null, (err, result) => {
64+
expect(err).to.exist
65+
done()
66+
})
67+
})
68+
69+
it('returns error for request with invalid argument', (done) => {
70+
ctl.cat('invalid', (err, result) => {
71+
expect(err).to.exist
72+
done()
73+
})
74+
})
75+
76+
it('returns a buffer', (done) => {
77+
ctl.cat('QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o', (err, result) => {
78+
expect(err).to.not.exist
79+
expect(result).to.deep.equal(new Buffer('hello world' + '\n'))
80+
done()
81+
})
82+
})
83+
})
84+
})
85+
})
86+
}

0 commit comments

Comments
 (0)