LiquidPlayer / LiquidCore

Node.js virtual machine for Android and iOS
MIT License
1.01k stars 127 forks source link

Unable to get `payload.getContext()` from `EventListener` #141

Closed bangonkali closed 4 years ago

bangonkali commented 4 years ago

Using 'com.github.LiquidPlayer:LiquidCore:0.6.2' I could not get payload.getContext() from EventListener using Kotlin 1.3.60.

Related to https://github.com/LiquidPlayer/LiquidCore/issues/138#issuecomment-558239276

bangonkali commented 4 years ago

image

ericwlange commented 4 years ago

My mistake. I forgot that this is a JSONObject and not a JSObject.

Ok, the less simple way of getting it (sorry, in Java -- my Kotlin knowledge is not great):

Put this in your ServiceStartListener:

class ContextBean {
    JSContext context;
}
final ContextBean contextBean = new ContextBean();

service.getProcess().addEventListener(new Process.EventListener() {
    @Override
    public void onProcessStart(final Process process, final JSContext context) {
        //                                                  ^^^^^^^^^^^^^^^^^
        //                                                  HERE IS THE CONTEXT
        contextBean.context = context;
    }
    @Override public void onProcessExit(Process process, int exitCode) {}
    @Override public void onProcessAboutToExit(Process process, int exitCode) {}
    @Override public void onProcessFailed(Process process, Exception error) {}
});

final JSContext context = contextBean.context;

Now you have the context.

Some notes.

bangonkali commented 4 years ago

Thanks for the example @ericwlange!

I was able to make it work using the following:

        // ...more code...

        val processEventListener = object : Process.EventListener {
            override fun onProcessAboutToExit(process: Process?, exitCode: Int) {}
            override fun onProcessExit(process: Process?, exitCode: Int) {}
            override fun onProcessFailed(process: Process?, error: Exception?) {}
            override fun onProcessStart(process: Process?, context: JSContext?) {
                if (context != null) {
                    jsContext = context

                    context.evaluateScript("var versions = JSON.stringify(process.versions);")
                    val versions = context.property("versions")
                    Log.d(TAG, "Javascript context retrieved. $versions")
                }
            }
        }

        // ...more code...

        val startListener =
            ServiceStartListener { service ->
                Log.d(TAG, "Microservice started.")
                service.process.addEventListener(processEventListener)
                ...more code...
            }

        // ...more code...

        microService = MicroService(
            context,
            res,
            startListener
        )

Output for Log.d(TAG, "Javascript context retrieved. $versions"), related to #137:

> Javascript context retrieved. {"http_parser":"2.7.0","node":"8.9.3","v8":"6.1.534.48","uv":"1.15.0","zlib":"1.2.11","ares":"1.10.1-DEV","modules":"57","nghttp2":"1.25.0","openssl":"1.0.2n","liquidcore":"0.6.2"}

Full wrapper for reference:

package my.package.name.service

import android.util.Base64
import android.util.Log
import org.json.JSONObject
import org.liquidplayer.javascript.JSContext
import org.liquidplayer.node.Process
import org.liquidplayer.service.MicroService
import org.liquidplayer.service.MicroService.EventListener
import org.liquidplayer.service.MicroService.ServiceStartListener
import my.package.name.R
import java.io.InputStream
import java.lang.Exception
import java.net.URI

class MyMicroservice(private val context: MyService) {
    companion object {
        private const val TAG: String = "MyMicroservice"
    }

    private lateinit var microService: MicroService
    private lateinit var jsContext: JSContext

    fun init() {
        val res = URI("android.resource://my.package.name/raw/index")
        val wasmStream: InputStream = context.resources.openRawResource(R.raw.main)
        val wasmBytes: ByteArray = wasmStream.readBytes()
        val wasmBase64 = Base64.encodeToString(
            wasmBytes,
            Base64.DEFAULT or Base64.NO_WRAP
        )

        Log.d(TAG, "Wasm Loaded (Base 64): $wasmBase64")

        val processEventListener = object : Process.EventListener {
            override fun onProcessAboutToExit(process: Process?, exitCode: Int) {
                TODO("not implemented")
            }

            override fun onProcessExit(process: Process?, exitCode: Int) {
                TODO("not implemented")
            }

            override fun onProcessFailed(process: Process?, error: Exception?) {
                TODO("not implemented")
            }

            override fun onProcessStart(process: Process?, context: JSContext?) {
                if (context != null) {
                    jsContext = context

                    context.evaluateScript("var versions = JSON.stringify(process.versions);")
                    val versions = context.property("versions")
                    Log.d(TAG, "Javascript context retrieved. $versions")
                }
            }
        }

        val exitListener =
            EventListener { service, event, payload ->
                Log.d(TAG, "Event:$event ${payload.getString("message")}")
                context.state = MyService.STOPPED
                context.terminateService()
            }

        val logListener =
            EventListener { service, event, payload ->
                Log.d(TAG, "Event:$event ${payload.getString("message")}")
            }

        val readyListener =
            EventListener { service, event, payload ->
                Log.d(TAG, "Event:$event")
                service.emit("req_init", wasmBase64)
            }

        val initListener =
            EventListener { service, event, payload ->
                Log.d(TAG, "Event:$event ${payload.getString("message")}")
            }

        val startListener =
            ServiceStartListener { service ->
                Log.d(TAG, "Microservice started.")

                service.process.addEventListener(processEventListener)

                service.addEventListener("log", logListener)
                service.addEventListener("res_ready", readyListener)
                service.addEventListener("res_init", initListener)
                service.addEventListener("res_exit", exitListener)

                context.state = MyService.STARTED
            }

        microService = MicroService(
            context,
            res,
            startListener
        )
    }

    fun stop() {
        Log.d(TAG, "Stopping My microservice.")
        microService.emit("req_exit")
    }

    fun start() {
        Log.d(TAG, "Starting My microservice.")
        microService.start()
    }
}
bangonkali commented 4 years ago

After much contemplation about this, I think using context might not be the best approach at all for my needs 😂 but nonetheless thanks for guiding me in this respect.