This repository has been archived by the owner on Sep 28, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathindex.js
117 lines (102 loc) · 3.85 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/* global Response */
'use strict'
const stream = require('stream')
const toBlob = require('stream-to-blob')
const resolver = require('./resolver')
const pathUtils = require('./utils/path')
const detectContentType = require('./utils/content-type')
// TODO: pass path and add Etag and X-Ipfs-Path + tests
const header = (status = 200, statusText = 'OK', headers = {}) => ({
status,
statusText,
headers
})
const response = (ipfsNode, ipfsPath) => {
// handle hash resolve error (simple hash, test for directory now)
const handleResolveError = (node, path, error) => {
if (error) {
const errorString = error.toString()
return new Promise((resolve, reject) => {
// switch case with true feels so wrong.
switch (true) {
case (errorString === 'Error: This dag node is a directory'):
resolver.directory(node, path, error.cid)
.then((content) => {
// dir render
if (typeof content === 'string') {
resolve(new Response(content, header(200, 'OK', { 'Content-Type': 'text/html' })))
}
// redirect to dir entry point (index)
resolve(Response.redirect(pathUtils.joinURLParts(path, content[0].name)))
})
.catch((error) => {
resolve(new Response(errorString, header(500, error.toString())))
})
break
case errorString.startsWith('Error: no link named'):
resolve(new Response(errorString, header(404, errorString)))
break
case errorString.startsWith('Error: multihash length inconsistent'):
case errorString.startsWith('Error: Non-base58 character'):
resolve(new Response(errorString, header(400, errorString)))
break
default:
resolve(new Response(errorString, header(500, errorString)))
}
})
}
}
return new Promise((resolve, reject) => {
// remove trailing slash for files if needed
if (ipfsPath.endsWith('/')) {
resolve(Response.redirect(pathUtils.removeTrailingSlash(ipfsPath)))
}
resolver.cid(ipfsNode, ipfsPath)
.then((resolvedData) => {
const readableStream = ipfsNode.catReadableStream(resolvedData.cid)
const responseStream = new stream.PassThrough({ highWaterMark: 1 })
readableStream.pipe(responseStream)
readableStream.once('error', (error) => {
if (error) {
resolve(new Response(error.toString(), header(500, 'Error fetching the file')))
}
})
// return only after first chunk being checked
let contentTypeDetected = false
readableStream.on('data', (chunk) => {
// check mime on first chunk
if (contentTypeDetected) {
return
}
contentTypeDetected = true
// return Response with mime type
const contentType = detectContentType(ipfsPath, chunk)
if (typeof Blob === 'undefined') {
if (contentType) {
resolve(new Response(responseStream, header(200, 'OK', { 'Content-Type': contentType })))
} else {
resolve(new Response(responseStream, header()))
}
} else {
toBlob(responseStream, (err, blob) => {
if (err) {
resolve(new Response(err.toString(), header(500, 'Error fetching the file')))
}
if (contentType) {
resolve(new Response(blob, header(200, 'OK', { 'Content-Type': contentType })))
} else {
resolve(new Response(blob, header()))
}
})
}
})
})
.catch((error) => {
resolve(handleResolveError(ipfsNode, ipfsPath, error))
})
})
}
module.exports = {
getResponse: response,
resolver: resolver
}