Skip to content
This repository was archived by the owner on Mar 10, 2020. It is now read-only.

Commit 524ebfc

Browse files
committed
Merge pull request #224 from xicombd/feat/files-api-symlinks
Add symlink support to feat/files-api
2 parents 038f37e + 2b5472b commit 524ebfc

File tree

9 files changed

+101
-33
lines changed

9 files changed

+101
-33
lines changed

dist/ipfsapi.js

+8-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/ipfsapi.min.js

+6-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ipfs-api",
3-
"version": "2.13.1",
3+
"version": "2.13.2",
44
"description": "A client library for the IPFS API",
55
"main": "src/index.js",
66
"dependencies": {
@@ -37,7 +37,7 @@
3737
"gulp": "^3.9.0",
3838
"gulp-bump": "^1.0.0",
3939
"gulp-eslint": "^2.0.0-rc-3",
40-
"gulp-filter": "^3.0.1",
40+
"gulp-filter": "^4.0.0",
4141
"gulp-git": "^1.6.0",
4242
"gulp-load-plugins": "^1.0.0",
4343
"gulp-mocha": "^2.1.3",

src/get-files-stream.js

+36-12
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ function headers (file) {
1212

1313
if (file.dir) {
1414
header['Content-Type'] = 'application/x-directory'
15+
} else if (file.symlink) {
16+
header['Content-Type'] = 'application/symlink'
1517
} else {
1618
header['Content-Type'] = 'application/octet-stream'
1719
}
@@ -46,20 +48,41 @@ function loadPaths (opts, file) {
4648
follow: followSymlinks
4749
})
4850

49-
return mg.found.map((name) => {
50-
if (mg.cache[name] === 'FILE') {
51-
return {
52-
path: strip(name, file),
53-
dir: false,
54-
content: fs.createReadStream(name)
51+
return mg.found
52+
.map((name) => {
53+
// symlinks
54+
if (mg.symlinks[name] === true) {
55+
return {
56+
path: strip(name, file),
57+
symlink: true,
58+
dir: false,
59+
content: fs.readlinkSync(name)
60+
}
5561
}
56-
} else {
57-
return {
58-
path: strip(name, file),
59-
dir: true
62+
63+
// files
64+
if (mg.cache[name] === 'FILE') {
65+
return {
66+
path: strip(name, file),
67+
symlink: false,
68+
dir: false,
69+
content: fs.createReadStream(name)
70+
}
6071
}
61-
}
62-
})
72+
73+
// directories
74+
if (mg.cache[name] === 'DIR' || mg.cache[name] instanceof Array) {
75+
return {
76+
path: strip(name, file),
77+
symlink: false,
78+
dir: true
79+
}
80+
}
81+
82+
// files inside symlinks and others
83+
return
84+
})
85+
.filter((file) => !!file) // filter out null files
6386
}
6487

6588
return {
@@ -88,6 +111,7 @@ function getFilesStream (files, opts) {
88111

89112
return {
90113
path: '',
114+
symlink: false,
91115
dir: false,
92116
content: file
93117
}

src/request-api.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function onRes (buffer, cb) {
2525

2626
const stream = !!res.headers['x-stream-output']
2727
const chunkedObjects = !!res.headers['x-chunked-output']
28-
const isJson = res.headers['content-type'].indexOf('application/json') === 0
28+
const isJson = res.headers['content-type'] && res.headers['content-type'].indexOf('application/json') === 0
2929

3030
if (res.statusCode >= 400 || !res.statusCode) {
3131
const error = new Error(`Server responded with ${res.statusCode}`)

test/api/add.spec.js

+26-2
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,37 @@ describe('.add', () => {
7878
})
7979
})
8080

81-
it('add a nested dir', (done) => {
81+
it('add a nested dir following symlinks', (done) => {
8282
apiClients['a'].add(path.join(__dirname, '/../test-folder'), { recursive: true }, (err, res) => {
8383
if (isNode) {
8484
expect(err).to.not.exist
8585

8686
const added = res[res.length - 1]
87-
expect(added).to.have.property('Hash', 'QmTDH2RXGn8XyDAo9YyfbZAUXwL1FCr44YJCN9HBZmL9Gj')
87+
expect(added).to.have.property('Hash', 'QmRNjDeKStKGTQXnJ2NFqeQ9oW23WcpbmvCVrpDHgDg3T6')
88+
89+
// check that the symlink was replaced by the target file
90+
const linkPath = 'test-folder/hello-link'
91+
const filePath = 'test-folder/files/hello.txt'
92+
const linkHash = res.filter((e) => e.Name === linkPath)[0].Hash
93+
const fileHash = res.filter((e) => e.Name === filePath)[0].Hash
94+
expect(linkHash).to.equal(fileHash)
95+
96+
done()
97+
} else {
98+
expect(err.message).to.be.equal('Recursive uploads are not supported in the browser')
99+
done()
100+
}
101+
})
102+
})
103+
104+
it('add a nested dir without following symlinks', (done) => {
105+
apiClients['a'].add(path.join(__dirname, '/../test-folder'), { recursive: true, followSymlinks: false }, (err, res) => {
106+
if (isNode) {
107+
expect(err).to.not.exist
108+
109+
const added = res[res.length - 1]
110+
// same hash as the result from the cli (ipfs add test/test-folder -r)
111+
expect(added).to.have.property('Hash', 'QmRArDYd8Rk7Zb7K2699KqmQM1uUoejn1chtEAcqkvjzGg')
88112
done()
89113
} else {
90114
expect(err.message).to.be.equal('Recursive uploads are not supported in the browser')

test/api/ls.spec.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ describe('ls', function () {
2727
it('should correctly handle a nonexisting path', function (done) {
2828
if (!isNode) return done()
2929

30-
apiClients['a'].ls('QmTDH2RXGn8XyDAo9YyfbZAUXwL1FCr44YJCN9HBZmL9Gj/folder_that_isnt_there', (err, res) => {
30+
apiClients['a'].ls('QmRNjDeKStKGTQXnJ2NFqeQ9oW23WcpbmvCVrpDHgDg3T6/folder_that_isnt_there', (err, res) => {
3131
expect(err).to.exist
3232
expect(res).to.not.exist
3333
done()
@@ -56,7 +56,7 @@ describe('ls', function () {
5656
it('should correctly handle a nonexisting path', () => {
5757
if (!isNode) return
5858

59-
return apiClients['a'].ls('QmTDH2RXGn8XyDAo9YyfbZAUXwL1FCr44YJCN9HBZmL9Gj/folder_that_isnt_there')
59+
return apiClients['a'].ls('QmRNjDeKStKGTQXnJ2NFqeQ9oW23WcpbmvCVrpDHgDg3T6/folder_that_isnt_there')
6060
.catch((err) => {
6161
expect(err).to.exist
6262
})

test/request-api.spec.js

+19
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,24 @@ describe('ipfsAPI request tests', () => {
4141
protocol: 'http'
4242
}).id(noop)
4343
})
44+
45+
it('does not crash if no content-type header is provided', (done) => {
46+
if (!isNode) {
47+
return done()
48+
}
49+
50+
// go-ipfs always (currently) adds a content-type header, even if no content is present,
51+
// the standard behaviour for an http-api is to omit this header if no content is present
52+
const server = require('http').createServer((req, res) => {
53+
res.writeHead(200)
54+
res.end()
55+
}).listen(6001, () => {
56+
ipfsAPI('/ip4/127.0.0.1/tcp/6001')
57+
.config.replace('test/r-config.json', (err) => {
58+
expect(err).to.not.exist
59+
server.close(done)
60+
})
61+
})
62+
})
4463
})
4564
})

test/test-folder/hello-link

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
files/hello.txt

0 commit comments

Comments
 (0)