Fichiers et DB

De Base de connaissances eggdrops & TCL

Cet article fait suite au message que j'avais posté sur le forum concernant les fichiers utilisés comme bases de données.

Quel que soit le format d'enregistrement des données, il faut avant tout réfléchir à la structure. Car utiliser MySQL ou un fichier ne fait que peu de différences sur le principe, c'est uniquement la mise en application qui va différer.

L'énoncé

Le but est de faire un système de gestion de niveaux d'accès par utilisateur et par canal, en utilisant des fichiers comme base de données.

Hypothèses

La première idée du demandeur était d'avoir un seul fichier, qu'il ne sait pas concevoir (ni moi d'ailleurs). Mon idée était d'avoir 3 fichiers, et finalement je suis venu à penser qu'un seul fichier suffisait.

Solution "3 fichiers"

Cette solution séparait les utilisateurs, les canaux et les niveaux des utilisateurs sur les canaux. Les 3 fichiers sont du type csv (champs séparés par une virgule) et on a donc:

  • fichier utilisateur
    • nick
    • password
    • autre info
  • fichier canaux
    • canal
    • description
    • autre info
  • fichier niveaux
    • nick
    • canal
    • niveau

On le constate vite, les deux premiers fichiers peuvent rapidement être remplacés par les bases internes de l'eggdrop qui gère déjà les utilisateurs et les canaux.

Solution "fichier unique"

Elle se résume donc à n'avoir que le dernier fichier, mais impose que l'utilisateur s'authentifie auprès de l'eggdrop.

On vérifie alors que le fichier contient une ligne commençant par le nick et le canal, et le dernier élément est le niveau d'accès.

Mise en pratique

En se basant sur la dernière hypothèse, qui est la plus pratique car elle évite les données redondantes, on peut développer un petit script.

Le script doit faire 3 actions:

  • Vérifier que le canal existe
  • Vérifier l'utilisateur (il existe et il est bien authentifié)
  • Vérifier que l'utilisateur a des droits sur ce canal

Cela peut donc faire un script très simple:

# la commande est /msg eggdrop !auth nick password chan
bind msg - "!auth" authenticate

proc authenticate { nick uhost handle args } {
   if { [llength $args] != 3 } {
      puthelp "PRIVMSG $nick :la commande est /msg $::botnick !auth nick password chan"
      return 0
   }
   set unick [lindex $args 0]
   set upass [lindex $args 1]
   set uchan [lindex $args 2]
   if { ![validchan $uchan] } {
      puthelp "PRIVMSG $nick :Je ne connais pas $uchan"
      return 0
   }
   if { ![authUser $unick $upass] } {
      # authUser est votre fonction pour authentifier l'utilisateur
      puthelp "PRIVMSG $nick :Erreur sur le nick ou le password"
      return 0
   }
   # Donc ici, on sait que le canal existe et que l'utilisateur peut potentiellement se connecter
   # On va donc chercher ses droits
   set level 0; # On initialise le niveau à 0
   set fp [open "niveaux.db" r]
   set urights [read -nonewline $fp]; # On met le contenu du fichier dans une variable
   foreach line [split $urights "/n"] { # On boucle sur chaque ligne
      if { [string first $line "$unick,$uchan,"] == 0 } { # La ligne commence par nick,#canal
         set level [lindex [split $line ","] 2]; # On change le niveau des droits
         close $fp
         return $level; # On retourne le niveau, plus la peine de boucler
      }
   }
   close $fp
   return 0; # On retourne 0 : pas d'accès trouvé pour le nick sur le #canal
}

Autre méthode

On aurait pu se passer de la boucle et appliquer une expression régulière sur $urights pour trouver "\n$unick,$uchan,(\d{1,})\n", mais autant rester dans le principe basique.