♻️ Move parsing and extracting into modules
This commit is contained in:
parent
2dae5f6c58
commit
62a877617b
4 changed files with 57 additions and 25 deletions
|
@ -1,29 +1,14 @@
|
||||||
import { TextDecoder } from 'util';
|
|
||||||
import extractFile from './ssn/extractFile';
|
|
||||||
import getPatchmanifest from './ssn/getPatchmanifest';
|
import getPatchmanifest from './ssn/getPatchmanifest';
|
||||||
import getSolidpkg from './ssn/getSolidpkg';
|
import getSolidpkg from './ssn/getSolidpkg';
|
||||||
import readSsnFile from './ssn/readSsnFile';
|
|
||||||
|
|
||||||
const Decoder = new TextDecoder('utf-8');
|
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
//----- PATCHMANIFEST -----
|
//----- PATCHMANIFEST -----
|
||||||
//.patchmanifest files contain a single XML file called "manifest.xml"
|
//.patchmanifest files contain a single XML file called "manifest.xml"
|
||||||
const patchmanifestBuffer = await getPatchmanifest('assets_swtor_de_de');
|
const patchmanifestXml = await getPatchmanifest('assets_swtor_de_de');
|
||||||
console.log(patchmanifestBuffer.byteLength, patchmanifestBuffer);
|
|
||||||
|
|
||||||
const patchmanifestFiles = readSsnFile(patchmanifestBuffer);
|
|
||||||
console.log(patchmanifestFiles);
|
|
||||||
|
|
||||||
const patchmanifestFile = extractFile(patchmanifestFiles[0], [new DataView(patchmanifestBuffer)]);
|
|
||||||
const patchmanifestXml = Decoder.decode(patchmanifestFile);
|
|
||||||
console.log(patchmanifestXml);
|
console.log(patchmanifestXml);
|
||||||
|
|
||||||
//----- SOLIDPKG -----
|
//----- SOLIDPKG -----
|
||||||
//.solidpkg files contain a single Bencode file called "metafile.solid"
|
//.solidpkg files contain a single Bencode file called "metafile.solid"
|
||||||
const solidpkgBuffer = await getSolidpkg('assets_swtor_de_de', -1, 0);
|
const solidFile = await getSolidpkg('assets_swtor_de_de', -1, 0);
|
||||||
console.log(solidpkgBuffer.byteLength, solidpkgBuffer);
|
console.log(solidFile);
|
||||||
|
|
||||||
const solidPkgFiles = readSsnFile(solidpkgBuffer);
|
|
||||||
console.log(solidPkgFiles);
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -41,7 +41,7 @@ class ByteReader {
|
||||||
/** Extracts the given file from the given DataView array and returns it as an ArrayBuffer.
|
/** Extracts the given file from the given DataView array and returns it as an ArrayBuffer.
|
||||||
* Will throw an error when end of final DataView is reached.
|
* Will throw an error when end of final DataView is reached.
|
||||||
*/
|
*/
|
||||||
export default function extractFile(file: ISsnFileEntry, dvArray: DataView[]): ArrayBuffer {
|
export default async function extractFile(file: ISsnFileEntry, dvArray: DataView[]): Promise<ArrayBuffer> {
|
||||||
//use ByteReader for reading a uint8 and seeking forward across DataView boundaries
|
//use ByteReader for reading a uint8 and seeking forward across DataView boundaries
|
||||||
const byteReader = new ByteReader(dvArray, file.diskNumberStart, file.offset);
|
const byteReader = new ByteReader(dvArray, file.diskNumberStart, file.offset);
|
||||||
|
|
||||||
|
@ -61,6 +61,10 @@ export default function extractFile(file: ISsnFileEntry, dvArray: DataView[]): A
|
||||||
}
|
}
|
||||||
|
|
||||||
//uncompress file
|
//uncompress file
|
||||||
const uncompressedBuffer = zlib.inflateRawSync(dvFinal);
|
const uncompressedBuffer: Buffer = await new Promise((resolve) => {
|
||||||
|
zlib.inflateRaw(dvFinal, (error, result) => {
|
||||||
|
resolve(result);
|
||||||
|
});
|
||||||
|
}) as Buffer;
|
||||||
return uncompressedBuffer.buffer as ArrayBuffer;
|
return uncompressedBuffer.buffer as ArrayBuffer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,36 @@
|
||||||
|
import { TextDecoder } from 'util';
|
||||||
import getUrlContents from '../getUrlContents';
|
import getUrlContents from '../getUrlContents';
|
||||||
import { Product } from '../interfaces/ISettings';
|
import { Product } from '../interfaces/ISettings';
|
||||||
import verifyProductName from '../verifyProductName';
|
import verifyProductName from '../verifyProductName';
|
||||||
|
import extractFile from './extractFile';
|
||||||
|
import readSsnFile from './readSsnFile';
|
||||||
|
|
||||||
export default function getPatchmanifest(product: Product): Promise<ArrayBuffer> {
|
const Decoder = new TextDecoder('utf-8');
|
||||||
|
|
||||||
|
export default async function getPatchmanifest(product: Product): Promise<string> {
|
||||||
//Verify function arguments
|
//Verify function arguments
|
||||||
if (!verifyProductName(product)) {
|
if (!verifyProductName(product)) {
|
||||||
throw new Error(`"${product}" is not a valid product.`);
|
throw new Error(`"${product}" is not a valid product.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getUrlContents({ host: 'manifest.swtor.com', path: `/patch/${product}.patchmanifest` });
|
//Download .patchmanifest file
|
||||||
|
const ssnFile = await getUrlContents({ host: 'manifest.swtor.com', path: `/patch/${product}.patchmanifest` });
|
||||||
|
|
||||||
|
//Parse .patchmanifest file
|
||||||
|
const fileEntries = readSsnFile(ssnFile);
|
||||||
|
|
||||||
|
if (fileEntries.length !== 1) {
|
||||||
|
throw new Error(`Expected .patchmanifest to contain 1 file but it had "${fileEntries.length}" files.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstFile = fileEntries[0];
|
||||||
|
if (firstFile.name !== 'manifest.xml') {
|
||||||
|
throw new Error(`Expected .patchmanifest to contain a file called manifest.xml but it is called "${firstFile.name}".`);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Extract manifest.xml file
|
||||||
|
const patchmanifestFile = await extractFile(firstFile, [new DataView(ssnFile)]);
|
||||||
|
const patchmanifestXml = Decoder.decode(patchmanifestFile);
|
||||||
|
|
||||||
|
return patchmanifestXml;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import getUrlContents from '../getUrlContents';
|
import getUrlContents from '../getUrlContents';
|
||||||
import { Product } from '../interfaces/ISettings';
|
import { Product } from '../interfaces/ISettings';
|
||||||
import verifyProductName from '../verifyProductName';
|
import verifyProductName from '../verifyProductName';
|
||||||
|
import extractFile from './extractFile';
|
||||||
|
import readSsnFile from './readSsnFile';
|
||||||
|
|
||||||
export default function getSolidpkg(product: Product, from: number, to: number): Promise<ArrayBuffer> {
|
export default async function getSolidpkg(product: Product, from: number, to: number): Promise<ArrayBuffer> {
|
||||||
//Verify function arguments
|
//Verify function arguments
|
||||||
if (!verifyProductName(product)) {
|
if (!verifyProductName(product)) {
|
||||||
throw new Error(`"${product}" is not a valid product.`);
|
throw new Error(`"${product}" is not a valid product.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof from !== 'number' || (from | 0) !== from || from < -1) {
|
if (typeof from !== 'number' || (from | 0) !== from || from < -1) {
|
||||||
throw new Error(`from must be an integer greater than or equal to -1 but it is "${from}"`);
|
throw new Error(`from must be an integer greater than or equal to -1 but it is "${from}"`);
|
||||||
}
|
}
|
||||||
|
@ -18,5 +19,23 @@ export default function getSolidpkg(product: Product, from: number, to: number):
|
||||||
throw new Error(`from must be less than to but "${from}" is not less than "${to}".`);
|
throw new Error(`from must be less than to but "${from}" is not less than "${to}".`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getUrlContents({ host: 'cdn-patch.swtor.com', path: `/patch/${product}/${product}_${from}to${to}.solidpkg` });
|
//Download .solidpkg file
|
||||||
|
const ssnFile = await getUrlContents({ host: 'cdn-patch.swtor.com', path: `/patch/${product}/${product}_${from}to${to}.solidpkg` });
|
||||||
|
|
||||||
|
//Parse .solidpkg file
|
||||||
|
const fileEntries = readSsnFile(ssnFile);
|
||||||
|
|
||||||
|
if (fileEntries.length !== 1) {
|
||||||
|
throw new Error(`Expected .solidpkg to contain 1 file but it had "${fileEntries.length}" files.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstFile = fileEntries[0];
|
||||||
|
if (firstFile.name !== 'metafile.solid') {
|
||||||
|
throw new Error(`Expected .solidpkg to contain a file called metafile.solid but it is called "${firstFile.name}".`);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Extract metafile.solid file
|
||||||
|
const solidFile = await extractFile(firstFile, [new DataView(ssnFile)]);
|
||||||
|
|
||||||
|
return solidFile;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue