Pass event listener (function) from LUA to JS part of plugin get "type <function> is not supported by JSON" warning

I have tried to pass event listener (function) from lua code to plugin and got “type <function> is not supported by JSON” warning in JS part.

How I can understand, I can not pass LUA listener to js and I need do a trick in LUA part of plugin and make a few “dances” with connection LUA-JS in plugin?  

Thanks!

Hi,

This has been on my mind as well, and I am wondering what a good solution to this would be.

This is semi-major in my opinion for working with cross-platform development between HTML5 and device builds. I’ve spent the last couple days rebuilding a fairly large device plugin from the ground up for HTML5 (JS), which is to be expected (and was certainly made much easier using Corona HTML5 Node Kit), but the major issue is that the developer will also need to either be very creative in how they build a cross-platform app or be required to build a device app, and then an additional HTML5 app.

In essence the developer interface to a plugin should be the same whether it is JS or Lua. I don’t imagine this to be an easy task, and I am extremely impressed with the parity so far.  :wink:

There are two things that stick out to me when trying to create a unified plugin interface for the developer.

  1. Properties (which I’ve mentioned in another post)
  2. Callbacks / Listeners

Working with properties could be handled with getters and setters, as long as that was worked into both the device plugin code and the JS plugin code. A little extra work, not my favorite solution, but doable.

The major one that I am running into is the callback interface. Here we lose all parity.

For device plugins we can do:

_ Device plugin _

... function doSomething(params, handler) return handler('whatever') end ...

Lua

local function handler(e) --callback stuff end myplugin.doSomething(params, handler)

But for JS, the workflow is something like:

JS plugin

... function doSomething(params, event\_id) { this.dispatchEvent({name: event\_id, data: 'whatever'}) } ...

Lua

local function handler(e) --callback stuff end myplugin.addEventListener('event\_id', handler) mypluing.doSomething(params, 'event\_id')

The only workaround that I have considered so far is to have both the device and JS plugin be entirely event driven by using the system.newEventDispatcher in the device side plugin, but I don’t think this is commonly what most developers use/do. We also end up with:

obj.addEventListener(...) --JS --and obj:addEventListener(...) --System Dispatcher

Note the dot vs. colon syntax (EDIT: I realized the colon syntax issue can be worked around by wrapping my own addEventListener method into a module).

In short (or long at this point), being able to pass a handler function to the JS side would solve what I see is a major issue for cross-platform plugins. I don’t know what kind of magic it would take, but in my opinion the use of a plugin, whether device or HTML5, should be as transparent to the developer as possible.

-dev

@dev,

We made plugin for facebook (as native with all functionality) and it work perfect, but I wanted to know, is there any other ways to solve issues with callbacks. Now we are making inapp plugin for facebook (as native inapp for ios) and it almost done, but with “dancing” yet :slight_smile:
 

About properties, it is very important problem now. I hope corona team can solve this issue in near future. For example, we can not use isActive property right now, because after compilation it becomes as function and we do special interface from JS to LUA. But for the sake of justice, in last facebook4a plugin isActive property is function too :frowning:

Thanks,

Dr.

Engineering is focused on getting C++ plugins working with HTML5 now. They will loop back to this some point after this. It’s important that works, but we have to focus on finishing one task before moving to another.

Rob

Hi,

This is nothing time critical (for myself), just wanted to share my observations. Let engineering keep on churning out the goodness.  :slight_smile:

-dev

@dev,

+1  :slight_smile:

Now one can to pass <function> to JS plugin and use it to call Lua from JS.

Here’s updated sample 

Hi,

Very nice! Looks like properties are working too.  :smiley:

-dev

Hi,

So I’ve been running a couple of tests integrating the ability to pass in a Lua function to the JS side. I am assuming that a limitation of the Lua function being passed is that it is only available synchronously.

If I try to use it in an HTTP request on the JS side it ends up throwing an error (even though the type is still “function” in JS).

Some pseudoish-code may make it easier to understand what I am referring to.

This works great:

Lua

local function onAction(e) print(e) --\> Hello end jsplugin.doAction(onAction)

JS

... function doAction(cb\_func) { cb\_func('Hello') } ...

But, this will throw an error:

Lua

local function onAction(e) print(e) end jsplugin.doAction(onAction)

JS (using superagent, tried other request libs as well)

