Satimage Précédent
Communicating between Smile's
Accueil Documentation Smile Server Communicating between Smile's  
Principes

Lorsque vous établissez une communication entre deux applications Smile, l'une est un serveur et l'autre un client. Le serveur ouvre un port sur la machine sur laquelle il tourne. Le client peut être situé n'importe où : sur la même machine, sur une autre machine sur un réseau local, ou sur une machine distante connectée à internet. Le Smile client envoie des données au port du serveur et peut (ou non) attendre la réponse à sa requête.

Les données
Les données envoyées d'un Smile à un autre sont des quantités AppleScript : typiquement, une string, une list, un record. Cependant, il est préférable de ne pas envoyer de données qui ne font pas sens des deux côtés : par exemple, évitez d'envoyer un alias.
Instructions
Toutes les informations dont vous avez besoin sont dans la Suite Smile over IP du dictionnaire de Smile.
Du côté du serveur : pour ouvrir un port sur la machine du Smile serveur, utilisez la commande install server port. Vous devrez fournir un numéro de port : utilisez un nombre positif inférieur à 65535 ; les nombres inférieurs à 1024 ne sont pas recommandés. N'utilisez en aucun cas un numéro de port déjà ouvert sur votre machine.
install server port 20000 subroutine "handle_client_request"
Le nom de la fonction ("handle_client_request" dans notre exemple) doit être le nom d'une fonction existant dans le contexte, c'est-à-dire d'une fonction compilée dans un terminal AppleScript ou appartenant à une bibliothèque de scripts située dans un dossier Context additions de Smile ou chargée à l'aide de la commande add library (cf Utiliser des bibliothèques AppleScript si vous n'êtes pas familier avec les bibliothèques AppleScript dans Smile).
Dans l'exemple suivant, nous supposerons que les données envoyées par le Smile client constituent une liste AppleScript et que le serveur doit compter les éléments de cette liste.
on handle_client_request(aList)
    return (count aList)
end handle_client_request
Du côté du client : pour envoyer une requête depuis le Smile client, utilisez la commande call remote port. Spécifiez le numéro de port, l'adresse IP de la machine du Smile serveur, les données à envoyer, et une chaîne vide pour le paramètre subroutine.
call remote port 20000 at "10.0.1.2" with data {1, 2, "3"} subroutine ""
    --> 3
L'appel se fait de façon synchrone : la commande call remote port attendra la réponse du serveur et la suite du script ne pourra s'exécuter qu'après cela. (Bien évidemment, ne tentez pas d'effectuer un appel synchrone si vous utilisez la même application Smile en tant que client et que serveur).
Appels asynchrones
Dans l'exemple précédent, le travail du serveur est minimal et la réponse est quasi-instantanée. Il existe des situations dans lesquelles vous voudrez que le script continue à s'exécuter sans attendre la réponse - par exemple, vous voulez lancer un calcul très long sans bloquer le Smile client. Pour faire cela, définissez le paramètre subroutine avec une chaîne non vide.
call remote port 20000 at "10.0.1.2" with data {1, 2, "3"} subroutine "process_result"
Cet appel est asynchrone : call remote port n'attend pas de réponse et les lignes de script qui suivent sont exécutées sans délai. Lorsque le serveur répondra, la réponse sera envoyée à la fonction spécifiée ("process_result" dans notre exemple). Cette fonction doit être définie dans le contexte du Smile client.
on process_result(x)
    quietmsg(x)
end process_result
Dans cet exemple, le Smile client écrira le résultat (3) dans la Console lorsqu'il recevra la réponse du serveur.
Si vous ne souhaitez pas recevoir de réponse du tout, ne spécifiez pas de paramètre subroutine : l'appel sera asynchrone et le Smile client ne recevra jamais la réponse.
call remote port 20000 at "10.0.1.2" with data {1, 2, "3"}
Fermeture du port
En quittant, le Smile serveur fermera tous les ports qu'il a ouvert. Cependant, il est préférable de fermer explicitement les ports qui ont été ouverts en utilisant la commande remove server port.
remove server port 20000
Spécifier des fonctions n'appartenant pas au contexte global
Dans les exemples précédents, la fonction appelée du côté serveur est disponible dans le contexte global du Smile serveur. Dans certains cas vous voudrez ne pas surcharger ainsi le contexte global et vous préfèrerez appeler une routine appartenant à un script. Cette routine doit alors appartenir au script d'un objet : le script objet d'un objet (script of theObject) ou le class script d'un objet (class script of theObject). (Mais pas un script objet). Pour spécifier une telle fonction, définissez le paramètre subroutine avec un record de la façon suivante :
install server port 20000 subroutine {name:"handle_client_request", script:script of window "answering window" as integer}
Filtrages pouvant être effectués sur les ports
Pour des questions de sécurité ou pour d'autres raisons, vous pouvez préférer limiter l'appel à votre Smile serveur seulement pour un certain nombre de machines spécifiques. Pour cela, fournissez une liste d'IP (sous forme de textes) via le paramètre optionnel for de la commande install server port.
install server port 20000 subroutine "handle_client_request" for {"82.231.243.102", "17.254.3.183"}
Gestion asynchrone de requêtes
Dans certains cas, le Smile serveur n'est pas censé renvoyer une réponse immédiatement. Un exemple serait le cas d'une discussion entre utilisateurs, où la réponse du Smile serveur serait la réponse d'un utilisateur du côté serveur à envoyer à un utilisateur du côté client. Un autre exemple serait le cas d'une tâche longue à effectuer mais ne devant pas bloquer le Smile serveur : vous voudrez alors rediriger cette tâche à effectuer vers un troisième Smile de façon à ce que le Smile serveur puisse répondre à d'autres requêtes pendant que la tâche est en cours d'exécution.
Pour cela, la fonction appelée du côté serveur doit renvoyer une erreur error number -1718, qui indique au Smile client que le contenu de la réponse n'est pas encore arrivé et qu'il arrivera plus tard. Cela débloquera le Smile serveur.
Pour envoyer effectivement la réponse le moment venu, le Smile serveur doit appeler la commande resume server task, qui enverra la réponse au Smile client. Pour indiquer à quelle requête il faut répondre, resume server task doit connaître l'identifiant de la requête. Le Smile serveur reçoit l'identifiant de la requête en second paramètre de la fonction appelée par la requête.
L'exemple suivant correspond à la gestion d'un dialogue entre utilisateurs.
on handle_client_request(theMessage, theRequestID)
    set end of text of window "SmileChat" to return & theMessage
    set my replyID to theRequestID -- stocke l'identifiant dans une variable persistante
    error number -1718 -- code d'erreur spécial, spécifiant que la réponse est différée
end handle_client_request
L'appel du client doit être de la forme suivante :
call remote port 20000 at "10.0.1.2" with data "salut, c'est moi" subroutine "process_result"
Lorsque le Smile client exécute la ligne précédente, le message "salut, c'est moi" s'affichera dans la fenêtre "SmileChat" du Smile serveur, et le Smile serveur reste disponible. Lorsque l'utilisateur du côté serveur répond, la commande resume server task doit être appelée :
resume server task (get my replyID) with data "salut, ça va ?"

Si la fonction "process_result" est celle définie plus haut, la réponse de l'utilisateur situé côté serveur s'affichera dans la console du Smile client.

Dans un vrai programme, vous ne devriez pas utiliser de variable globale (my replyID) pour stocker l'identifiant de la requête, en particulier si vous souhaitez transmettre (en asynchrone) une requête longue à exécuter vers un autre Smile serveur.

Problèmes d'accessibilité des ports
Le fait qu'un port puisse ou non être appelé depuis l'extérieur dépend de votre configuration. Si les deux machines sont sur un même réseau local, vous devez simplement vérifier que les firewalls de MacOSX vous permettent d'utiliser ce port. Pour l'utiliser à travers internet, vous devez régler spécifiquement votre configuration. Par exemple si vous utilisez une borne Airport, vous devrez la configurer dans l'utilitaire d'administration d'Airport et régler les redirections de ports de façon à rediriger les requêtes sur votre machine.
Publication de ports
Si les deux machines sont sur un même réseau local, vous pouvez utiliser Bonjour (le protocole ZeroConf d'Apple) pour publier les ports que vous avez ouvert (en utilisant les commandes register et unregister server port), de façon à ce que les machines du réseau local puissent savoir quels serveurs sont disponibles (en utilisant la commande list registered ports).
English version
Copyright ©2009 Paris, Satimage