mirror of https://github.com/Requarks/wiki.git
5 changed files with 153 additions and 0 deletions
Split View
Diff Options
@ -0,0 +1,130 @@ |
|||
const pickle = require('chromium-pickle-js') |
|||
const path = require('path') |
|||
const UINT64 = require('cuint').UINT64 |
|||
const fs = require('fs') |
|||
|
|||
/* global WIKI */ |
|||
|
|||
/** |
|||
* Based of express-serve-asar (https://github.com/toyobayashi/express-serve-asar)
|
|||
* by Fenglin Li (https://github.com/toyobayashi)
|
|||
*/ |
|||
|
|||
const packages = { |
|||
'twemoji': path.join(WIKI.ROOTPATH, `assets/svg/twemoji.asar`) |
|||
} |
|||
|
|||
module.exports = { |
|||
fdCache: {}, |
|||
async serve (pkgName, req, res, next) { |
|||
const file = this.readFilesystemSync(packages[pkgName]) |
|||
const { filesystem, fd } = file |
|||
const info = filesystem.getFile(req.path.substring(1)) |
|||
if (info) { |
|||
res.set({ |
|||
'Content-Type': 'image/svg+xml', |
|||
'Content-Length': info.size |
|||
}) |
|||
|
|||
fs.createReadStream('', { |
|||
fd, |
|||
autoClose: false, |
|||
start: 8 + filesystem.headerSize + parseInt(info.offset, 10), |
|||
end: 8 + filesystem.headerSize + parseInt(info.offset, 10) + info.size - 1 |
|||
}).on('error', (err) => { |
|||
WIKI.logger.warn(err) |
|||
res.sendStatus(404) |
|||
}).pipe(res.status(200)) |
|||
} else { |
|||
res.sendStatus(404) |
|||
} |
|||
}, |
|||
async unload () { |
|||
if (this.fdCache) { |
|||
WIKI.logger.info('Closing ASAR file descriptors...') |
|||
for (const fdItem in this.fdCache) { |
|||
fs.closeSync(this.fdCache[fdItem].fd) |
|||
} |
|||
this.fdCache = {} |
|||
} |
|||
}, |
|||
readArchiveHeaderSync (fd) { |
|||
let size |
|||
let headerBuf |
|||
|
|||
const sizeBuf = Buffer.alloc(8) |
|||
if (fs.readSync(fd, sizeBuf, 0, 8, null) !== 8) { |
|||
throw new Error('Unable to read header size') |
|||
} |
|||
|
|||
const sizePickle = pickle.createFromBuffer(sizeBuf) |
|||
size = sizePickle.createIterator().readUInt32() |
|||
headerBuf = Buffer.alloc(size) |
|||
if (fs.readSync(fd, headerBuf, 0, size, null) !== size) { |
|||
throw new Error('Unable to read header') |
|||
} |
|||
|
|||
const headerPickle = pickle.createFromBuffer(headerBuf) |
|||
const header = headerPickle.createIterator().readString() |
|||
return { header: JSON.parse(header), headerSize: size } |
|||
}, |
|||
readFilesystemSync (archive) { |
|||
if (!this.fdCache[archive]) { |
|||
const fd = fs.openSync(archive, 'r') |
|||
const header = this.readArchiveHeaderSync(fd) |
|||
const filesystem = new Filesystem(archive) |
|||
filesystem.header = header.header |
|||
filesystem.headerSize = header.headerSize |
|||
this.fdCache[archive] = { |
|||
fd, |
|||
filesystem: filesystem |
|||
} |
|||
} |
|||
|
|||
return this.fdCache[archive] |
|||
} |
|||
} |
|||
|
|||
class Filesystem { |
|||
constructor (src) { |
|||
this.src = path.resolve(src) |
|||
this.header = { files: {} } |
|||
this.offset = UINT64(0) |
|||
} |
|||
|
|||
searchNodeFromDirectory (p) { |
|||
let json = this.header |
|||
const dirs = p.split(path.sep) |
|||
for (const dir of dirs) { |
|||
if (dir !== '.') { |
|||
json = json.files[dir] |
|||
} |
|||
} |
|||
return json |
|||
} |
|||
|
|||
getNode (p) { |
|||
const node = this.searchNodeFromDirectory(path.dirname(p)) |
|||
const name = path.basename(p) |
|||
if (name) { |
|||
return node.files[name] |
|||
} else { |
|||
return node |
|||
} |
|||
} |
|||
|
|||
getFile (p, followLinks) { |
|||
followLinks = typeof followLinks === 'undefined' ? true : followLinks |
|||
const info = this.getNode(p) |
|||
|
|||
if (!info) { |
|||
return false |
|||
} |
|||
|
|||
if (info.link && followLinks) { |
|||
return this.getFile(info.link) |
|||
} else { |
|||
return info |
|||
} |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save