JDownloader Community - Appwork GmbH
 

Notices

Reply
 
Thread Tools Display Modes
  #1  
Old 08.12.2019, 20:01
noone1
Guest
 
Posts: n/a
Default [javascript] callAsync and named callback / lost in asynchronous space...

Hello,

I didn't find a way to use callback function in callAsync, so I ended up with something that seems overcomplicated. If somebody could give me an example to 're-sync' the standard output in the flow in this case.

Here I call a function that contains a callAsync and needs its result to go on, but in the context of this function I don't see variable accessible for a callback.

Meanwhile, here is my dirty, messy attempt:), while it is working I'm hopping something shorter:
I use an object.watch polyfill that switch a global param on variable change and use a while loop to check if the switch has been modified!

The problematic call from which I need a return inside the function's context is a simple test of echo %userprofile%.

I put functional script but it's part of a larger, so sorry for the mess;)

(At the beginning I just wanted to play a little with msdos hybrids to learn a bit of javascript but now I think I spent some time on SO and MDN and saw the evilness of javascript, lol.)


Spoiler:

Code:
'use strict';

disablePermissionChecks();
setDisableOnException(false);
setAdvancedAlert(true);

//------------------------------------------
// non native object.watch polyfill
//------------------------------------------
//Eli Grey initial version, improved Xose Lluis

if (!Object.prototype.watch) {

 Object.defineProperty(
   Object.prototype,
   "watch", {
     enumerable: false,
     configurable: true,
     writable: false,
     value: function (prop, handler) {
       var old = this[prop];
       var cur = old;
       //getsw=0;
       var getter = function () {return cur;};
       var setter = function (val) {
        old = cur;
        cur = handler.call(this,prop,old,val);
        //getsw=1;
        return cur;
       };
 
       // can't watch constants
       if (delete this[prop]) {
        Object.defineProperty(this,prop,{
            get: getter,
            set: setter,
            enumerable: true,
            configurable: true
        });
       }
    }
 });
}

//------------------------------------------
// settings
//------------------------------------------

const crlf="\r\n";
const sp=' ';
const bs=getEnvironment().pathSeparator;
const JD_TEMP=JD_HOME+bs+"tmp"+bs;

var start_date = new Date();
var today = start_date.toLocaleString();
var start_msg='-- start@'+today+crlf+crlf;

//obj to watch + switch
var getsw=0;
var geto = { mypath: '', username: '', usertemp: ''};

//act as var listener (trigger when modified)
geto.watch('mypath', function (id, oldval, newval) { 
    getsw=1;
    return newval;}
);

//----------- user defined ----------------- 

var mypath;                    //specify a path for tmp files or default will be used (desktop here)

if (typeof(mypath)=="undefined") {        //using it will define username and user temp folder for logfile
    getLocalPath();}            //will wait for async var to be set
                        
var log_file=mypath+'jsjd_log_tmp.txt';        // log file

var check_locpath='back to main:'+crlf+
'mypath:' +mypath+crlf+
'log_file:'+log_file;

del_file(log_file);
logf(start_msg+"working path: "+mypath+crlf,true);
logf(crlf+print_r(check_locpath));

alert('Hello '+geto.username+" \u0110");

//-- end -- //

//------------------------------------------
//getLocalPath
//------------------------------------------
//set mypath

function getLocalPath(){ 
//function(e,s,r) in callAsync is the callback function except it is an annonymous (unamed) function
//need to send standard output to a parser and then have the result sync here
//I didn't find how to use it so I make it call another function

    callAsync(function(e,s,r){coutput(e,s,r,"path");},"cmd","/c",'@echo off & echo.%userprofile%"');

    sync(); //wait till getsw switch is set

    //now we have the result (geto) from the console log parser  and we can go on
    
    /*choose default*/
    var default_path=geto.mypath+bs+"Desktop"+bs;
    //var default_path=default_path+"JDscripts"+bs;

    if (getPath(default_path)) {
        mypath=default_path;
    } else {
        mypath=JD_TEMP;
    }
}

//------------------------------------------
//sync
//------------------------------------------

function sync(dummy){//if watch switch used

    var i=0;
    while (this['getsw']!=1) {//global this
        if(i>3*Math.pow(10,6)) {break;}
    }
}

//------------------------------------------
//console log parser
//------------------------------------------

function coutput(e,s,r,typ){

    //split console log 
    var b=s.split(crlf);

    /*output for local path*/
    if (typ=="path"){

        // mypath=b[0]=%userprofile%
        geto.mypath=b[0].trim();
        geto.username=b[0].split(bs).pop();
        geto.usertemp=getEnv('TEMP');
    }
}

//------------------------------------------
//format&output
//------------------------------------------

function file_exist(myfile) {
    return getPath(myfile).exists();
}

function del_file(myfile){ //non recursive
    if (file_exist(myfile)) deleteFile(myfile,false);
}

function logf(log_content,bAppend){
//call a 1st time with true to create the file, then bAppend is obsolete

	if (typeof bAppend === 'undefined') bAppend = true;
	if (!bAppend) {
		del_file(log_file);
	} else {
		if (typeof log_file!=="undefined") {
			writeFile(log_file,log_content,bAppend);
		}else{
			alert(' /!\\ attempt to log to undefined file /!\\'
		}
	}
}

function print_r(arr, level) {
//stackoverflow.com/a/9613740

    var dumped_text = "";
    if (!level) level = 0;

    var level_padding = "";//The padding given at the beginning of the line.
    for (var j = 0; j < level + 1; j++) level_padding += "    ";

    if (typeof(arr) == 'object') { 
        for (var item in arr) {
            var value = arr[item];

            if (typeof(value) == 'object') { 
                dumped_text += level_padding + item + " ...\n";
                dumped_text += print_r(value, level + 1);
            } else {
                dumped_text += level_padding + item + " => " + value + "\n";
            }
        }
    } else { 
        dumped_text = "=> " + arr + " <=(" + typeof(arr) + ")";
    }
    return dumped_text;
}

Last edited by noone1; 08.12.2019 at 22:43.
Reply With Quote
  #2  
Old 09.12.2019, 18:49
mgpai mgpai is offline
Script Master
 
Join Date: Sep 2013
Posts: 1,533
Default

Assuming I have understood your requirement correctly, you can use the setProperty() and getProperty() global methods to set session properties (will be available till JD exits or is overwritten by a script), compare them and switch values. You can then use callSync() to get/set the OS environment variables instead of callAsync(). The getEnv() method might be more suitable for this though.
Reply With Quote
  #3  
Old 09.12.2019, 23:25
noone1
Guest
 
Posts: n/a
Default

%userprofile% is just an example here, just to say 'hello user':)

Not clear for me neither, plus it's specific to JD. I'll try to explain more but sorry this callback thing of js is new for me.

In main I call getLocalPath to set a default dir for my files.

In this sub, I first call
Code:
    callAsync(function(exitCode,stdOut,errOut){anotherfunction(where I send exitCode,stdOut,errOut)},"some prog", "some arg");
Then at this moment in getLocalPath I don't have yet the result of "anotherfunction". To wait for it I added a watcher and a function to 'sync' (a simple while to wait):
sync()

Thus, once "anotherfunction" has ended, sync() allow to continue and now I can use the result, for ex
mypath=...

I need callAsync to use the 'anonymous callback' function of JD (function(exitCode,stdOut,errOut){}) to be able to use the standard output since there is not this option with callSync(). (and in anycase, js is single-threaded)

And, these variables (exitCode,stdOut,errOut) are not accessible outside of callAsync, that's why I use anotherfunction to 'catch' them.

Perhaps to better see the effect, comment in/out the line sync() after the callAsync and you will see that back to main the variable is not yet set and thus path is still unknown.

CallSync doesn't help since there is no sdtOut and 'synchronous execution script' option seems, I guess, for JD not js.

For what I understand, but js is really evil:), I should need to define a custom callback function that evaluates the variable I need, hence to force it to be evaluated on call (-back!) and pass it to the current context.., but didn't find.

Best attempt was to embed a custom callback function in a var:
Code:
callAsync(var-as-cbfunc,"some prog","some arg")
but it simply moves the problem on.

In short, without this workaround (anotherfunc+watcher+sync), how can I force callAsync to end before js continues, or js to wait till callAsync has ended and pass the result? (could be anything, file conversion, file i/o, ping, etc..)

Last edited by noone1; 09.12.2019 at 23:30.
Reply With Quote
  #4  
Old 10.12.2019, 13:34
mgpai mgpai is offline
Script Master
 
Join Date: Sep 2013
Posts: 1,533
Default

Both these options use JD Eventscripter API methods (I haven't used JS outside of JD), and as such I am not quite sure how they can be applied to JS in general.

Code:
//stdOut using callSync
var syncStdOut = callSync("cmd", "/c", "echo off & echo %userprofile%", "2>nul");
alert(syncStdOut.trim());

Code:
//stdOut using callAsync
var asyncStdOut;

callAsync(function(exitCode, stdOut, errOut) {
    asyncStdOut = stdOut;
}, "cmd", "/c", "echo off & echo %userprofile%");

while (!asyncStdOut) sleep(1000);
alert(asyncStdOut.trim());
Reply With Quote
  #5  
Old 10.12.2019, 15:10
noone1
Guest
 
Posts: n/a
Default

Thank You!!

- in 2nd ex, asyncStdOut doesn't exist outside callAsync scope, which indeed is the problem. And thank you for the idea, your workaround, while it is still a workarroud, is way more simple!

Code:
//----------------------------------------------------------------------------------------------------------------
    //var async;
    //callAsync(function(e,s,r){coutput(e,s,r,"path");async=s;},"cmd","/c",'@echo off & echo.%userprofile%"');
    //while (!async) sleep(1);
    //alert('show must go on'+async);
    //or
    var easync,sasync,rasync;
    callAsync(function(e,s,r){easync=e;sasync=s;rasync=r;},"cmd","/c",'@echo off & echo.%userprofile%"');
    while (!sasync) sleep(1);
    coutput(easync,sasync,rasync,"path");
//----------------------------------------------------------------------------------------------------------------
- as per your first solution, I guess it resolves my problem, too! I didn't think to get a sdtOut out of callSync! so since it exists, it's even more simple!

Code:
//----------------------------------------------------------------------------------------------------------------
    var syncOut, syncStdOut
    syncOut = callSync("cmd", "/c", "echo off & echo %userprofile%","2>&1"); //(to log sdtErr too if needed/any)
    syncStdOut=syncOut.split(crlf)[0];//will depend on the result
    coutput('',syncStdOut,'',"path");

//----------------------------------------------------------------------------------------------------------------
then, will see which one is faster.

I guess I was actually lost in asynchronous space... Arigato sensei

Last edited by noone1; 10.12.2019 at 15:19.
Reply With Quote
  #6  
Old 10.12.2019, 16:06
mgpai mgpai is offline
Script Master
 
Join Date: Sep 2013
Posts: 1,533
Default

Quote:
Originally Posted by noone1 View Post
syncOut = callSync("cmd", "/c", "echo off & echo %userprofile%","2>&1"); //(to log sdtErr too if needed/any)
By default (if redirection is not specified) it will return stdOut or stdErr.

Code:
var out = callSync("cmd", "/c", "dir/b", "nofile"); // stdOut or stdErr
var stdOut = callSync("cmd", "/c", "dir/b", "nofile", "2>nul"); // Only stdOut
var stdErr = callSync("cmd", "/c", "dir/b", ".", "2>&1", "1>nul"); // Only stdErr
Reply With Quote
  #7  
Old 10.12.2019, 17:42
mgpai mgpai is offline
Script Master
 
Join Date: Sep 2013
Posts: 1,533
Default

Quote:
Originally Posted by mgpai View Post
The getEnv() method might be more suitable for this though.
I was referring to the following method to get environment variables:

Code:
// Get environment variables

var env = {};
env.mypath = getEnv("userprofile");
env.username = env.mypath.replace(/.+\\/, "");
env.usertemp = getEnv("tmp");

alert(env);
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

All times are GMT +2. The time now is 13:01.
Provided By AppWork GmbH | Privacy | Imprint
Parts of the Design are used from Kirsch designed by Andrew & Austin
Powered by vBulletin® Version 3.8.10 Beta 1
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.