Fonctions

Les fonctions sont un élément de base de la programmation. Elles constituent un moyen pratique et puissant de regrouper des instructions exécutant une tâche. Il s’agit de l’interface entre l’appliance Citrix ADC et le code d’extension. Pour les stratégies, vous définissez des fonctions d’extension de stratégie. Pour les protocoles, vous implémentez des fonctions de rappel pour les comportements de protocole. Les fonctions sont constituées de définitions de fonctions qui spécifient quelles valeurs sont passées dans et hors de la fonction et quelles instructions sont exécutées pour la fonction, et d’appels de fonction, qui exécutent des fonctions avec des données d’entrée spécifiques et obtiennent des résultats de la fonction.

Fonctions de rappel du comportement du protocole

Le comportement du client TCP consiste en une fonction de rappel (on_data) qui traite les événements de flux de données du client TCP. Pour implémenter l’équilibrage de charge basé sur les messages (MBLB) pour un protocole TCP, vous pouvez ajouter du code pour cette fonction de rappel afin de traiter le flux de données TCP provenant du client et d’analyser le flux d’octets en messages de protocole.

Les fonctions de rappel d’un comportement sont appelées avec un contexte, qui correspond à l’état du module de traitement. Le contexte est l’instance du module de traitement. Par exemple, les rappels du comportement du client TCP sont appelés avec différents contextes pour différentes connexions TCP clientes.

En plus du contexte, les fonctions de rappel de comportement peuvent comporter d’autres arguments. Habituellement, le reste des arguments est passé en tant que charge utile, qui est la collection de tous les arguments. Ainsi, les instances du module de traitement programmable peuvent être considérées comme une combinaison de fonctions d’état d’instance et de rappel d’événement, c’est-à-dire le contexte et le comportement. Et le trafic circule à travers le pipeline comme charge utile d’événement.

Prototype de la fonction de rappel client TCP :



                Function                client on_data (ctxt, payload)

                                                //.code

                end


<!--NeedCopy-->

Où,

  • ctxt - Contexte de traitement du client TCP
  • payload — charge utile d’événement
    • payload.data : données TCP reçues, disponibles sous forme de flux d’octets

Fonctions d’extension de stratégie

Étant donné que le langage d’expression de stratégie NetScaler est tapé, la définition d’une fonction d’extension doit spécifier les types de ses entrées et sa valeur de retour. La définition de la fonction Lua a été étendue pour inclure ces types :


function self-type: function-name(parameter1: parameter1-type, and so on): return-type
     statements
end

<!--NeedCopy-->

Où,

Les types sont NSTEXT, NSNUM, NSBOOL ou NSDOUBLE.

Self-type est le type de l’auto-paramètre implicite qui est passé à la fonction. Lorsque la fonction d’extension est utilisée dans une expression de stratégie Citrix ADC, il s’agit de la valeur générée par l’expression située à gauche de la fonction. Une autre façon de voir cela est que la fonction étend ce type dans le langage de stratégie Citrix ADC.

Les types de paramètres sont les types de chaque paramètre spécifié dans l’appel de fonction d’extension dans l’expression de stratégie. Une fonction d’extension peut avoir zéro paramètre ou plus.

Type de retour est le type de la valeur renvoyée par l’appel de la fonction d’extension. Il s’agit de l’entrée de la partie de l’expression de stratégie, le cas échéant, à droite de la fonction, ou bien de la valeur du résultat de l’expression.

Exemple :

function NSTEXT:COMBINE_HEADERS() : NSTEXT

Utilisation de la fonction d’extension dans une expression de stratégie :

HTTP.REQ.FULL_HEADER.AFTER_STR("HTTP/1.1\r\n").COMBINE_HEADERS()

Ici, l’auto-paramètre est le résultat de HTTP.REQ.FULL_HEADER.AFTER_STR("HTTP/1.1\r\n"), qui est une valeur de texte. Le résultat de l’appel COMBINE_HEADERS () est du texte, et comme il n’y a rien à droite de cet appel, le résultat de l’expression entière est du texte.

Définition de la fonction locale

Outre les fonctions d’extension, aucune fonction globale ne peut être définie dans un fichier d’extension. Mais les fonctions locales peuvent être définies dans les fonctions d’extension à l’aide de l’instruction normale de la fonction Lua. Cela déclare le nom de la fonction et les noms de ses paramètres (également appelés arguments), et comme toutes les déclarations de Lua, ne spécifie aucun type. La syntaxe est la suivante :


local function function-name(parameter1-name, parameter2-name, and so on)
     statements
end

