He estado leyendo los ejemplos de sockets, pero todo lo que puedo hacer para que JMP haga es acusar recibo de una solicitud, no puedo obtener la carga útil o el mensaje de la solicitud.¿Hay una mejor manera que los sockets o el programador para lograr una comunicación sin bloqueos?
Todo está en las ventanas.
Básicamente mi flujo de trabajo es:
- Renderizar una página HTML con JMP,
- interactuar con los datos usando javascript, html, css
- pasar el resultado a un servidor python Flask usando la solicitud Javascript XMLHTTP
- Haga ping continuamente al servidor Flask con jmp a través del programador para ver si el servidor Flask tiene algún dato esperándome, si es así, Python devolverá los datos y JMP lo obtendrá como respuesta, si no es así, entonces jmp obtiene la cadena ' sin actualización' y yo solo devolver .
- Actualice la tabla JMP con los datos que obtuve del servidor.
Me gustaría deshacerme de los pasos 3 y 4, y PUSH datos directamente DESDE el navegador a jmp usando esa solicitud javascript xmlhttp con un oyente sin bloqueo en jmp que activa una devolución de llamada cuando recibe una solicitud y usa los datos en esa solicitud para actualizar mi tabla. Actualmente, mi "oyente" sin bloqueo es un bucle que envía spam al programador.
Cosas que he leído hasta ahora:
Índice de secuencias de comandos: sockets
Orientación detallada sobre el uso de JSL para obtener datos de la API
Comunicación de socket para obtener y registrar mensajes de secuencias de comandos JMP, R y python
Yo tampoco entiendo esto: ((blobdata == Char To Blob( "" )) & (Left(r[2], 11) == "WOULDBLOCK:" ))
¿Qué es r[2]? ¿El valor de estas cosas sigue indexando cosas diferentes? En python, esperaría decir algo como:
r = solicitud
mi_dict.update({ 'último_jmp_datos' :pd.DataFrame(solicitud.json)})
Eso funciona en python para recuperar mis datos, pero cuando trato de volver a pasar a JMP, lo único que se imprime son los encabezados, no puedo acceder a los datos JSON que envié. Supongo que mis datos están en algún r[#] elemento?
Estoy tratando de hacer algo que no bloquee y pueda recibir datos, en este momento estoy usando una solución pirateada con el programador para crear el flujo de trabajo y SÍ funciona, pero es torpe.
Utilizo el programador para mantener esta función programada, esto llega a mi servidor de matraz, recibe datos como JSON y actualiza mi tabla principal. La actualización hace que JMP elimine todos los filtros, por lo que registramos eso en una cadena y luego lo volvemos a aplicar para que el usuario no pierde lo que estaban haciendo.
Lo que me gustaría es poder ENVIAR una solicitud desde javascript y recogerla con JMP:
Esta es mi función de JavaScript, no necesito ninguna respuesta, solo quiero que vaya a JMP. Anteriormente, usaba una solución alternativa de JavaScript diferente para escribir un archivo JSON en mis descargas y usaba mi ciclo de programador para ver la carpeta de descarga de los usuarios para un archivo JSON específico con el que actualizar la tabla.
Esta aplicación es una aplicación de un solo usuario que se ejecuta localmente en la PC de los usuarios y no se comunica con ningún recurso externo, solo necesitaba hacer mi GUI/ciertas interacciones de datos en un navegador, pero aún quiero recuperar esos datos en JMP para mi aplicación quimérica JMP/HTML/JS/CSS.
El código Javascript que uso para enviar datos a mi servidor Python desde el navegador, me gustaría enviar esto directamente a JMP y hacer mi actualización cuando llegue.
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://localhost:8081', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send([my_json_data]);
Bucle del programador Jmp
//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
);La llamada jmp al servidor python recibe datos JSON y actualiza si es necesario.
//****************************************************************
//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=""></GET>
Socket Scripts No entiendo especialmente esta parte: //Escribe todo lo que se recibe en el registro
Imprime los encabezados en el registro, pero no puedo acceder a los datos JSON que envié.
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();
Puede usar la solicitud HTTP de JMP para hacer ping al servidor Flask. Eso eliminaría un nivel de complejidad de lo que quieres hacer.
Puede consultar el servidor con solicitudes HTTP (supongo que una operación GET) y leer la respuesta directamente con el retorno (como una carga JSON) y luego, cuando esté listo, use la solicitud HTTP nuevamente (probablemente como GET) y procesar los datos de el servidor. Por supuesto, si está utilizando sockets, en lugar de HTTP/HTTPS, querrá seguir con su enfoque de socket.
Además, los sockets de JMP no admiten https, solo http. Son envoltorios bastante delgados alrededor del código de socket de bajo nivel y no saben nada sobre el protocolo http: tiene que construirlo todo usted mismo. Hay un ejemplo completo en el índice de secuencias de comandos:
The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.The "listen" example is self-contained.El ejemplo de "escuchar" es autónomo.
Es bastante difícil construir un servidor web en JSL. Si ya está usando Python de JMP, eche un vistazo a Archivo de proyecto para Jelly Video especialmente el NumberServer. Necesitaba ejecutar varias copias de JMP para producir las imágenes del video y necesitaba una forma de entregarles el trabajo que tenían que hacer. El servidor de números hizo eso y proporcionó la instrumentación para un tablero JSL para que pudiera saber cuándo algo necesitaba atención. (Creo que ese servidor Python tenía un solo subproceso, lo que resultó ser algo bueno para servir números únicos para solicitudes simultáneas. Al menos nunca noté un duplicado...)
Esto suena prometedor: javascript también puede hacer websockets de forma nativa.
¿Se puede ejecutar el programa para obtener datos en JMP sin bloqueo? Pensé que mientras tiene el programa externo ejecutando su interfaz gráfica de usuario de JMP se bloquearía.
De esa página:
Note: If you use Run Program() to launch a GUI program, JMP is inoperable until you close the program
Editar: ¡De hecho, ya descargué esto y traté de entenderlo una vez! Le daré otra oportunidad.
¿No es eso lo que estoy haciendo actualmente?
Solo estoy interesado en los sockets porque parece ser una forma de crear un oyente que no bloquee en comparación con mi mecanismo actual de transmisión de solicitudes HTTP GET de JMP a Flask cada medio segundo para ver si el contenido del navegador web cambió por la interacción del usuario. Espero EMPUJAR un evento de matraz o javascript a JMP sin que JMP pida nada por sí mismo.
función check_downloads_over_ip() //obtener http
Y el get_remote_update(). // ciclo del planificador
get_remote_update() mantiene la función check_downloads constantemente programada en el programador como un mecanismo para que sea "en tiempo real"
El problema es que el planificador no es una forma muy elegante de generar un comportamiento sin bloqueo.
Me gustaría que JMP se siente a escuchar (sin bloqueo) y luego puedo enviar una solicitud http desde javascript directamente en el navegador a JMP y eliminar el servidor del matraz por completo.
El quid es que JMP tiene las herramientas para EXTRAER datos de un servidor y luego trabajar con la respuesta, pero ¿puedo EMPUJAR un evento desde el navegador o el servidor a JMP sin que JMp solicite nada primero?
Quitaré toda la IP de mi aplicación y publicaré un video para dejar más claro lo que busco.
RunProgram puede ejecutar N programas externos, de forma concurrente y asíncrona. Si JMP está inactivo, los N RunPrograms pueden ejecutar sus scripts ReadFunction() a medida que reciben datos en stdin, y pueden escribir datos a través de stdout. Si Python es el programa que está ejecutando RunProgram, el stdin de Python es el stdout de RunProgram y ...stdout...stdin. (N probablemente no puede ser más grande que unos pocos 10).
RunProgram puede ejecutar cosas como Excel, pero eso bloqueará. RunProgram es mucho mejor para programas de línea de comandos con stdin y stdout. Puede usar cmd.exe, o puede usar plink para abrir un shell en una máquina Linux remota. O puede ejecutar un C o Python u otro programa de lenguaje propio.
RunProgram tiene dos modos de operación: si tiene ReadFunction("texto") entonces se ejecuta en modo de bloqueo, recolectando todo el stdout y devolviendo una cadena. De lo contrario, se ejecuta en modo sin bloqueo y devuelve un objeto RunProgram. que debes conservar en una variable (de lo contrario, se eliminará antes de que finalice el proceso).
Solo hay unos pocos comandos que puede enviar a un objeto RunProgram; puede preguntar sobre la conexión y enviar y recibir datos.
No suelo usar el programador para este tipo de cosas porque quiere tener una ventana abierta, pero mira Noticias . El mismo artículo muestra cómo usar el comando de inicio de CMD para ejecutar el navegador msedge sin el comportamiento de bloqueo.
He escrito servidores en JSL (mismo artículo), pero creo que es mucho mejor usar una solución python o python+flask. Si usa un matraz, intente esto: deje que RunProgram inicie el código Python+flask y dé a RunProgram algo de lógica en su función de lectura y escritura para comunicarse con el código python (stdin/stdout). En el código de python, agregue un hilo para hablar con JMP. El servidor del matraz tiene su propio subproceso para atender las solicitudes http. Si el servidor necesita enviar algo a jmp, debe señalar un evento al subproceso JMP que imprimirá algo a JMP. Es posible que desee un subproceso de Python más que sea un subproceso de lector, escuchando JMP.