resolve-dat-path
Version:
Resolves a file within a dat archive based on how web browsers would load it
91 lines (84 loc) • 2.03 kB
JavaScript
const MANIFEST_LOCATION = '/dat.json'
const CHECK_PATHS = [
path => path,
path => `${path}index.html`,
path => `${path}index.md`,
path => `${path}/index.html`,
path => `${path}/index.md`,
path => `${path}.html`,
path => `${path}.md`
]
module.exports = async function resolveFileInArchive (archive, path) {
let {
web_root: webRoot = '',
fallback_page: fallbackPage
} = await getManifest(archive)
if (!path.startsWith('/')) {
path = `/${path}`
}
path = `${webRoot}${path}`
for (const makePath of CHECK_PATHS) {
const file = await getEntry(archive, makePath(path), 'file')
if (file) {
return file
}
}
const dir = await getEntry(archive, path, 'directory')
if (dir) {
return dir
}
if (fallbackPage) {
if (!fallbackPage.startsWith('/')) {
fallbackPage = `/${fallbackPage}`
}
let file
file = await getEntry(archive, fallbackPage, 'file')
if (file) {
return file
}
file = await getEntry(archive, `${webRoot}${fallbackPage}`, 'file')
if (file) {
return file
}
}
throw new Error('Not Found')
}
async function getManifest (archive) {
try {
const rawManifest = await readFile(archive, MANIFEST_LOCATION, 'utf-8')
return JSON.parse(rawManifest) || {}
} catch (error) {
// Oh well
return {}
}
}
async function getEntry (archive, path, type) {
try {
const stat = await asyncStat(archive, path)
if (
(type === 'directory' && stat.isDirectory()) ||
(type === 'file' && stat.isFile())
) {
return {
type,
path,
stat
}
}
} catch (error) {
// Oh well
}
return null
}
const asyncStat = (archive, path) => new Promise((resolve, reject) =>
archive.stat(path, (err, stat) => {
if (err) reject(err)
else resolve(stat)
})
)
const readFile = (archive, file, encoding) => new Promise((resolve, reject) =>
archive.readFile(file, encoding, (err, data) => {
if (err) reject(err)
else resolve(data)
})
)