Ho letto gli esempi di socket, ma tutto quello che posso fare per JMP è riconoscere di aver ricevuto una richiesta, non riesco a ottenere il payload o il messaggio della richiesta.Esiste un modo migliore dei socket o dello scheduler per ottenere comunicazioni non bloccanti?
Tutto è su Windows.
Fondamentalmente il mio flusso di lavoro è:
- Renderizza una pagina HTML con JMP,
- interagire con i dati utilizzando javascript, html, css
- passare il risultato a un server Python Flask utilizzando la richiesta Javascript XMLHTTP
- Eseguire continuamente il ping del server Flask con jmp tramite lo scheduler per vedere se il server Flask ha dei dati che mi aspettano, in tal caso Python restituirà i dati e JMP li riceverà come risposta, in caso contrario jmp ottiene la stringa ' nessun aggiornamento' e io solo ritorno .
- Aggiorna la tabella JMP con i dati che ho ricevuto dal server.
Mi piacerebbe eliminare i passaggi 3 e 4 e i dati PUSH direttamente DAL browser a jmp utilizzando quella richiesta javascript xmlhttp con un listener non bloccante in jmp che attiva una richiamata quando riceve una richiesta e utilizza i dati in quella richiesta per aggiornare la mia tabella. Attualmente il mio "ascoltatore" non bloccante è un loop che invia spam allo scheduler.
Cose che ho letto finora:
Indice di scripting: socket
Guida dettagliata sull'utilizzo di JSL per ottenere dati dall'API
Comunicazione socket per ottenere e registrare messaggi da script JMP, R e python
anche io non capisco questo: ((blobdata == Char To Blob( "" )) & (Left(r[2], 11) == "WOULDBLOCK:" ))
cos'è r[2]? Il valore di queste cose continua a indicizzare cose diverse? In Python mi sarei aspettato di dire qualcosa del tipo:
R = domanda
my_dict.update({ 'last_jmp_data' :pd.DataFrame(request.json)})
Funziona in Python per recuperare i miei dati, ma quando provo a tornare a JMP, l'unica cosa che stampa sono le intestazioni, non riesco ad accedere ai dati JSON che ho inviato. Presumo che i miei dati siano in alcuni r[#] elemento?
Sto cercando di creare qualcosa di non bloccante che possa ricevere dati, in questo momento sto usando una soluzione hacky con lo scheduler per creare il flusso di lavoro e FUNZIONA, ma è goffo.
Uso lo scheduler per mantenere questa funzione pianificata, questo colpisce il mio server flask, riceve i dati di ritorno come JSON e aggiorna la mia tabella principale l'aggiornamento fa sì che JMP elimini tutti i filtri, quindi lo registriamo in una stringa e quindi lo riapplichiamo in modo che l'utente non perde quello che stavano facendo.
Quello che mi piacerebbe è poter INVIARE una richiesta da javascript e raccoglierla con JMP:
Questa è la mia funzione JavaScript, non ho bisogno di alcuna risposta, voglio solo che vada su JMP. In precedenza stavo utilizzando una soluzione alternativa JavaScript diversa per scrivere un file JSON nei miei download e utilizzando il mio ciclo di pianificazione per guardare la cartella di download degli utenti per un file JSON specifico con cui aggiornare la tabella.
Questa applicazione è un'app per utente singolo che viene eseguita localmente sul PC dell'utente e non comunica con alcuna risorsa esterna, avevo solo bisogno di effettuare la mia GUI/alcune interazioni di dati in un browser, ma voglio comunque recuperare quei dati in JMP per la mia chimerica applicazione JMP/HTML/JS/CSS.
Codice Javascript che utilizzo per inviare dati al mio server Python dal browser, vorrei inviarlo direttamente a JMP e fare il mio aggiornamento quando arriva.
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://localhost:8081', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send([my_json_data]);
Ciclo programmatore 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
);jmp chiama al server python riceve i dati JSON e aggiorna se necessario.
//****************************************************************
//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>
Script socket non capisco soprattutto questa parte: //Scrive tutto ciò che viene ricevuto nel registro
Stampa le intestazioni nel registro, ma non riesco ad accedere ai dati JSON che ho inviato.
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();
È possibile utilizzare la richiesta HTTP di JMP per eseguire il ping del server Flask. Ciò eliminerebbe un livello di complessità di ciò che vuoi fare.
Puoi interrogare il server con richieste HTTP (presumo un'operazione GET) e leggere la risposta direttamente con il ritorno (come un payload JSON) e quindi quando è pronto, utilizzare nuovamente la richiesta HTTP (probabilmente come GET) ed elaborare i dati da il server. Ovviamente, se stai usando i socket, piuttosto che HTTP/HTTPS, allora vorrai attenersi al tuo approccio basato sui socket.
Inoltre, i socket di JMP non supportano https, solo http. Sono involucri abbastanza sottili attorno al codice socket di basso livello e non sanno nulla del protocollo http: devi costruirlo tutto da solo. C'è un esempio completo nell'indice di scripting:
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.L'esempio "ascolta" è autonomo.
È abbastanza difficile costruire un server web in JSL. Se stai già utilizzando Python da JMP, dai un'occhiata a File di progetto per Jelly Video in particolare il NumberServer. Avevo bisogno di eseguire più copie di JMP per produrre le immagini nel video e avevo bisogno di un modo per consegnare loro il lavoro che dovevano fare. Il server dei numeri lo ha fatto e ha fornito la strumentazione per un dashboard JSL in modo da poter dire quando qualcosa richiedeva attenzione. (Quel server Python era a thread singolo, credo, il che si è rivelato una buona cosa per fornire numeri univoci per richieste simultanee. Almeno non ho mai notato un duplicato...)
Sembra promettente che anche javascript possa creare websocket in modo nativo.
Il programma in esecuzione può inserire i dati in JMP in modo non bloccante? Ho pensato che mentre hai il programma esterno in esecuzione la tua gui JMP sarebbe bloccata?
Da quella pagina:
Note: If you use Run Program() to launch a GUI program, JMP is inoperable until you close the program
Modifica: in realtà l'ho già scaricato e ho provato a capirlo una volta! Ci proverò un'altra volta.
Non è quello che sto facendo attualmente però?
Sono interessato solo ai socket perché sembra essere un modo per creare un listener non bloccante rispetto al mio attuale meccanismo di streaming di richieste HTTP GET da JMP a Flask ogni mezzo secondo per vedere se il contenuto del browser Web è cambiato dall'interazione dell'utente. Spero di PUSH un evento da flask o javascript a JMP senza che JMP chieda nulla da solo.
funzione check_downloads_over_ip() //http get
E get_remote_update(). // ciclo programmatore
get_remote_update() mantiene la funzione check_downloads costantemente pianificata nello scheduler come meccanismo per renderlo "in tempo reale"
Il problema è che lo scheduler non è un modo molto elegante per generare comportamenti non bloccanti.
Vorrei che JMP rimanesse in ascolto (in modo non bloccante) e quindi posso inviare una richiesta http da javascript direttamente nel browser a JMP ed eliminare completamente il server flask.
Il punto cruciale è che JMP ha gli strumenti per estrarre i dati da un server e quindi lavorare con la risposta, ma posso INVIARE un evento dal browser o dal server in JMP senza che JMp richieda prima nulla.
Eliminerò tutti gli IP dalla mia app e pubblicherò un video per rendere più chiaro cosa sto cercando.
RunProgram può eseguire N programmi esterni, contemporaneamente e in modo asincrono. Se JMP è altrimenti inattivo, gli N RunPrograms possono eseguire i loro script ReadFunction() non appena ricevono dati su stdin e possono scrivere dati tramite stdout. Se Python è il programma eseguito da RunProgram, lo stdin di Python è lo stdout di RunProgram e ...stdout...stdin. (N probabilmente non può essere maggiore di qualche decina.)
RunProgram può eseguire cose come Excel ma questo si bloccherà. RunProgram è molto meglio per i programmi a riga di comando con stdin e stdout. Potresti usare cmd.exe o potresti usare plink per aprire una shell su una macchina Linux remota. Oppure potresti eseguire un tuo programma C o Python o un altro linguaggio.
RunProgram ha due modalità di funzionamento: se ha ReadFunction("text") allora viene eseguito in modalità di blocco, raccogliendo tutto lo stdout e restituendo una stringa. Altrimenti viene eseguito in modalità non bloccante e restituisce un oggetto RunProgram che devi preservare in una variabile (altrimenti verrà cancellata prima che il processo finisca).
Ci sono solo pochi comandi che puoi inviare a un oggetto RunProgram; puoi chiedere informazioni sulla connessione e inviare e ricevere dati.
Di solito non uso lo scheduler per questo genere di cose perché vuole avere una finestra aperta, ma vedi Feed di notizie . Lo stesso articolo mostra come utilizzare il comando CMD start per eseguire il browser msedge senza il comportamento di blocco.
Ho scritto server in JSL (stesso articolo), ma penso che sia molto meglio usare una soluzione python o python+flask. Se usi flask, prova questo: lascia che RunProgram avvii il codice Python+flask e fornisci a RunProgram un po' di logica nella sua funzione di lettura e funzione di scrittura per comunicare con il codice python (stdin/stdout). Nel codice Python, aggiungi un thread per parlare con JMP. Il server del pallone ha il proprio thread per soddisfare le richieste http. Se il server deve inviare qualcosa a jmp, deve segnalare un evento al thread JMP che stamperà qualcosa su JMP. Potresti volere un altro thread Python che sia un thread di lettura, in ascolto per JMP.