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