refactor to single class
This commit is contained in:
+190
-117
@@ -5,14 +5,6 @@ import { forAsync } from "@sugoidogo/js-util"
|
||||
|
||||
const pathSeperatorRegex = /[\\\/]/
|
||||
|
||||
export interface PackwizPack {
|
||||
packDirectoryHandle: FileSystemDirectoryHandle
|
||||
packFileName: Path
|
||||
packMetaData: PackMetaData
|
||||
packIndex: PackIndex
|
||||
packFiles: { [key: Path]: PackFileMetaData | undefined }
|
||||
}
|
||||
|
||||
function assertOK(response: Response) {
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText, { "cause": response })
|
||||
@@ -69,7 +61,7 @@ async function getHash(data: Uint8Array<ArrayBuffer> | string, format: HashForma
|
||||
throw new Error('unknown hash format: ' + format)
|
||||
}
|
||||
|
||||
async function assertHashMatch(bytes: Uint8Array<ArrayBuffer>, hashFormat: HashFormat, hash: Hash, errorFileName?:string) {
|
||||
async function assertHashMatch(bytes: Uint8Array<ArrayBuffer>, hashFormat: HashFormat, hash: Hash, errorFileName?: string) {
|
||||
const bytesHash = await getHash(bytes, hashFormat)
|
||||
if (bytesHash.toString() !== hash) {
|
||||
if (errorFileName) throw new Error("hash verification failed on " + errorFileName)
|
||||
@@ -78,117 +70,198 @@ async function assertHashMatch(bytes: Uint8Array<ArrayBuffer>, hashFormat: HashF
|
||||
return true
|
||||
}
|
||||
|
||||
export async function fetchPack(packUrl: Url, packDirectoryHandle: FileSystemDirectoryHandle) {
|
||||
const { packMetaData, packFileName } = await fetch(packUrl).then(async response => {
|
||||
const packFileText = await assertOK(response).text()
|
||||
const packMetaData = parseTOML(packFileText) as PackMetaData
|
||||
const packFileName = packUrl.split(pathSeperatorRegex).pop()
|
||||
const packFileHandle = await getFileHandle(packDirectoryHandle, packFileName, { "create": true })
|
||||
await writeFile(packFileHandle, packFileText)
|
||||
return { packMetaData, packFileName }
|
||||
})
|
||||
const packIndexURL = new URL(packMetaData.index.file, packUrl)
|
||||
const { packIndex, indexDirname: packIndexDirname } = await fetch(packIndexURL).then(async response => {
|
||||
const packIndexBytes = await assertOK(response).bytes()
|
||||
await assertHashMatch(packIndexBytes, packMetaData.index["hash-format"], packMetaData.index.hash, packMetaData.index.file)
|
||||
const packIndex = parseTOML(packIndexBytes.toString()) as PackIndex
|
||||
const packIndexFileHandle = await getFileHandle(packDirectoryHandle, packMetaData.index.file, { "create": true })
|
||||
await writeFile(packIndexFileHandle, packIndexBytes)
|
||||
const packIndexPathSegments = packIndexURL.pathname.split("/")
|
||||
packIndexPathSegments.pop()
|
||||
const indexDirname = packIndexPathSegments.join("/")
|
||||
return { packIndex, indexDirname }
|
||||
})
|
||||
const pack: PackwizPack = {
|
||||
packDirectoryHandle,
|
||||
packFileName,
|
||||
packMetaData,
|
||||
packIndex,
|
||||
packFiles: {}
|
||||
}
|
||||
await forAsync(packIndex.files, async entry => {
|
||||
const fileHandle = await getFileHandle(packDirectoryHandle, packIndexDirname + "/" + entry.file, { "create": true })
|
||||
const file = await fileHandle.getFile()
|
||||
let fileBytes = await file.bytes()
|
||||
if (await assertHashMatch(fileBytes, entry["hash-format"] || packIndex["hash-format"], entry.hash)) return
|
||||
const fileURL = new URL(entry.file, packIndexURL)
|
||||
fileBytes = await fetch(fileURL)
|
||||
.then(response => assertOK(response).bytes())
|
||||
await assertHashMatch(fileBytes, entry["hash-format"] || packIndex["hash-format"], entry.hash, entry.file)
|
||||
await writeFile(fileHandle, fileBytes)
|
||||
if (entry.metafile) pack.packFiles[entry.file] = parseTOML(fileBytes.toString())
|
||||
})
|
||||
return pack
|
||||
}
|
||||
export class PackwizPack {
|
||||
|
||||
export async function loadPack(packDirectoryHandle: FileSystemDirectoryHandle, packFileName = "pack.toml") {
|
||||
const packMetaData = await getFileHandle(packDirectoryHandle, packFileName).then(async packDirectoryHandle => {
|
||||
const packFile = await packDirectoryHandle.getFile()
|
||||
const packFileText = await packFile.text()
|
||||
return parseTOML(packFileText) as PackMetaData
|
||||
})
|
||||
const { packIndex, packIndexDirname } = await getFileHandle(packDirectoryHandle, packMetaData.index.file).then(async indexFileHandle => {
|
||||
const packIndexFile = await indexFileHandle.getFile()
|
||||
const packIndexBytes = await packIndexFile.bytes()
|
||||
if (!packMetaData.options || !packMetaData.options["no-internal-hashes"]) {
|
||||
await assertHashMatch(packIndexBytes, packMetaData.index["hash-format"], packMetaData.index.hash, packMetaData.index.file)
|
||||
packDirectoryHandle: FileSystemDirectoryHandle
|
||||
packFileName: Path
|
||||
packMetaData: PackMetaData
|
||||
packIndex: PackIndex
|
||||
packFiles: { [key: Path]: PackFileMetaData | undefined }
|
||||
|
||||
constructor(packDirectoryHandle: FileSystemDirectoryHandle, packName: string, versions:PackMetaData["versions"]) {
|
||||
this.packDirectoryHandle = packDirectoryHandle
|
||||
this.packFileName = "pack.toml"
|
||||
this.packMetaData = {
|
||||
"name": packName,
|
||||
"pack-format": "packwiz:1.1.0",
|
||||
"index": {
|
||||
"file": "index.toml",
|
||||
"hash-format": "sha1"
|
||||
},
|
||||
"versions": versions
|
||||
}
|
||||
const packIndexPathSegments = packMetaData.index.file.split(pathSeperatorRegex)
|
||||
this.packIndex = {
|
||||
"hash-format": "sha1",
|
||||
"files": [] as any
|
||||
}
|
||||
this.packFiles = {}
|
||||
}
|
||||
|
||||
static async fetchPack(packDirectoryHandle: FileSystemDirectoryHandle, packUrl: Url) {
|
||||
const { packMetaData, packFileName } = await fetch(packUrl).then(async response => {
|
||||
const packFileText = await assertOK(response).text()
|
||||
const packMetaData = parseTOML(packFileText) as PackMetaData
|
||||
const packFileName = packUrl.split(pathSeperatorRegex).pop()
|
||||
const packFileHandle = await getFileHandle(packDirectoryHandle, packFileName, { "create": true })
|
||||
await writeFile(packFileHandle, packFileText)
|
||||
return { packMetaData, packFileName }
|
||||
})
|
||||
const packIndexURL = new URL(packMetaData.index.file, packUrl)
|
||||
const { packIndex, indexDirname: packIndexDirname } = await fetch(packIndexURL).then(async response => {
|
||||
const packIndexBytes = await assertOK(response).bytes()
|
||||
await assertHashMatch(packIndexBytes, packMetaData.index["hash-format"], packMetaData.index.hash, packMetaData.index.file)
|
||||
const packIndex = parseTOML(packIndexBytes.toString()) as PackIndex
|
||||
const packIndexFileHandle = await getFileHandle(packDirectoryHandle, packMetaData.index.file, { "create": true })
|
||||
await writeFile(packIndexFileHandle, packIndexBytes)
|
||||
const packIndexPathSegments = packIndexURL.pathname.split("/")
|
||||
packIndexPathSegments.pop()
|
||||
const indexDirname = packIndexPathSegments.join("/")
|
||||
return { packIndex, indexDirname }
|
||||
})
|
||||
const pack = Object.assign(new PackwizPack(undefined, undefined, undefined), {
|
||||
packDirectoryHandle,
|
||||
packFileName,
|
||||
packMetaData,
|
||||
packIndex
|
||||
})
|
||||
await forAsync(packIndex.files, async entry => {
|
||||
const fileHandle = await getFileHandle(packDirectoryHandle, packIndexDirname + "/" + entry.file, { "create": true })
|
||||
const file = await fileHandle.getFile()
|
||||
let fileBytes = await file.bytes()
|
||||
if (await assertHashMatch(fileBytes, entry["hash-format"] || packIndex["hash-format"], entry.hash)) return
|
||||
const fileURL = new URL(entry.file, packIndexURL)
|
||||
fileBytes = await fetch(fileURL)
|
||||
.then(response => assertOK(response).bytes())
|
||||
await assertHashMatch(fileBytes, entry["hash-format"] || packIndex["hash-format"], entry.hash, entry.file)
|
||||
await writeFile(fileHandle, fileBytes)
|
||||
if (entry.metafile) pack.packFiles[entry.file] = parseTOML(fileBytes.toString())
|
||||
})
|
||||
return pack
|
||||
}
|
||||
|
||||
static async loadPack(packDirectoryHandle: FileSystemDirectoryHandle, packFileName = "pack.toml") {
|
||||
const packMetaData = await getFileHandle(packDirectoryHandle, packFileName).then(async packDirectoryHandle => {
|
||||
const packFile = await packDirectoryHandle.getFile()
|
||||
const packFileText = await packFile.text()
|
||||
return parseTOML(packFileText) as PackMetaData
|
||||
})
|
||||
const { packIndex, packIndexDirname } = await getFileHandle(packDirectoryHandle, packMetaData.index.file).then(async indexFileHandle => {
|
||||
const packIndexFile = await indexFileHandle.getFile()
|
||||
const packIndexBytes = await packIndexFile.bytes()
|
||||
if (!packMetaData.options || !packMetaData.options["no-internal-hashes"]) {
|
||||
await assertHashMatch(packIndexBytes, packMetaData.index["hash-format"], packMetaData.index.hash, packMetaData.index.file)
|
||||
}
|
||||
const packIndexPathSegments = packMetaData.index.file.split(pathSeperatorRegex)
|
||||
packIndexPathSegments.pop()
|
||||
const packIndexDirname = packIndexPathSegments.join("/")
|
||||
const packIndex = parseTOML(packIndexBytes.toString()) as PackIndex
|
||||
return { packIndex, packIndexDirname }
|
||||
})
|
||||
const pack = Object.assign(new PackwizPack(undefined, undefined, undefined), {
|
||||
packDirectoryHandle,
|
||||
packFileName,
|
||||
packMetaData,
|
||||
packIndex
|
||||
})
|
||||
await forAsync(packIndex.files, async entry => {
|
||||
const fileHandle = await getFileHandle(packDirectoryHandle, packIndexDirname + "/" + entry.file)
|
||||
const file = await fileHandle.getFile()
|
||||
const fileBytes = await file.bytes()
|
||||
if (!packMetaData.options || !packMetaData.options["no-internal-hashes"]) {
|
||||
await assertHashMatch(fileBytes, entry["hash-format"] || packIndex["hash-format"], entry.hash, entry.file)
|
||||
}
|
||||
if (entry.metafile) pack.packFiles[entry.file] = parseTOML(fileBytes.toString())
|
||||
})
|
||||
return pack
|
||||
}
|
||||
|
||||
static async refreshPack(packDirectoryHandle: FileSystemDirectoryHandle, packFileName = "pack.toml") {
|
||||
const { packMetaData, packFileHandle } = await getFileHandle(packDirectoryHandle, packFileName).then(async packDirectoryHandle => {
|
||||
const packFile = await packDirectoryHandle.getFile()
|
||||
const packFileText = await packFile.text()
|
||||
const packMetaData = parseTOML(packFileText) as PackMetaData
|
||||
return { packMetaData, packFileHandle }
|
||||
})
|
||||
const { packIndex, packIndexDirname, indexFileHandle } = await getFileHandle(packDirectoryHandle, packMetaData.index.file).then(async indexFileHandle => {
|
||||
const packIndexFile = await indexFileHandle.getFile()
|
||||
const packIndexBytes = await packIndexFile.bytes()
|
||||
const packIndexPathSegments = packMetaData.index.file.split(pathSeperatorRegex)
|
||||
const packIndexDirname = packIndexPathSegments.join("/")
|
||||
const packIndex = parseTOML(packIndexBytes.toString()) as PackIndex
|
||||
packIndex.files = [] as any
|
||||
return { packIndex, packIndexDirname, indexFileHandle }
|
||||
})
|
||||
const pack = Object.assign(new PackwizPack(undefined, undefined, undefined), {
|
||||
packDirectoryHandle,
|
||||
packFileName,
|
||||
packMetaData,
|
||||
packIndex
|
||||
})
|
||||
const indexDirectoryHandle = await getDirectoryHandle(packDirectoryHandle, packIndexDirname)
|
||||
const directoryHandles = [indexDirectoryHandle]
|
||||
do {
|
||||
const directoryHandle = directoryHandles.pop()
|
||||
await forAsync(directoryHandle.values(), async handle => {
|
||||
if (handle.kind === "directory") {
|
||||
directoryHandles.push(handle)
|
||||
return
|
||||
}
|
||||
if (handle.isSameEntry(indexFileHandle) || handle.isSameEntry(packFileHandle)) return
|
||||
const pathSegments = await indexDirectoryHandle.resolve(handle)
|
||||
const filePath = pathSegments.join("/")
|
||||
const isMetafile = handle.name.endsWith(".pw.toml")
|
||||
pack.packIndex.files.push({
|
||||
"file": filePath,
|
||||
"metafile": isMetafile
|
||||
})
|
||||
if (isMetafile) {
|
||||
const file = await handle.getFile()
|
||||
const text = await file.text()
|
||||
pack.packFiles[filePath] = parseTOML(text)
|
||||
}
|
||||
})
|
||||
} while (directoryHandles.length !== 0)
|
||||
return pack
|
||||
}
|
||||
|
||||
async savePack(hashes?: boolean) {
|
||||
if (typeof hashes !== "boolean") {
|
||||
hashes = !this.packMetaData.options || !this.packMetaData.options["no-internal-hashes"]
|
||||
}
|
||||
const textEncoder = new TextEncoder()
|
||||
const packIndexPathSegments = this.packMetaData.index.file.split(pathSeperatorRegex)
|
||||
packIndexPathSegments.pop()
|
||||
const packIndexDirname = packIndexPathSegments.join("/")
|
||||
const packIndex = parseTOML(packIndexBytes.toString()) as PackIndex
|
||||
return { packIndex, packIndexDirname }
|
||||
})
|
||||
const pack: PackwizPack = {
|
||||
packDirectoryHandle,
|
||||
packFileName,
|
||||
packMetaData,
|
||||
packIndex,
|
||||
packFiles: {}
|
||||
await forAsync(this.packIndex.files, async entry => {
|
||||
const packFileMetaData = this.packFiles[entry.file]
|
||||
const fileHandle = await getFileHandle(this.packDirectoryHandle, packIndexDirname + "/" + entry.file, { "create": true })
|
||||
let packFileBytes: Uint8Array<ArrayBuffer>
|
||||
if (packFileMetaData) {
|
||||
packFileBytes = textEncoder.encode(stringifyTOML(packFileMetaData))
|
||||
await writeFile(fileHandle, packFileBytes)
|
||||
}
|
||||
else {
|
||||
const file = await fileHandle.getFile()
|
||||
packFileBytes = await file.bytes()
|
||||
}
|
||||
if (hashes) {
|
||||
entry.hash = await getHash(packFileBytes, entry["hash-format"] || this.packIndex["hash-format"])
|
||||
.then(hash => hash.toString())
|
||||
} else {
|
||||
delete entry.hash
|
||||
}
|
||||
})
|
||||
await getFileHandle(this.packDirectoryHandle, this.packMetaData.index.file, { "create": true }).then(async packIndexFileHandle => {
|
||||
const packIndexBytes = textEncoder.encode(stringifyTOML(this.packIndex))
|
||||
if (hashes) {
|
||||
this.packMetaData.index.hash = await getHash(packIndexBytes, this.packMetaData.index["hash-format"])
|
||||
.then(hash => hash.toString())
|
||||
} else {
|
||||
delete this.packMetaData.index.hash
|
||||
}
|
||||
await writeFile(packIndexFileHandle, packIndexBytes)
|
||||
})
|
||||
await getFileHandle(this.packDirectoryHandle, this.packFileName, { "create": true })
|
||||
.then(packFileHandle => writeFile(packFileHandle, stringifyTOML(this.packMetaData)))
|
||||
}
|
||||
await forAsync(packIndex.files, async entry => {
|
||||
const fileHandle = await getFileHandle(packDirectoryHandle, packIndexDirname + "/" + entry.file)
|
||||
const file = await fileHandle.getFile()
|
||||
const fileBytes = await file.bytes()
|
||||
if (!packMetaData.options || !packMetaData.options["no-internal-hashes"]) {
|
||||
await assertHashMatch(fileBytes, entry["hash-format"] || packIndex["hash-format"], entry.hash, entry.file)
|
||||
}
|
||||
if (entry.metafile) pack.packFiles[entry.file] = parseTOML(fileBytes.toString())
|
||||
})
|
||||
return pack
|
||||
}
|
||||
|
||||
export async function savePack(pack: PackwizPack, hashes?: boolean) {
|
||||
if (typeof hashes !== "boolean") {
|
||||
hashes = !pack.packMetaData.options || !pack.packMetaData.options["no-internal-hashes"]
|
||||
}
|
||||
const textEncoder = new TextEncoder()
|
||||
const packIndexPathSegments = pack.packMetaData.index.file.split(pathSeperatorRegex)
|
||||
packIndexPathSegments.pop()
|
||||
const packIndexDirname = packIndexPathSegments.join("/")
|
||||
await forAsync(pack.packIndex.files, async entry => {
|
||||
const packFileMetaData = pack.packFiles[entry.file]
|
||||
if (!packFileMetaData) return
|
||||
const packFileBytes = textEncoder.encode(stringifyTOML(packFileMetaData))
|
||||
if (hashes) {
|
||||
entry.hash = await getHash(packFileBytes, entry["hash-format"] || pack.packIndex["hash-format"])
|
||||
.then(hash => hash.toString())
|
||||
} else {
|
||||
delete entry.hash
|
||||
}
|
||||
const fileHandle = await getFileHandle(pack.packDirectoryHandle, packIndexDirname + "/" + entry.file, { "create": true })
|
||||
await writeFile(fileHandle, packFileBytes)
|
||||
})
|
||||
await getFileHandle(pack.packDirectoryHandle, pack.packMetaData.index.file, { "create": true }).then(async packIndexFileHandle => {
|
||||
const packIndexBytes = textEncoder.encode(stringifyTOML(pack.packIndex))
|
||||
if (hashes) {
|
||||
pack.packMetaData.index.hash = await getHash(packIndexBytes, pack.packMetaData.index["hash-format"])
|
||||
.then(hash => hash.toString())
|
||||
} else {
|
||||
delete pack.packMetaData.index.hash
|
||||
}
|
||||
await writeFile(packIndexFileHandle, packIndexBytes)
|
||||
})
|
||||
await getFileHandle(pack.packDirectoryHandle, pack.packFileName, { "create": true })
|
||||
.then(packFileHandle => writeFile(packFileHandle, stringifyTOML(pack.packMetaData)))
|
||||
}
|
||||
Reference in New Issue
Block a user