<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
Mark,<br>
<br>
I'll have a look.<br>
<br>
Regards,<br>
Michael<br>
<br>
<br>
<div class="moz-cite-prefix">Am 01.09.20 um 07:30 schrieb Mark
Webb-Johnson:<br>
</div>
<blockquote type="cite"
cite="mid:9393E6BF-E1C9-495C-88CE-16082D7678A0@webb-johnson.net">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
Michael,
<div class=""><br class="">
</div>
<div class="">Still struggling with this. It seems like your
DuktapeObject will do this, but I can’t work out how it works.</div>
<div class=""><br class="">
</div>
<div class="">Here are some notes one what I have done so far:</div>
<div class=""><br class="">
</div>
<div class="">
<ol class="MailOutline">
<li class="">Created a stub DuktapeConsoleCommand (derived
from DuktapeObject) in ovms_duktape.{h,cpp}. This should
hold enough to be able to call the javascript callback
method for that object. It also stores the module filename
(so the registration can be removed when the module is
unloaded).<br class="">
<br class="">
</li>
<li class="">Provide a DuktapeCommandMap m_cmdmap in
ovms_duktape.{h,cpp} OvmsDuktape class that stores a mapping
from OvmsCommand to DuktapeConsoleCommand.<br class="">
<br class="">
</li>
<li class="">Created
a OvmsDuktape::RegisterDuktapeConsoleCommand in
ovms_duktape.{h,cpp) that (a) creates the OvmsCommand()
object, (b) registers it, (c) creates
the DuktapeConsoleCommand() object, and (d) updates a map
from OvmsCommand->DuktapeConsoleCommand. There Is also a
single callback DukOvmsCommandRegisterRun designed to be run
by all.<br class="">
<br class="">
</li>
<li class="">Created
hooks NotifyDuktapeModuleLoad, NotifyDuktapeModuleUnload,
and NotifyDuktapeModuleUnloadAll in OvmsDuktape. The
javascript module is identified by filename (path to module
or script on vfs, usually, but may also be an internal
module). The Unload functions look through the m_cmdmap and
unregister commands for javascript modules being unloaded.<br
class="">
<br class="">
</li>
<li class="">Provide an implementation for
ovms_command DukOvmsCommandRegister to support registering
commands from Javascript modules. This should extract the
details, and then call
OvmsDuktape::RegisterDuktapeConsoleCommand to do the actual
registration. This has been implemented, except for the
callback method (and somehow passing that method from
Javascript in the OvmsCommand.Register javascript call).<br
class="">
<br class="">
</li>
<li class="">Provide a stub implementation for <span
style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
class="">DukOvmsCommandRegisterRun. This uses m_cmdmap to
lookup the </span><font class="" color="#000000">DuktapeConsoleCommand
object for the command to be run. It should execute the
callback method (but that part is not yet implemented).</font></li>
</ol>
</div>
<div class=""><br class="">
</div>
<div class=""><br class="">
</div>
<div class="">I still need help with #5 and #6. What needs to be
implemented in DuktapeConsoleCommand, and how is the parameter
in <span style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
class="">OvmsCommand.Register used to store the callback (#5)?
Then how to callback the command method from</span> <span
style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
class="">DukOvmsCommandRegisterRun</span><span
style="caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);"
class=""> (#6)? If you have time, it is probably much quicker
for you to simply make those changes.</span></div>
<div class=""><span style="caret-color: rgb(0, 0, 0); color:
rgb(0, 0, 0);" class=""><br class="">
</span></div>
<div class=""><font class="" color="#000000">An alternative
implementation would be to do something like the pubsub
framework, where the mapping command->callback is done from
within a javascript module. That I could do, but it seems
your </font><span style="caret-color: rgb(0, 0, 0); color:
rgb(0, 0, 0);" class="">DuktapeObject can do it better.</span><font
class="" color="#000000"> </font></div>
<div class=""><br class="">
</div>
<div class="">Thanks, Mark.<br class="">
<div><br class="">
<blockquote type="cite" class="">
<div class="">On 15 Jul 2020, at 3:34 PM, Michael Balzer
<<a href="mailto:dexter@expeedo.de" class=""
moz-do-not-send="true">dexter@expeedo.de</a>> wrote:</div>
<br class="Apple-interchange-newline">
<div class="">
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8" class="">
<div class=""> Mark,<br class="">
<br class="">
yes, I needed that persistence for the HTTP and VFS
classes, but I also needed to be able to couple a
dynamic C++ instance with a JS object and have a
mechanism to prevent garbage collection while the C++
side is still in use. If the C++ side is no longer
needed, the JS finalizer also needs to imply the C++
instance can be deleted.<br class="">
<br class="">
That is all implemented by DuktapeObject. DuktapeObject
also provides JS method invocation on the coupled JS
object and a mutex for concurrency protection.<br
class="">
<br class="">
We probably need some more framework documentation than
the header comments (applies to all of our framework
classes…):<br class="">
<br class="">
<tt class="">/***************************************************************************************************</tt><tt
class=""><br class="">
</tt><tt class=""> * DuktapeObject: coupled C++ / JS
object</tt><tt class=""><br class="">
</tt><tt class=""> * </tt><tt class=""><br class="">
</tt><tt class=""> * Intended for API methods to attach
internal API state to a JS object and provide</tt><tt
class=""><br class="">
</tt><tt class=""> * a standard callback invocation
interface for JS objects in local scopes.</tt><tt
class=""><br class="">
</tt><tt class=""> * </tt><tt class=""><br class="">
</tt><tt class=""> * - Override CallMethod() to
implement specific method calls</tt><tt class=""><br
class="">
</tt><tt class=""> * - Override Finalize() for specific
destruction in JS context (garbage collection)</tt><tt
class=""><br class="">
</tt><tt class=""> * - call Register() to prevent
normal garbage collection (but not heap destruction)</tt><tt
class=""><br class="">
</tt><tt class=""> * - call Ref() to protect against
deletion (reference count)</tt><tt class=""><br
class="">
</tt><tt class=""> * - call Lock() to protect
concurrent access (recursive mutex)</tt><tt class=""><br
class="">
</tt><tt class=""> * </tt><tt class=""><br class="">
</tt><tt class=""> * - GetInstance() retrieves the
DuktapeObject associated with a JS object if any</tt><tt
class=""><br class="">
</tt><tt class=""> * - Push() pushes the JS object onto
the Duktape stack</tt><tt class=""><br class="">
</tt><tt class=""> * </tt><tt class=""><br class="">
</tt><tt class=""> * Note: the DuktapeObject may
persist after the JS object has been finalized, e.g.</tt><tt
class=""><br class="">
</tt><tt class=""> * if some callbacks are pending
after the Duktape heap has been destroyed.</tt><tt
class=""><br class="">
</tt><tt class=""> * Use IsCoupled() to check if the
JS object is still available.</tt><tt class=""><br
class="">
</tt><tt class=""> * </tt><tt class=""><br class="">
</tt><tt class=""> * Ref/Unref:</tt><tt class=""><br
class="">
</tt><tt class=""> * Normal life cycle is from
construction to finalization. Pending callbacks extend</tt><tt
class=""><br class="">
</tt><tt class=""> * the life until the last callback
has been processed. A subclass may extend the life</tt><tt
class=""><br class="">
</tt><tt class=""> * by calling Ref(), which
increases the reference count. Unref() deletes the
instance</tt><tt class=""><br class="">
</tt><tt class=""> * if no references are left.</tt><tt
class=""><br class="">
</tt><tt class=""> */</tt><tt class=""><br class="">
</tt><br class="">
You normally just need to use Register/Deregister &
Ref/Unref, and to implement the constructor and
CallMethod. Coupling of the instances normally is done
on construction, as a JS object is normally already
needed for the parameters and can simply be attached to.<br
class="">
<br class="">
Have a look at DuktapeHTTPRequest, DuktapeVFSLoad and
DuktapeVFSSave, these are the current subclasses using
this.<br class="">
<br class="">
For the command registration I would probably couple the
OvmsCommand instance with a JS command object providing
an execution method.<br class="">
<br class="">
Tell me if you need more info.<br class="">
<br class="">
Regards,<br class="">
Michael<br class="">
<br class="">
<br class="">
<div class="moz-cite-prefix">Am 15.07.20 um 08:12
schrieb Mark Webb-Johnson:<br class="">
</div>
<blockquote type="cite"
cite="mid:B291C8AF-8382-4F45-87E3-3DA555E068BE@webb-johnson.net"
class="">
<meta http-equiv="Content-Type" content="text/html;
charset=UTF-8" class="">
<div class=""><br class="">
</div>
<div class="">@Michael this is probably for you.</div>
<div class=""><br class="">
</div>
<div class="">I am trying to implement javascript
command registration. The idea is that a javascript
module can call something like:</div>
<div class=""><br class="">
</div>
<div class="">
<blockquote style="caret-color: rgb(0, 0, 0);
margin: 0px 0px 0px 40px; border: none; padding:
0px;" class="">OvmsCommand.Register(basecommand,
name, title, callbackfn, usage, min, max)</blockquote>
<div style="caret-color: rgb(0, 0, 0);" class=""><br
class="">
</div>
</div>
<div style="caret-color: rgb(0, 0, 0);" class="">Then
we reflect that into MyCommandApp.RegisterCommand,
and keep a track of which command is for which
javascript callbackfn. When the command is executed,
we pass it into duktape.</div>
<div style="caret-color: rgb(0, 0, 0);" class=""><br
class="">
</div>
<div style="caret-color: rgb(0, 0, 0);" class="">I
also have tracking for javascript module loading and
unloading, so I can DeregisterCommand() if duktape
is reloaded (and also protected against commands
being registered in short-lived scripts run from the
command line).</div>
<div style="caret-color: rgb(0, 0, 0);" class=""><br
class="">
</div>
<div style="caret-color: rgb(0, 0, 0);" class="">To
implement this, I need to store the callbackfn as a
persistent reference to a duktape javascript
function.</div>
<div class=""><br class="">
</div>
<div class="">The issue with callback function
references in duktape is summarised here:</div>
<div class=""><br class="">
</div>
<blockquote style="margin: 0 0 0 40px; border: none;
padding: 0px;" class="">
<div class=""><a
href="https://wiki.duktape.org/howtonativepersistentreferences"
class="" moz-do-not-send="true">https://wiki.duktape.org/howtonativepersistentreferences</a></div>
<div class=""><br class="">
</div>
<div class=""><i class="">When a Duktape/C function
is called, Duktape places the call arguments on
the value stack. While the arguments are on the
value stack, they're guaranteed to be reachable
and the Duktape/C function can safely work with
the arguments.<br class="">
<br class="">
However, when the Duktape/C function returns,
the value stack is unwound and references in the
function's value stack frame are lost. If the
last reference to a particular value was in the
function's value stack frame, the value will be
garbage collected when the function return is
processed.</i></div>
</blockquote>
<div class=""><br class="">
</div>
<div class="">The standard approach is to store the
reference back in the duktape duk_push_global_stash
so it won’t get garbage-collected. But, that seems
messy.</div>
<div class=""><br class="">
</div>
<div class="">I see that Michael has already
implemented something that seems similar in
ovms_script.{h, cpp}, for the async http callbacks.
Presumably to avoid this issue. But, the approach
seems very different, and I am not sure if it is
stopping _all_ garbage collection for the duration
of the async query, or just that particular object
being garbage collected. The work seems extensive
(quite a few objects involved).</div>
<div class=""><br class="">
</div>
<div class="">So @Michael, any suggestions for this? I
don’t want to reinvent the wheel...</div>
<div class=""><br class="">
</div>
<div class="">Regards, Mark.</div>
<br class="">
<fieldset class="mimeAttachmentHeader"></fieldset>
<pre class="moz-quote-pre" wrap="">_______________________________________________
OvmsDev mailing list
<a class="moz-txt-link-abbreviated" href="mailto:OvmsDev@lists.openvehicles.com" moz-do-not-send="true">OvmsDev@lists.openvehicles.com</a>
<a class="moz-txt-link-freetext" href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev" moz-do-not-send="true">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a>
</pre>
</blockquote>
<br class="">
<pre class="moz-signature" cols="72">--
Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal
Fon 02333 / 833 5735 * Handy 0176 / 206 989 26
</pre>
</div>
_______________________________________________<br
class="">
OvmsDev mailing list<br class="">
<a href="mailto:OvmsDev@lists.openvehicles.com" class=""
moz-do-not-send="true">OvmsDev@lists.openvehicles.com</a><br
class="">
<a class="moz-txt-link-freetext" href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a><br
class="">
</div>
</blockquote>
</div>
<br class="">
</div>
<br>
<fieldset class="mimeAttachmentHeader"></fieldset>
<pre class="moz-quote-pre" wrap="">_______________________________________________
OvmsDev mailing list
<a class="moz-txt-link-abbreviated" href="mailto:OvmsDev@lists.openvehicles.com">OvmsDev@lists.openvehicles.com</a>
<a class="moz-txt-link-freetext" href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a>
</pre>
</blockquote>
<br>
<pre class="moz-signature" cols="72">--
Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal
Fon 02333 / 833 5735 * Handy 0176 / 206 989 26</pre>
</body>
</html>