Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrating from J2V8 to Javet/Javenode? #2

Open
Awesome1221 opened this issue Jul 16, 2022 · 9 comments
Open

Migrating from J2V8 to Javet/Javenode? #2

Awesome1221 opened this issue Jul 16, 2022 · 9 comments
Labels
feat: core New feature related to the core of BlockJS (ie: the Java side code)

Comments

@Awesome1221
Copy link
Contributor

Since J2V8 isn't maintained that much lately, and there are better alternatives to work with, I think the actual library should've been deprecated from the project baseline and replaced with Javet/Javenode.

See here: https://www.caoccao.com/Javet/tutorial/migration_guides/migrate_from_j2v8.html

@TheGreatViolet TheGreatViolet added the feat: other New feature label Jul 16, 2022
@TheGreatViolet
Copy link
Member

It's actually funny you should mention this, I've been working on trying to migrate this project to Javet for a little bit now (see branch at https://github.com/Block-JS/blockjs/tree/javet). The migration is done for the most part, I've just hit a couple snags (mainly not being able to import modules without Javet throwing an exception)

@Awesome1221
Copy link
Contributor Author

Yeah, I've noticed some issues with Javet as well, although I don't know if these are the same ones we're talking about. I just made a pull request, you can check it. As of now there's no way to directly pass a File/Path reference to the Javet runtime, as it messes up with the file reading/writing, possibly a bug?

@TheGreatViolet
Copy link
Member

Well the pull request seems to have fixed one of the issues, that being that whereas before the PR when I'd run the test command /bjs test again after having ran it before it wouldn't run again.

However another issue that I had before still remains. When I'd try to import another file/an NPM module using the import/export syntax Javet claims to support, I get an error like this:

[10:25:51 INFO]: litteraly1984 issued server command: /bjs test
[10:25:51 WARN]: [com.caoccao.javet.interop.NodeRuntime] 7 V8 callback context object(s) not recycled.
[10:25:51 WARN]: [com.caoccao.javet.interop.NodeRuntime] 7 V8 callback context object(s) not recycled.
[10:25:51 ERROR]: [BlockJS] There was an error with the script: test2.js
[10:25:51 ERROR]: [BlockJS] Error: Cannot find package './test'
[10:25:51 WARN]: [com.caoccao.javet.interop.NodeRuntime] 7 V8 callback context object(s) not recycled.

I'm not entirely sure if this is a problem with Javet or if it's perhaps something I'm doing wrong, but I haven't gotten things to work no matter what I try. If anyone wants to take a look I've attached the full logs along with the files I used to test.

test.js

export function test() {
  return 'test';
}

test2.js

import { test } from "./test";

console.log(test());

latest.log

@Awesome1221
Copy link
Contributor Author

Perhaps it might be related to caoccao/Javet#4

@Awesome1221
Copy link
Contributor Author

I checked it, and it looks like even after trying to set up a custom module resolver, it doesn't seem to help. When running the command for the first time it seems to be working, however when the V8 context is reused those imported modules appear to still be there despite the fact that V8Runtime.resetContext() is being used.

> bjs test
[INFO]: test
[INFO]: [BlockJS] [STDOUT] function test() {
return 'test';
}
> bjs test
[INFO]: test
[ERROR]: [BlockJS] There was an error with the script: test2.js
[ERROR]: [BlockJS] Error: Cannot read the array length because "" is null
...
[ERROR]: Could not save data net.minecraft.world.entity.raid.PersistentRaid
...
[ERROR]: Failed to save level ./world
...

Seems like it's the same thing #2 (comment)

@TheGreatViolet
Copy link
Member

Alright, I was able to get a custom module resolver working in the test suite for the JSExecutionInterface, and it seems to work quite well. All that's left now is to get that resolver working in the JSRunner class

@Awesome1221
Copy link
Contributor Author

Awesome1221 commented Aug 2, 2022

Let me know if this works for you, because the last time I've tried it, I had some issues with reusing the context.

public class FilenameUtils {
    static public String[] getParts(String name, String separator) {
        var parts = name.split(separator);

        return parts;
    }
    static public String[] getParts(String name) {
        return getParts(name, "\\.");
    }
}
nodeRuntime.setV8ModuleResolver((moduleRuntime, rawRequestedModulePath, moduleImporter) -> {
    try {
        var rawRequestedModuleFile = new File(rawRequestedModulePath);
        var rawRequestedModuleFileNameParts = FilenameUtils.getParts(rawRequestedModuleFile.getName());

        for(var fsEntry: BlockJS.getScriptsFolder().listFiles()) {
            var entryFileNameParts = FilenameUtils.getParts(fsEntry.getName());

            if(entryFileNameParts[entryFileNameParts.length - 1].equals("js")) {
                if(entryFileNameParts[0].equals(rawRequestedModuleFileNameParts[0])) {
                    var modulePath = fsEntry.toPath().toAbsolutePath();

                    var requestedModuleFileContent = Files.readString(modulePath);

                    return moduleRuntime.getExecutor(requestedModuleFileContent)
                            .setResourceName(modulePath.toString())
                            .compileV8Module();
                }
            }
        }
    } catch (IOException e) {
        BlockJS.instance.getLogger().log(Level.SEVERE, "There was an error with reading the file: " + file.getName());
        BlockJS.instance.getLogger().log(Level.SEVERE, e.getMessage());
    }

    return null;
});

@TheGreatViolet
Copy link
Member

I ended up with something similar to this. I'm not entirely sure what I did different, but it seems to work when reusing the context:

NodeRuntime createRuntime(File file) throws JavetException {
        JavetEngineConfig config = new JavetEngineConfig();
        config.setJSRuntimeType(JSRuntimeType.Node);

        JavetEnginePool<NodeRuntime> pool = new JavetEnginePool<NodeRuntime>(config);

        NodeRuntime runtime = pool.getEngine().getV8Runtime();

        runtime.setV8ModuleResolver(((v8Runtime, resourceName, iv8Module) -> {
            // Matches the file extension
            Pattern pattern = Pattern.compile("((?<=\\w)\\.[^.]+)$");
            Matcher matcher = pattern.matcher(resourceName);

            String ext = matcher.find() ? matcher.group(1) : "";

            String trueResourceName;

            if (ext.equals("")) {
                trueResourceName = resourceName + ".js";
            } else {
                trueResourceName = resourceName;
            }

            File resourceFile = new File(file.getParentFile(), trueResourceName);

            if (!resourceFile.exists()) {
                // TODO: Resolve module from node_modules
                return null;
            }

            return runtime.getExecutor(resourceFile)
                    .setResourceName(resourceName)
                    .compileV8Module();
        }));

        return runtime;
    }

Pretty much all that needs to be done now is resolving any packages from node_modules.

@TheGreatViolet TheGreatViolet added feat: core New feature related to the core of BlockJS (ie: the Java side code) and removed feat: other New feature labels Aug 3, 2022
@Awesome1221
Copy link
Contributor Author

I'm not entirely sure if it helped, there're still some errors with it

> bjs test
[INFO]: test
> bjs test
[ERROR]: [com.destroystokyo.paper.io.PaperFileIOThread] Failed to read chunk data for task: Task for world: 'world_nether' at -19,20 poi: true, hash: 1934452656
java.nio.file.FileAlreadyExistsException: ./world_nether/DIM-1/poi
at sun.nio.fs.UnixException.translateToIOException(UnixException.java:94) ~[?:?]
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:106) ~[?:?]
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111) ~[?:?]
at sun.nio.fs.UnixFileSystemProvider.createDirectory(UnixFileSystemProvider.java:397) ~[?:?]
at java.nio.file.Files.createDirectory(Files.java:700) ~[?:?]
at java.nio.file.Files.createAndCheckIsDirectory(Files.java:807) ~[?:?]
at java.nio.file.Files.createDirectories(Files.java:753) ~[?:?]
at net.minecraft.world.level.chunk.storage.RegionFileStorage.getRegionFile(RegionFileStorage.java:96) ~[?:?]
at net.minecraft.world.level.chunk.storage.RegionFileStorage.read(RegionFileStorage.java:182) ~[?:?]
at net.minecraft.world.entity.ai.village.poi.PoiManager.a(PoiManager.java:472) ~[?:?]
at net.minecraft.server.level.ServerLevel$1.readData(ServerLevel.java:333) ~[?:?]
at com.destroystokyo.paper.io.PaperFileIOThread$ChunkDataTask.run(PaperFileIOThread.java:508) ~[paper-1.19.2.jar:git-Paper-118]
at com.destroystokyo.paper.io.QueueExecutorThread.pollTasks(QueueExecutorThread.java:118) ~[paper-1.19.2.jar:git-Paper-118]
at com.destroystokyo.paper.io.QueueExecutorThread.run(QueueExecutorThread.java:51) ~[paper-1.19.2.jar:git-Paper-118]
[ERROR]: [com.destroystokyo.paper.io.chunk.ChunkLoadTask] Could not load chunk for task: Chunk task: class:com.destroystokyo.paper.io.chunk.ChunkLoadTask, for world 'world_nether', (-19,20), hashcode:705348310, priority: -1, file IO thread has dumped the relevant exception above
[ERROR]: [BlockJS] There was an error with the script: test2.js
[ERROR]: [BlockJS] Error: Cannot invoke "java.io.File.getAbsolutePath()" because "parentFile" is null

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat: core New feature related to the core of BlockJS (ie: the Java side code)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants