feat(sync): init
Some checks failed
Actions / Build and Push Documentation (push) Failing after 14s

This commit is contained in:
cswimr 2025-02-12 00:53:25 -06:00
parent 65e3144bd1
commit 50b42b038a
Signed by: cswimr
GPG key ID: 0EC431A8DA8F8087
5 changed files with 188 additions and 1 deletions

15
packages/sync/README.md Normal file
View file

@ -0,0 +1,15 @@
# @packwiz/sync
To install dependencies:
```bash
bun install
```
To run:
```bash
bun run sync.ts
```
This project was created using `bun init` in bun v1.2.2. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.

View file

@ -0,0 +1,38 @@
{
"name": "@packwizjs/sync",
"module": "src/sync.ts",
"version": "1.0.0",
"type": "module",
"description": "A directory syncing tool for Minecraft modpacks",
"author": {
"name": "cswimr",
"email": "seaswimmerthefsh@gmail.com"
},
"repository": {
"url": "https://c.csw.im/GalacticFactory/PackwizJS",
"type": "git"
},
"license": "GPL-3.0-only",
"files": [
"src"
],
"readme": "README.md",
"homepage": "https://packwizjs.csw.im",
"keywords": [
"packwiz",
"minecraft"
],
"scripts": {},
"peerDependencies": {
"typescript": "^5.0.0"
},
"dependencies": {
"@packwizjs/parser": "workspace:*",
"murmurhash2": "^0.1.0"
},
"exports": {
".": {
"import": "./src/sync.ts"
}
}
}

110
packages/sync/src/sync.ts Normal file
View file

@ -0,0 +1,110 @@
import {
IndexFileEntry,
Resource,
type Metafile,
type PackwizIndex,
type HashFormat,
doHashesMatch,
} from "@packwizjs/parser";
import { write } from "bun";
function getSaveLocation(
indexFileEntry: IndexFileEntry,
index: PackwizIndex,
metafile?: Metafile,
): Resource {
const cwd = new Resource(process.cwd());
const diff = index.location.diff(indexFileEntry.file);
const fileDirectory = cwd.join(...diff);
if (metafile) {
return fileDirectory.parent.join(metafile.filename);
} else {
return fileDirectory;
}
}
async function downloadFile(
hash: string,
hashFormat: HashFormat,
url: Resource,
path: Resource,
) {
const response = await fetch(new URL(url.toString()));
if (!response.ok) {
throw new Error(`Failed to download ${url}: ${response.statusText}`);
}
const arrayBuffer = await response.arrayBuffer();
if (arrayBuffer.byteLength === 0) {
console.log(`WARNING: Downloaded file is empty: ${url}`);
}
const dataBuffer = Buffer.from(new Uint8Array(arrayBuffer));
doHashesMatch(hash, hashFormat, dataBuffer);
console.log(`Saving file to ${path.toString()}`);
const fileSize = await write(path.toString(), arrayBuffer);
console.log(`Saved ${fileSize} file to ${path.toString()}`);
}
/**
* Iterates over the files in a Packwiz index and downloads them concurrently.
* @param index The Packwiz index to iterate over.
* @param concurrencyLimit The maximum number of concurrent downloads.
* @returns A promise that resolves when all files have been downloaded.
*/
export async function iteratePackwizIndex(
index: PackwizIndex,
concurrencyLimit: number = 5,
) {
let currentIndex = 0;
let activeDownloads = 0;
const totalFiles = index.files.length;
return new Promise<void>((resolve, reject) => {
function downloadNextFile() {
// Resolve if all file entries are downloaded and no active downloads are ongoing
if (currentIndex >= totalFiles && activeDownloads === 0) {
resolve();
return;
}
// If there is still file entries to download and there are empty concurrency slots,
// start a new download.
while (activeDownloads < concurrencyLimit && currentIndex < totalFiles) {
const file = index.files[currentIndex++];
activeDownloads++;
(async () => {
try {
let saveLocation: Resource;
let url: Resource;
let hash: string;
let hashFormat: HashFormat;
if (file.metafile) {
const metafile = await file.parse();
hash = metafile.provider.hash;
hashFormat = metafile.provider.hashFormat;
url = metafile.provider.url;
saveLocation = getSaveLocation(file, index, metafile);
} else {
const diff = index.location.diff(file.file);
hash = file.hash;
hashFormat = file.hashFormat;
url = index.location.parent.join(...diff);
saveLocation = getSaveLocation(file, index);
}
await downloadFile(hash, hashFormat, url, saveLocation);
} catch (error) {
console.error(`Error downloading file: ${error}`);
reject(error);
return;
} finally {
activeDownloads--;
downloadNextFile();
}
})();
}
}
downloadNextFile();
});
}

View file

@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
},
"include": [
"src/**/*.ts"
],
}