Skip to content

Instantly share code, notes, and snippets.

@coder0107git
Created June 12, 2025 04:34
Show Gist options
  • Save coder0107git/bc1a421ce88933ef67658d9787066fc6 to your computer and use it in GitHub Desktop.
Save coder0107git/bc1a421ce88933ef67658d9787066fc6 to your computer and use it in GitHub Desktop.
A small wrapper for writing files to the java-writable portion of the CheerpJ filesystem.
<script src="https://cjrtnc.leaningtech.com/3_20250514_1341/loader.js"></script>
<script type="module">
import { fileOpen } from "https://cdn.jsdelivr.net/npm/[email protected]/+esm";
class CheerpJFs {
// This probably should be static
#textEncoder = new TextEncoder();
#java;
#lib;
constructor(cheerpjLib) {
const lib = cheerpjLib;
this.#lib = cheerpjLib;
this.#java = new Promise(async (resolve) => {
const Files = await lib.java.nio.file.Files;
const Paths = await lib.java.nio.file.Paths;
resolve({ Files, Paths });
});
}
// Handles errors that might be java errors
async #errorHandler(e) {
try {
const lib = this.#lib;
const JavaError = await lib.java.lang.Throwable;
if(e instanceof JavaError) {
return new Error(await e.toString());
}
} catch (_) {}
if(e instanceof Error) {
return e;
}
return new Error(e);
}
/**
* @param {Object} options
* @param {string} options.path - The absolute path to the file.
* @param {string | Int8Array} options.contents - The contents of the file.
* @param {boolean} [options.ensureDirectoryExists=true] - If parent directories should be created if they don't exist before creating the file.
*
* @returns {string}
*/
async writeFile(options = {}) {
// To avoid modification of an object we don't own.
options = Object.assign({}, options);
if(typeof options.path !== "string") {
throw new Error("File path is required");
}
if(typeof options.contents === "string") {
options.contents = new Int8Array(
this.#textEncoder.encode(options.contents)
);
}
if(options.contents instanceof Int8Array !== true) {
throw new Error("File contents are required. Contents must be either a string or an Int8Array.");
}
const {
path,
contents: fileContents,
ensureDirectoryExists,
throwErrors,
} = {
ensureDirectoryExists: true,
throwErrors: true,
...options,
};
try {
const { Files, Paths } = await this.#java;
const filePath = await Paths.get(path);
if(ensureDirectoryExists) {
const parentDir = await filePath.getParent();
await Files.createDirectories(parentDir);
}
const fileStream = await Files.newOutputStream(filePath);
// Int8Array -> byte[]
await fileStream.write(fileContents);
// TODO: Is flushing needed?
await fileStream.flush();
await fileStream.close();
return true;
} catch(e) {
throw await this.#errorHandler(e);
}
}
}
console.log(-1)
await cheerpjInit({
version: 11,
});
console.log(0)
const lib = await cheerpjRunLibrary("");
console.log(1)
try {
alert("Click on page a lot for 3 seconds");
await new Promise(r => setTimeout(r, 2000));
const file = await fileOpen([
{
description: "Any file",
id: "open-file",
},
]);
const fileBuffer = await file.arrayBuffer();
console.log(2);
const fs = new CheerpJFs(lib);
console.log(3);
await fs.writeFile({
path: `/files/js/${file.name}`,
contents: new Int8Array(fileBuffer),
});
console.log(4);
// Make sure the file exists
const fileBlob = await cjFileBlob(`/files/js/${file.name}`);
console.log(`Size: ${JSON.stringify(fileBlob.size)}, Type: ${JSON.stringify(fileBlob.type)}`)
} catch(e) {
debugger;
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment