I've been reading the sockets examples, but all I can get JMP to do is acknowledge receiving a request, I can't get the payload or message of the request. Is there a better way than sockets or scheduler to achieve nonblocking communication?
Everything is on windows.
Basically my workflow is:
- Render an HTML page with JMP,
- interact with the data using javascript, html, css
- pass the result to a python Flask server using Javascript XMLHTTP request
- Continuously ping the Flask server with jmp via scheduler to see if Flask server has any data waiting for me, if it does then python will return the data and JMP will get it as a response, if it doesn't then jmp gets the string 'no update' and I just return.
- Update JMP table with the data I got from the server.
I'd like to get rid of steps 3 and 4, and PUSH data directly FROM the browser to jmp using that javascript xmlhttp request with a non-blocking listener in jmp that fires a callback when receiving a request and uses the data in that request to update my table. Currently my non-blocking "listener" is a loop spamming the scheduler.
Things I've read so far:
Scripting Index: Sockets
Detailed Guidance on Using JSL to get data from API
Socket communication to get and log messages from JMP, R, and python scripts
I also don't understand this: ((blobdata == Char To Blob( "" )) & (Left(r[2], 11) == "WOULDBLOCK:" ))
what is r[2]? The value of these things keeps indexing to different stuff ? In python I'd be expecting to say something like:
r = request
my_dict.update({'last_jmp_data':pd.DataFrame(request.json)})
That works in python to retrieve my data, but when I try to pass back to JMP, the only thing that prints is the headers, I can't access the JSON data I sent. I'm assuming that my data is in some r[#] item?
I'm trying to make something non blocking that can receive data, right now I'm using a hacky solution with the scheduler to create the workflow and it DOES work, but it's clunky.
I use the scheduler to keep this function scheduled, this hits my flask server, receives back data as JSON and updates my main table the update makes JMP drop all the filters so we log that to a string and then re-apply it so the user doesn't lose what they were doing.
What I'd like is to be able to SEND a request from javascript, and pick it up with JMP:
This is my JavaScript function, I don't need any reply I just want it to go to JMP. Previously I was using a different JavaScript workaround to write a JSON file to my downloads and using my scheduler loop to watch the users download folder for a specific JSON file to update the table with.
This application is a single user app that runs locally on the users PC and does not communicate to any external resource, I just needed to make my GUI/certain data interactions in a browser, but I still want to get that data back into JMP for my chimeric JMP/HTML/JS/CSS application.
Javascript code I use to send data to my python server from browser, I'd like to send this straight to JMP and do my update when it arrives.
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://localhost:8081', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send([my_json_data]);
Jmp scheduler loop
//scheduled loop to ping python local server and see if it's time to update:
get_remote_update = Function({},
s = Schedule(.25,
//show("remote update fn");
//check_downloads_folder(); // old routine that was watching download folder
check_downloads_over_ip();
get_remote_update(); //loops by scheduling the event again
);
jmp call to python server receive JSON data and update if needed.
//****************************************************************
//check_downloads_OVER_IP();
//****************************************************************
// EXPLORE THIS dt = Open( Char To Blob( request << Send() ), "JSON" );
// see if we can just get the response back into a table without creating it with the weird JMP thing
check_downloads_over_ip = Function({},
request = New HTTP Request(
URL("localhost:8088/get_update"),
Method("Post"),
Timeout( .5 ),
);
data=request << Send;
if((data != "No Update" > 0) & ( isempty(data) != 1 ),
obj = JSON:Parse( data );
dt = JSON:Make Table(obj);
dt << show window(0);
temp_dtf = CHAR(dtf <<get script);
temp_dtf_str = substitute(temp_dtf,"Current Data Table()","summary_jmp_table");
temp_dtf_parsed = parse(temp_dtf_str);
summary_jmp_table << Update( With(dt), Match Columns( :col_name = :col_name ));
(filter_hlb <<Child) << Delete Box;
//filter_hlb
ldfExpr = Eval Expr( filter_hlb << Append( dtf =temp_dtf_parsed ));
Eval( ldfExpr );
Close( dt, No Save );
);
);
//******************************************
Socket Scripts I don't understand especially this part: //Write whatever is received to the log
It prints the headers in the log, but I can't access the JSON data I sent.
Names default to here( 1 );
//Table to hold received data
dtLog = New Table( "Log",
New Column( "Time", Numeric, "Continuous", Format( "m/d/y h:m:s", 23, 0 ),
Input Format( "m/d/y h:m:s", 0 ) ),
New Column( "Client", Character, "Nominal" ),
New Column( "Message", Character, "Nominal" )
);
//Wait for and get data from remote machine
receivedata = Function( {c, waittime = 1, waitcount = 10},
//Varaible to store data received from remote machine
blobdata = Char To Blob( "" );
//Make socket is connected
r = c << GetPeerName();
//While receiving data or waiting to receive data
i = 0;
While(
(
(r[2] == "ok") |
((blobdata == Char To Blob( "" )) & (Left(r[2], 11) == "WOULDBLOCK:" ))
) &
(i < waitcount),
i++;
//Get data
r = c << recv( 100000 );
//If no data is received yet, wait
If(Left(r[2], 11) == "WOULDBLOCK:", Wait( waittime ) );
//Write whatever is received to the log
show("writing to log now");
Write( Blob to Char( r[3] ) );
show("Done writing to log now");
//join data to whatever is already received
blobdata = blobdata || r[3];
);
return( blobdata );
);
//Get log info from remote machine, store it in a data table
processlogconnection = function( {c},
//New row in log table
dtLog << Add Rows( 1 );
rowout = N Rows( dtLog );
Column( dtLog, "Time" )[rowout] = Today();
//Get computer name of remote machine
r = c << GetPeerName();
Column( dtLog, "Client" )[rowout] = r[3];
//Get message from the remote machine
Column( dtLog, "Message" )[rowout] = Blob to Char( receivedata( c ) );
//Close the connection
c << Close;
);
//Function to accept conections from remote machine, calls another
//function to handle communication with that machine
callbackfn = function( {x},
//Call another function with the connection returned from the Accept message
If( x[2] == "ok", processlogconnection( x[4] ) );
);
//Create a socket
con = Socket();
//Use a specific port on this computer
con << Bind( "localhost", "8081" );
//Tell this socket to be ready for other sockets to connect to it
Write( "\!nlistening on ", (con << getSockName)[3]);
con << Listen();
//Verify that the connection is active
con << getsockname;
//When something connects to this socket, call a function to handle
//the connection. Accept connections for the next 5 minutes.
con << Accept(callbackfn, 30000);
//Now messages can be sent to this connection.
//When all done, close the connection
//con << close();