Fonctions

Les fonctions sont un élément de base de la programmation — elles constituent un moyen pratique et puissant de regrouper les instructions qui exécutent 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 fonction 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 les 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 de comportement de protocole

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

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

En plus du contexte, les rappels de comportement peuvent avoir d’autres arguments. Habituellement, le reste des arguments sont passés 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 d’état d’instance et de fonctions 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

où,

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

Fonctions d’extension de stratégie

Comme le langage d’expression de stratégie NetScaler est fortement typé, 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 les types suivants :

function self-type:function-name(parameter1: parameter1-type, etc.): return-type
     statements
end

where,

the types are NSTEXT, NSNUM, NSBOOL, or NSDOUBLE.
<!--NeedCopy-->

self-type est le type du paramètre self implicite qui est passé dans 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 d’afficher ceci 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 ou plusieurs paramètres.

return-type est le type de la valeur renvoyée par l’appel de fonction d’extension. Ce sera l’entrée de la partie de l’expression de stratégie, le cas échéant, à droite de la fonction, ou bien est 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.1rn").COMBINE_HEADERS()

Ici, le paramètre self est le résultat de HTTP.REQ.FULL_HEADER.AFTER_STR(“HTTP/1.1rn”), 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 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 en utilisant l’instruction de fonction Lua normale. Cela déclare le nom de la fonction et les noms de ses paramètres (également connus sous le nom d’arguments), et comme toutes les déclarations dans Lua, ne spécifie aucun type. La syntaxe pour ceci est :

local function function-name(parameter1-name, parameter2-name, etc.)
     statements
end
<!--NeedCopy-->

Les noms de fonction et de paramètre sont tous des identificateurs. (Le nom de la fonction est en fait une variable et l’instruction de fonction est abrégée pour fonction locale-name = fonction (parameter1, etc.), mais vous n’avez pas à comprendre cette subtilité pour utiliser des fonctions.)

Notez que etc. est utilisé ici pour la poursuite 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 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 des valeurs à renvoyer à l’appelant de la fonction. Il doit apparaître à la fin d’un bloc (dans une fonction, si alors, pour boucle, et ainsi de suite ; Il peut être dans son propre bloc ne retourne… fin). Il peut spécifier 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-->

Appels de fonction

Un appel de fonction exécute le corps d’une fonction, en fournissant des valeurs pour ses paramètres et en recevant des résultats. La syntaxe d’un appel de fonction est function-name (expression1, expression2, etc.), où les paramètres de 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. Ainsi, vous pouvez rendre un ou plusieurs paramètres à la fin de l’appel facultatif, et votre fonction peut vérifier s’ils sont spécifiés en vérifiant s’ils ne sont pas nuls. Une façon courante de le faire est avec l’opération ou :

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 Iterator et générique pour les boucles

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

for variable in iterator(parameter1, parameter2, etc.) do
     statements in the for loop body
end
<!--NeedCopy-->

où iterator () est une fonction avec zéro ou plusieurs paramètres qui fournit une valeur pour variable sur chaque itération du corps de la boucle. La fonction itérateur garde une trace de l’endroit où elle se trouve dans l’itération en utilisant une technique appelée fermeture, dont vous n’avez pas à vous inquiéter ici. Il signale la fin de l’itération en retournant zéro. Les fonctions Iterator peuvent renvoyer plus d’une valeur, pour une utilisation dans une affectation multiple.

L’écriture d’une fonction d’itérateur dépasse le cadre de cet article, mais il existe un certain nombre d’itérateurs intégrés utiles qui illustrent le concept. L’un est l’itérateur pairs(), qui itère à travers 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 fonction string.gmatch(), qui sera utilisée dans l’exemple COMBINE_HEADERS() suivant.

Fonctions