<!--NeedCopy-->

Les noms des fonctions et des paramètres sont tous des identificateurs. (Le nom de la fonction est en fait une variable et l’instruction de fonction est un raccourci pour nom-fonction locale = fonction (paramètre1, etc.), mais vous n’avez pas besoin de comprendre cette subtilité pour utiliser des fonctions.)

Notez que, et ainsi de suite, est utilisé ici pour la continuation du modèle des noms de paramètres au lieu de l’habituel…. C’est parce que… lui-même signifie en fait une liste de paramètres variables, qui ne sera pas discutée ici.

Corps de fonction et retour

Le bloc d’instructions entre la fonction et les instructions de fin est le corps de la fonction. Dans le corps de la fonction, les paramètres de la fonction agissent comme des variables locales, avec des valeurs fournies par les appels de fonction, comme décrit précédemment.

L’instruction return fournit les valeurs à renvoyer à l’appelant de la fonction. Il doit apparaître à la fin d’un bloc (dans une fonction, si c’est le cas, pour la boucle, etc.). Il peut être dans son propre bloc do return… end). Il ne spécifie aucune, une ou plusieurs valeurs de retour :


return -- returns nil
return expression -- one return value
return expression1, expression2, ... -- multiple return values

<!--NeedCopy-->

Exemples :


local function fsum(a)
     local sum = 0
     for i = 1, #a do
          sum = sum + a[i]
     end
     return sum
end

Local function fsum_and_average(a)
     local sum = 0
     for i = 1, #a do
          sum = sum + a[i]
     end
     return sum, sum/#a
end

<!--NeedCopy-->

Les appels de fonctions

Un appel de fonction exécute le corps d’une fonction, fournit des valeurs pour ses paramètres et reçoit des résultats. La syntaxe d’un appel de fonction est nom-fonction (expression1, expression2, etc.), où les paramètres de la fonction sont définis sur les expressions correspondantes. Le nombre d’expressions et de paramètres ne doit pas nécessairement être le même. S’il y a moins d’expressions que de paramètres, les paramètres restants sont définis sur zéro. Vous pouvez donc rendre un ou plusieurs paramètres facultatifs à la fin de l’appel, et votre fonction peut vérifier s’ils sont spécifiés en vérifiant s’ils ne sont pas nuls. Une méthode courante consiste à utiliser l’opération OR :


function f(p1, p2) -- p2 is optional
     p2 = p2 or 0 -- if p2 is nil, set to a default of 0
     . . .
end

<!--NeedCopy-->

S’il y a plus d’expressions que de paramètres, les valeurs d’expression restantes sont ignorées.

Comme indiqué précédemment, les fonctions peuvent renvoyer plusieurs valeurs. Ces retours peuvent être utilisés dans une instruction d’affectation multiple. Exemple :


local my_array = {1, 2, 3, 4}
local my_sum, my_ave = sum_and_average(my_array)

<!--NeedCopy-->

Fonctions d’itérateur et boucles génériques for

Maintenant que nous avons introduit des fonctions, nous pouvons parler de boucles for génériques. La syntaxe de la boucle for générique (avec une variable) est la suivante :


for variable in iterator(parameter1, parameter2, and so on) do
     statements in the for loop body
end

<!--NeedCopy-->

Où iterator () est une fonction avec zéro ou plusieurs paramètres qui fournissent une valeur pour une variable à chaque itération du corps de la boucle. La fonction itérateur garde une trace de son emplacement dans l’itération à l’aide d’une technique appelée closure, dont vous n’avez pas à vous soucier ici. Il signale la fin de l’itération en renvoyant zéro. Les fonctions d’itérateur peuvent renvoyer plus d’une valeur, pour une utilisation dans plusieurs affectations.

L’écriture d’une fonction itérateur dépasse le cadre de cet article, mais il existe peu d’itérateurs intégrés utiles qui illustrent le concept. L’un est l’itérateur pairs (), qui parcourt les entrées d’une table et renvoie deux valeurs, la clé et la valeur de l’entrée suivante.

Exemple :


local t = {k1 = "v1", k2 = "v2", k3 = "v3"}
local a = {} -- array to accumulate key-value pairs
local n = 0 -- number of key-value pairs
for key, value in pairs(t) do
     n = n + 1
     a[n] = key.. " = ".. Value -- add key-value pair to the array
end
local s = table.concat(a, ";") -- concatenate all key-value pairs into one string

<!--NeedCopy-->

Un autre itérateur utile est la string.gmatch() fonction, utilisée dans l’ COMBINE_HEADERS() exemple suivant.

Fonctions