... function doAction(cb\_func) { request .post('/api') .send({name: 'Sally'}) .set('accept', 'json') .end((err, res) =\> { console.log(res.body) //\> outputs correct response console.log(typeof(cb\_func)) //\> function cb\_func(res.body) //\> throws error (see below) }) } ...

The error thrown is:

ERROR: Runtime error attempt to call a nil value

The ability to pass a Lua function alone is already awesome.  :)  But this will be a common pattern when trying to work with external APIs which tend to be asynchronous. I’ve tried a number of different work arounds (wrapping the callback, etc.) but still get the same error.

Of course using the dispatchEvent pattern here works just fine. So is this a limitation that can be overcome? Any tips on workarounds? Or should I just stick to event dispatching. I have a “hybrid” plugin that is at about 99% parity except for the callback feature not working in this type of situation.

Thanks for all the hard work on the HTML5 builds. It really is some amazing stuff.

-dev

Thanks for the detailed report . Fixed, asynchronous callbacks should be available with 3268.

Hi,

Excellent. That was fast!  :slight_smile:

-dev

Super!  :) 

Thank you very much!

Dr.

Implemented getters and setters, they should come with 3269.

here’s sample 

Hey! Quick heads-up! Next daily build (2018.3276) would bring breaking changes to plugin.

  1. Removed addEventListere and removeEventListener
  2. Now you can pass functions to JS:
     - as arguments (top level, inside tables)
     - assigning to properties. This are ready to use JS functions.
  3. Parameter functions come in JS as “references”. To work with references there’re 3 functions (in javascript)
     - LuaIsFunction(reference) -> boolean
     - LuaCreateFunction(fererence) ->function
     - LuaReleaseFunction( function )

IMPORTANT : JS must acquire function with LuaCreateFunction as soon as it passed. Returning from wherever parameter is received would make all function references invalid.

main.lua:

p = require "ppp" p.c = function() print "Hello" end p.i(function() print "World" end)

ppp.js

window.ppp = {&nbsp; &nbsp; &nbsp; &nbsp;i : function(cb) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var f = LuaCreateFunction(cb); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.c(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setTimeout(function(){ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;f(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LuaReleaseFunction(f); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, 500) &nbsp; &nbsp; } }

Overall there’s not limitations of how things are passed around. As long as all Created functions are Released, there would be no memory leaks.

Only limitation is that java functions do not get returned to Lua from function calls.

P.S. no more ‘type <function> is not supported by JSON’ messages :wink:

Hi,

I assume this needed to be done because of memory leaks, which I understand. But, it’s certainly not as elegant as before.  :rolleyes:

-dev

I think it is very elegant to have basically seamless interop between JS & Lua like this (did you see native C apis?). Wrapping up functions is pretty easy.

Also, you can assign fields to JS module and functions would just work.

Problem is that we don’t know what functions and when JS would use. JS doesn’t expose any garbage collection events as far as I know. So references just become invalid as soon as they go out of scope. If you can come up with some nice wrappers/additional functions - we’ll add then.

Hi,

I’m certainly not complaining. I can adjust to the changes. It’s been amazing what you all have done so far.  :slight_smile:

Keep up the great work!

-dev

Hi,

This has been on my mind as well, and I am wondering what a good solution to this would be.

This is semi-major in my opinion for working with cross-platform development between HTML5 and device builds. I’ve spent the last couple days rebuilding a fairly large device plugin from the ground up for HTML5 (JS), which is to be expected (and was certainly made much easier using Corona HTML5 Node Kit), but the major issue is that the developer will also need to either be very creative in how they build a cross-platform app or be required to build a device app, and then an additional HTML5 app.

In essence the developer interface to a plugin should be the same whether it is JS or Lua. I don’t imagine this to be an easy task, and I am extremely impressed with the parity so far.  :wink:

There are two things that stick out to me when trying to create a unified plugin interface for the developer.

  1. Properties (which I’ve mentioned in another post)
  2. Callbacks / Listeners

Working with properties could be handled with getters and setters, as long as that was worked into both the device plugin code and the JS plugin code. A little extra work, not my favorite solution, but doable.

The major one that I am running into is the callback interface. Here we lose all parity.

For device plugins we can do:

_ Device plugin _

... function doSomething(params, handler) return handler('whatever') end ...

Lua

local function handler(e) --callback stuff end myplugin.doSomething(params, handler)

But for JS, the workflow is something like:

JS plugin

... function doSomething(params, event\_id) { this.dispatchEvent({name: event\_id, data: 'whatever'}) } ...

Lua

local function handler(e) --callback stuff end myplugin.addEventListener('event\_id', handler) mypluing.doSomething(params, 'event\_id')

The only workaround that I have considered so far is to have both the device and JS plugin be entirely event driven by using the system.newEventDispatcher in the device side plugin, but I don’t think this is commonly what most developers use/do. We also end up with:

obj.addEventListener(...) --JS --and obj:addEventListener(...) --System Dispatcher

Note the dot vs. colon syntax (EDIT: I realized the colon syntax issue can be worked around by wrapping my own addEventListener method into a module).

In short (or long at this point), being able to pass a handler function to the JS side would solve what I see is a major issue for cross-platform plugins. I don’t know what kind of magic it would take, but in my opinion the use of a plugin, whether device or HTML5, should be as transparent to the developer as possible.

-dev

@dev,

We made plugin for facebook (as native with all functionality) and it work perfect, but I wanted to know, is there any other ways to solve issues with callbacks. Now we are making inapp plugin for facebook (as native inapp for ios) and it almost done, but with “dancing” yet :slight_smile:
 

About properties, it is very important problem now. I hope corona team can solve this issue in near future. For example, we can not use isActive property right now, because after compilation it becomes as function and we do special interface from JS to LUA. But for the sake of justice, in last facebook4a plugin isActive property is function too :frowning:

Thanks,

Dr.

Engineering is focused on getting C++ plugins working with HTML5 now. They will loop back to this some point after this. It’s important that works, but we have to focus on finishing one task before moving to another.

Rob