|
2 | 2 |
|
3 | 3 | const mh = require('multihashes') |
4 | 4 | const promisify = require('promisify-es6') |
5 | | -const reduce = require('async/reduce') |
6 | 5 | const CID = require('cids') |
7 | | -const Unixfs = require('ipfs-unixfs') |
8 | 6 | const debug = require('debug') |
| 7 | +const tryEach = require('async/tryEach') |
| 8 | +const waterfall = require('async/waterfall') |
9 | 9 | const log = debug('jsipfs:http:response:resolver') |
10 | 10 | log.error = debug('jsipfs:http:response:resolver:error') |
11 | | - |
12 | 11 | const dirView = require('./dir-view') |
13 | | -const pathUtil = require('./utils/path') |
14 | 12 |
|
15 | | -function getIndexFiles (links) { |
16 | | - const INDEX_HTML_FILES = [ |
17 | | - 'index.html', |
18 | | - 'index.htm', |
19 | | - 'index.shtml' |
20 | | - ] |
21 | | - // directory |
22 | | - let indexes = links.filter((link) => INDEX_HTML_FILES.indexOf(link.name) !== -1) |
23 | | - if (indexes.length) { |
24 | | - return indexes |
25 | | - } |
26 | | - // hamt-sharded-directory uses a 2 char prefix |
27 | | - return links.filter((link) => { |
28 | | - return link.name.length > 2 && INDEX_HTML_FILES.indexOf(link.name.substring(2)) !== -1 |
29 | | - }) |
30 | | -} |
| 13 | +const INDEX_HTML_FILES = [ |
| 14 | + 'index.html', |
| 15 | + 'index.htm', |
| 16 | + 'index.shtml' |
| 17 | +] |
31 | 18 |
|
32 | 19 | const directory = promisify((ipfs, path, cid, callback) => { |
33 | | - cid = new CID(cid) |
34 | | - |
35 | | - ipfs.object.get(cid.buffer, (err, dagNode) => { |
36 | | - if (err) { |
37 | | - return callback(err) |
| 20 | + // Test if it is a Website |
| 21 | + return tryEach(INDEX_HTML_FILES.map(file => { |
| 22 | + return (cb) => { |
| 23 | + waterfall([ |
| 24 | + (cb) => ipfs.files.stat(`${path}/${file}`, cb), |
| 25 | + (_, cb) => cb(null, { name: file }) |
| 26 | + ], cb) |
38 | 27 | } |
| 28 | + }), (err, res) => { |
| 29 | + if (err) { |
| 30 | + if (err.message.includes('does not exist')) { |
| 31 | + // not a website, just show a directory listing |
| 32 | + return ipfs.dag.get(cid, (err, result) => { |
| 33 | + if (err) { |
| 34 | + return callback(err) |
| 35 | + } |
39 | 36 |
|
40 | | - // Test if it is a Website |
41 | | - const indexFiles = getIndexFiles(dagNode.links) |
| 37 | + return callback(null, dirView.render(path, result.value.links)) |
| 38 | + }) |
| 39 | + } |
42 | 40 |
|
43 | | - if (indexFiles.length) { |
44 | | - return callback(null, indexFiles) |
| 41 | + return callback(err) |
45 | 42 | } |
46 | 43 |
|
47 | | - return callback(null, dirView.render(path, dagNode.links)) |
| 44 | + callback(err, [ res ]) |
48 | 45 | }) |
49 | 46 | }) |
50 | 47 |
|
51 | 48 | const cid = promisify((ipfs, path, callback) => { |
52 | | - const parts = pathUtil.cidArray(path) |
53 | | - let firstCid = parts.shift() |
54 | | - let currentCid |
55 | | - |
56 | | - // TODO: replace below with ipfs.resolve(path, {recursive: true}) |
57 | | - // (requires changes to js-ipfs/js-ipfs-api) |
58 | | - |
59 | | - reduce( |
60 | | - parts, |
61 | | - firstCid, |
62 | | - (memo, item, next) => { |
63 | | - try { |
64 | | - currentCid = new CID(memo) |
65 | | - } catch (err) { |
66 | | - return next(err) |
67 | | - } |
68 | | - |
69 | | - log('memo: ', memo) |
70 | | - log('item: ', item) |
71 | | - |
72 | | - ipfs.dag.get(currentCid, (err, result) => { |
73 | | - if (err) { |
74 | | - return next(err) |
75 | | - } |
76 | | - |
77 | | - const dagNode = result.value |
78 | | - // find multihash/cid of requested named-file in current dagNode's links |
79 | | - let cidOfNextFile |
80 | | - const nextFileName = item |
81 | | - |
82 | | - try { |
83 | | - for (let link of dagNode.links) { |
84 | | - if (link.name === nextFileName) { |
85 | | - // found multihash/cid of requested named-file |
86 | | - try { |
87 | | - // assume a Buffer with a valid CID |
88 | | - // (cid is allowed instead of multihash since https://github.com/ipld/js-ipld-dag-pb/pull/80) |
89 | | - cidOfNextFile = new CID(link.cid) |
90 | | - } catch (err) { |
91 | | - // fallback to multihash |
92 | | - cidOfNextFile = new CID(mh.toB58String(link.multihash)) |
93 | | - } |
94 | | - break |
95 | | - } |
96 | | - } |
97 | | - } catch (err) { |
98 | | - return next(err) |
99 | | - } |
100 | | - |
101 | | - if (!cidOfNextFile) { |
102 | | - const missingLinkErr = new Error(`no link named "${nextFileName}" under ${memo}`) |
103 | | - missingLinkErr.parentDagNode = memo |
104 | | - missingLinkErr.missingLinkName = nextFileName |
105 | | - return next(missingLinkErr) |
106 | | - } |
107 | | - |
108 | | - next(null, cidOfNextFile) |
109 | | - }) |
110 | | - }, (err, cid) => { |
111 | | - if (err) { |
112 | | - return callback(err) |
113 | | - } |
114 | | - |
115 | | - try { |
116 | | - cid = new CID(cid) |
117 | | - } catch (err) { |
118 | | - return callback(err) |
119 | | - } |
| 49 | + ipfs.files.stat(path, (err, stats) => { |
| 50 | + if (err) { |
| 51 | + return callback(err) |
| 52 | + } |
120 | 53 |
|
121 | | - if (cid.codec === 'raw') { |
122 | | - // no need for additional lookup, its raw data |
123 | | - callback(null, { cid }) |
124 | | - } |
| 54 | + const cid = new CID(stats.hash) |
125 | 55 |
|
126 | | - ipfs.dag.get(cid, (err, dagResult) => { |
127 | | - if (err) { |
128 | | - return callback(err) |
129 | | - } |
| 56 | + if (stats.type.includes('directory')) { |
| 57 | + const err = new Error('This dag node is a directory') |
| 58 | + err.cid = cid |
130 | 59 |
|
131 | | - try { |
132 | | - let dagDataObj = Unixfs.unmarshal(dagResult.value.data) |
133 | | - // There are at least two types of directories: |
134 | | - // - "directory" |
135 | | - // - "hamt-sharded-directory" (example: QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX) |
136 | | - if (dagDataObj.type === 'directory' || dagDataObj.type === 'hamt-sharded-directory') { |
137 | | - let isDirErr = new Error('This dag node is a directory') |
138 | | - // store memo of last multihash so it can be used by directory |
139 | | - isDirErr.cid = isDirErr.fileName = cid |
140 | | - isDirErr.dagDirType = dagDataObj.type |
141 | | - return callback(isDirErr) |
142 | | - } |
143 | | - } catch (err) { |
144 | | - return callback(err) |
145 | | - } |
| 60 | + return callback(err) |
| 61 | + } |
146 | 62 |
|
147 | | - callback(null, { cid }) |
148 | | - }) |
| 63 | + callback(err, { |
| 64 | + cid |
149 | 65 | }) |
| 66 | + }) |
150 | 67 | }) |
151 | 68 |
|
152 | 69 | const multihash = promisify((ipfs, path, callback) => { |
|
0 commit comments