J'ai lu les exemples de sockets, mais tout ce que je peux faire pour que JMP accuse réception d'une demande, je ne peux pas obtenir la charge utile ou le message de la demande.Existe-t-il un meilleur moyen que les sockets ou le planificateur pour obtenir une communication non bloquante ?
Tout est sur les fenêtres.
Fondamentalement, mon flux de travail est :
- Rendre une page HTML avec JMP,
- interagir avec les données en utilisant javascript, html, css
- transmettre le résultat à un serveur python Flask à l'aide de la requête Javascript XMLHTTP
- Envoyez un ping continu au serveur Flask avec jmp via le planificateur pour voir si le serveur Flask a des données qui m'attendent, si c'est le cas, python renverra les données et JMP les obtiendra en réponse, si ce n'est pas le cas, jmp obtient la chaîne ' pas de mise à jour' et je viens retour .
- Mettre à jour la table JMP avec les données que j'ai obtenues du serveur.
Je voudrais me débarrasser des étapes 3 et 4, et PUSH les données directement DU navigateur vers jmp en utilisant cette requête javascript xmlhttp avec un écouteur non bloquant dans jmp qui déclenche un rappel lors de la réception d'une requête et utilise les données dans cette requête pour mettre à jour mon tableau. Actuellement, mon "auditeur" non bloquant est une boucle qui spamme le planificateur.
Ce que j'ai lu pour l'instant :
Index des scripts : sockets
Conseils détaillés sur l'utilisation de JSL pour obtenir des données à partir de l'API
Communication par socket pour obtenir et consigner les messages des scripts JMP, R et Python
Je ne comprends pas non plus ceci : ((blobdata == Char To Blob( "" )) & (Left(r[2], 11) == "WOULDBLOCK:" ))
qu'est-ce que r[2] ? La valeur de ces choses continue d'indexer sur différentes choses ? En python, je m'attendrais à dire quelque chose comme:
r = demande
mon_dict.update({ 'dernière_jmp_données' :pd.DataFrame(request.json)})
Cela fonctionne en python pour récupérer mes données, mais lorsque j'essaie de revenir à JMP, la seule chose qui s'imprime est les en-têtes, je ne peux pas accéder aux données JSON que j'ai envoyées. Je suppose que mes données sont dans certains r[#] élément ?
J'essaie de faire quelque chose de non bloquant qui peut recevoir des données, en ce moment j'utilise une solution hacky avec le planificateur pour créer le flux de travail et ça marche, mais c'est maladroit.
J'utilise le planificateur pour garder cette fonction planifiée, cela frappe mon serveur de flacon, reçoit les données en retour en tant que JSON et met à jour ma table principale la mise à jour oblige JMP à supprimer tous les filtres afin que nous enregistrions cela dans une chaîne, puis réappliquons-le pour que l'utilisateur ne perd pas ce qu'ils faisaient.
Ce que j'aimerais, c'est pouvoir ENVOYER une requête à partir de javascript et la récupérer avec JMP :
Ceci est ma fonction JavaScript, je n'ai pas besoin de réponse, je veux juste qu'elle aille dans JMP. Auparavant, j'utilisais une solution de contournement JavaScript différente pour écrire un fichier JSON dans mes téléchargements et j'utilisais ma boucle de planificateur pour regarder le dossier de téléchargement des utilisateurs pour un fichier JSON spécifique avec lequel mettre à jour la table.
Cette application est une application mono-utilisateur qui s'exécute localement sur le PC de l'utilisateur et ne communique avec aucune ressource externe. J'avais juste besoin de créer mon interface graphique/certaines interactions de données dans un navigateur, mais je souhaite toujours récupérer ces données dans JMP pour mon application chimérique JMP/HTML/JS/CSS.
Code Javascript que j'utilise pour envoyer des données à mon serveur python à partir du navigateur, j'aimerais l'envoyer directement à JMP et faire ma mise à jour quand elle arrivera.
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://localhost:8081', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send([my_json_data]);
Boucle du planificateur 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
);l'appel jmp au serveur python reçoit les données JSON et les met à jour si nécessaire.
//****************************************************************
//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 Je ne comprends pas spécialement cette partie: //Écrit tout ce qui est reçu dans le journal
Il imprime les en-têtes dans le journal, mais je ne peux pas accéder aux données JSON que j'ai envoyées.
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();
Vous pouvez utiliser la requête HTTP de JMP pour envoyer un ping au serveur Flask. Cela supprimerait un niveau de complexité de ce que vous voulez faire.
Vous pouvez interroger le serveur avec des requêtes HTTP (je suppose une opération GET) et lire la réponse directement avec le retour (comme une charge utile JSON), puis lorsqu'elle est prête, utilisez à nouveau la requête HTTP (probablement en tant que GET) et traitez les données de le serveur. Bien sûr, si vous utilisez des sockets plutôt que HTTP/HTTPS, vous devrez vous en tenir à votre approche socket.
De plus, les sockets de JMP ne prennent pas en charge https, uniquement http. Ce sont des enveloppes assez minces autour du code de socket de bas niveau et ne connaissent rien au protocole http : vous devez tout construire vous-même. Il y a un exemple complet dans l'index de script :
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'exemple "écouter" est autonome.
Il est assez difficile de construire un serveur Web en JSL. Si vous utilisez déjà Python de JMP, consultez Fichier de projet pour Jelly Video en particulier le NumberServer. J'avais besoin d'exécuter plusieurs copies de JMP pour produire les images de la vidéo et j'avais besoin d'un moyen de leur confier le travail qu'ils devaient faire. Le serveur de numéros a fait cela et a fourni l'instrumentation d'un tableau de bord JSL afin que je puisse dire quand quelque chose avait besoin d'attention. (Ce serveur python était monothread, je pense, ce qui s'est avéré être une bonne chose pour servir des numéros uniques pour des requêtes simultanées. Au moins, je n'ai jamais remarqué de doublon...)
Cela semble prometteur, javascript peut également créer des websockets en mode natif.
Le programme d'exécution peut-il obtenir des données dans JMP de manière non bloquante ? Je pensais que pendant que le programme externe exécutait votre interface graphique JMP, il serait bloqué ?
À partir de cette page :
Note: If you use Run Program() to launch a GUI program, JMP is inoperable until you close the program
Edit : En fait, je l'ai déjà téléchargé et j'ai essayé de le comprendre une fois ! Je vais lui donner un autre coup.
N'est-ce pas ce que je fais actuellement ?
Je ne m'intéresse qu'aux sockets car cela semble être un moyen de créer un écouteur non bloquant par rapport à mon mécanisme actuel de diffusion des requêtes HTTP GET de JMP vers Flask toutes les demi-secondes pour voir si le contenu du navigateur Web a changé à partir de l'interaction de l'utilisateur. J'espère POUSSER un événement de flacon ou javascript vers JMP sans que JMP ne demande quoi que ce soit par lui-même.
fonction check_downloads_over_ip() //http get
ET le get_remote_update(). // boucle du planificateur
get_remote_update () maintient la fonction check_downloads constamment planifiée dans le planificateur en tant que mécanisme pour la rendre "en temps réel"
Le problème est que le planificateur n'est pas un moyen très élégant de générer un comportement non bloquant.
J'aimerais que JMP reste à l'écoute (de manière non bloquante), puis je peux envoyer une requête http de javascript directement dans le navigateur à JMP et éliminer complètement le serveur de flacon.
Le point crucial est que JMP a les outils pour extraire les données d'un serveur, puis travailler avec la réponse, mais puis-je pousser un événement du navigateur ou du serveur vers JMP sans que JMp ne demande quoi que ce soit au préalable.
Je supprimerai toute l'adresse IP de mon application et publierai une vidéo pour clarifier ce que je veux faire.
RunProgram peut exécuter N programmes externes, simultanément et de manière asynchrone. Si JMP est autrement inactif, les N RunPrograms peuvent exécuter leurs scripts ReadFunction() lorsqu'ils reçoivent des données sur stdin, et ils peuvent écrire des données via stdout. Si Python est le programme exécuté par RunProgram, le stdin de Python est le stdout de RunProgram et ...stdout...stdin. (N ne peut probablement pas être supérieur à quelques dizaines.)
RunProgram peut exécuter des choses comme Excel mais cela bloquera. RunProgram est bien meilleur pour les programmes en ligne de commande avec stdin et stdout. Vous pouvez utiliser cmd.exe, ou vous pouvez utiliser plink pour ouvrir un shell sur une machine Linux distante. Ou vous pouvez exécuter votre propre programme C ou Python ou un autre langage.
RunProgram a deux modes de fonctionnement : s'il a ReadFunction("text"), il s'exécute en mode bloquant, collectant toutes les stdout et renvoyant une chaîne. Sinon, il s'exécute en mode non bloquant et renvoie un objet RunProgram que vous devez conserver dans une variable (sinon elle sera supprimée avant la fin du processus.)
Il n'y a que quelques commandes que vous pouvez envoyer à un objet RunProgram ; vous pouvez poser des questions sur la connexion et envoyer et recevoir des données.
Je n'utilise généralement pas le planificateur pour ce genre de chose car il veut avoir une fenêtre ouverte, mais voyez Fil d'actualité . Le même article montre comment utiliser la commande de démarrage CMD pour exécuter le navigateur msedge sans le comportement de blocage.
J'ai écrit des serveurs en JSL (même article), mais je pense qu'il est bien préférable d'utiliser une solution python ou python+flask. Si vous utilisez flask, essayez ceci : laissez RunProgram lancer le code Python + flask et donnez à RunProgram une logique dans sa fonction de lecture et sa fonction d'écriture pour communiquer avec le code python (stdin/stdout). Dans le code Python, ajoutez un thread pour parler à JMP. Le serveur flask a son propre thread pour traiter les requêtes http. Si le serveur doit envoyer quelque chose à jmp, il doit signaler un événement au thread JMP qui imprimera quelque chose à JMP. Vous voudrez peut-être un autre thread Python qui soit un thread de lecture, à l'écoute de JMP.