lundi 31 août 2009

Premiers pas avec Ocsigen

Je voulais m'y mettre depuis longtemps, à ce serveur web. Or, justement, j'avais un petit projet en tête pour me délasser d'AdH: un système de documentation.


Ocsigen est donc un serveur web écrit en Ocaml, qui charge des modules basés sur le framework Eliom. Ocsigen est performant, mais surtout force un typage extrêmement fort du HTML en lui-même, et des liens entre les différents services. Enfin, l'on pourra réutiliser tout le code Ocaml existant, à condition de le faire rentrer dans le modèle de thread, basé sur une bibliothèque de threads coopératifs, Lwt.

Le gros problème d'Ocsigen, c'est qu'en dehors de la documentation, point de salut, ou si peu.

La documentation en elle-même est complète, mais manque furieusement d'exemples si l'on sort un tant soit peu des sentiers battus, et il faut pas mal d'efforts pour commencer à comprendre la manière dont les différents éléments s'enchaînent. L'inférence de types de nos amis Hindley et Milner vient heureusement à notre secours, et il serait une très mauvaise idée d'essayer d'écrire les interfaces avec des types aussi biscornus.

La communauté, elle, est inexistante (ou du moins, très bien cachée), et les sites publics qui tournent sous Ocsigen sont rares. Heureusement, un Wiki a été écrit pour Ocsigen pour le Google Summer of Code, ce qui aide beaucoup à voir comment, par exemple, utiliser Postgresql à travers Lwt.

Il est particulièrement intéressant d'écrire des pages à travers Ocsigen, c'est une manière d'appréhender la programmation Web tout à fait différente. On finit par se faire aux types ésotériques, et j'ai rapidement écrit quelques fonctions pour faciliter l'utilisation d'éléments récurrents.

Mon système de documentation, répondant au doux nom de Médoc (Mes docs :) ), avance tout gentiment, en quelques jours j'ai déjà une base de données (avec chiffrage des données les plus sensibles!), un outil en ligne de commande pour y sauver les documents, et une page web qui permet d'effectuer des recherches et d'afficher les documents. En voici une petite capture:



La page affiche tous les documents correspondant à un terme, en se basant sur le "Full Text Search" de Postgresql. L'on affiche également les miniatures de chaque page, cliquables et qui mènent au document grandeur nature.

Un peu de CSS sera nécessaire pour rendre l'ensemble plus joli, mais le système est déjà utile, ce qui est un bon début!

vendredi 28 août 2009

Postgresql Full Text Search - Planquez ces chiffres!

Admettons que l'on veuille sauver des textes cryptés dans la colonne d'une table Postgresql. Rien de plus facile en utilisant les fonctions pgp_sym_encrypt et pgp_sym_decrypt. Jusque là, tout va bien.

Mais admettons maintenant que l'on veuille également pouvoir faire des recherches rapides sur ces textes en utilisant le Full Text Search. L'on rajoute une colonne de type tsvector, et l'on parse le texte là dedans. Patatras, votre vilain espion peut maintenant recréer le document en regardant ce champ, qui, lui, ne peut pas être crypté!

L'on peut bien sûr monter ses données sur une partition cryptée. Mais c'est compliqué, et pas facile à installer chez l'utilisateur, sans compter que tout est en clair tant que la machine est allumée.

Cependant, admettons encore (ça fait beaucoup, je sais!) que les données sensibles soient plutôt des nombres (codes secrets, identification, numéros de compte, sommes d'argent). Sans ces nombres, les documents deviennent plutôt inoffensifs. Et de plus, il est peu probable que l'on aie besoin de ces nombres pour faire des recherches. C'est parfois utile, certes ("quels sont les documents qui contiennent mon numéro de compte?"), mais on pourra s'en passer.

Ça tombe bien, il est possible de créer une nouvelle configuration qui escamotera ce genre de données. Il suffit d'enlever la correspondance entre les types de tokens et le parseur.

Ajoutons donc la configuration french_safe:

create text search configuration french_safe ( copy = pg_catalog.french );
alter text search configuration french_safe drop mapping for int;
alter text search configuration french_safe drop mapping for uint;
alter text search configuration french_safe drop mapping for float;
alter text search configuration french_safe drop mapping for numword;

Alors que de la configuration de base, tout un tas de données sensibles auraient pu être extraites:


select * from to_tsvector(
'french',
'mon code secret est le 12345 et j''ai 217.45 € sur mon compte')
=> "'12345':6 '217.45':10 'cod':2 'compt':13 'secret':3"


la nouvelle configuration, elle, garde nos petits secrets bien au chaud!

select * from to_tsvector(
'french_safe',
'mon code secret est le 12345 et j''ai 217.45 € sur mon compte')
=> "'cod':2 'compt':11 'secret':3"


Faites donc un peu tourner des phrases sous ts_debug, et voyez comment les nombres et les mélanges chiffres lettres (mots de passes!) sont gentiment effacés.

lundi 17 août 2009

Trading

Petit aperçu de ce que va donner la GUI de trading



L'idée est de permettre au joueur de choisir lui-même la disposition des éléments d'interface, à travers l'utilisation du wxAuiNotebook de chez wxWidgets. Pour l'instant, il n'existe que deux types de composants: la liste des marchandises, et l'inventaire. Je vais y ajouter le carnet d'ordres, et enfin la visualisation des prix du marché en temps réel.

Le serveur est séparé du serveur de jeu AdH, ce qui me permet d'être plus léger, et d'identifier les composants partagés pour les mettre dans une bibliothèque à part. A terme, je devrais avoir migré de nombreux composants, rendus génériques, vers cette bibliothèque, ce qui devrait permettre de créer très facilement des serveurs spécifiques, voire de monter des clusters. Mais pour le moment, j'essaie de trouver un gameplay sympa pour la partie trading. Je compte bien que ça soit le souk, dans le sens premier du terme!

lundi 10 août 2009

Postgresql 8.4 et les requêtes récursives

La fonctionnalité de Postgres 8.4 que je préfère, c'est les requêtes récursives. Voilà vraiment quelque chose qui va permettre de résoudre bon nombre de problèmes de manière beaucoup plus élégante, et notamment tout ce qui concerne les arbres, les graphes, et les hiérarchies de toutes sortes.

Voici par exemple un arbre où chaque élément pointe vers son parent.


create table h(entry int not null, parent int null);

insert into h values(1, null);
insert into h values(2, 1);
insert into h values(3, 1);
insert into h values(4, 1);
insert into h values(5, 1);
insert into h values(6, 2);
insert into h values(7, 2);
insert into h values(8, 6);
insert into h values(9, 8);
insert into h values(10, 4);


Maintenant, répondons à la question: Quels sont tous les éléments enfants de l'élément 2? Avec le SQL récursif, c'est trivial:


with recursive deep(n) as(
select entry from h where entry = 2
union
select entry from h join deep on h.parent = deep.n
)
select * from deep;


Le premier élément de l'union est l'amorce de la récursion: l'on démarre donc avec l'élément 2. Le second élément est la récursion en elle-même: l'on retourne l'ensemble des éléments qui sont parents de l'élément n.

La documentation contient quelques exemples beaucoup plus compliqués, où l'on explore des graphes cycliques, avec un SQL qui devient franchement ésotérique. Mais pour des cas simples, c'est un très bon moyen de se débarrasser des couches de pl/pgsql ou autres, et de revenir en pur SQL, ce qui pourrait entre autres améliorer les performances en permettant au planificateur de travailler directement sur toutes les tables.

A propos de planificateur, le nouveau pgadmin3 (malheureusement pas encore dans Squeeze, mais cela ne saurait tarder) montre de bien jolies choses sur ces requêtes récursives. Voici donc l'explain de ma requête.



En faisant quelques tests supplémentaires, je me suis rendu compte que Postgres utilisait gentiment les index qu'on lui donnait sur les colonnes "entry" et "parent", ce qui permettait de gagner environ 25% de temps sur de très grosses requêtes (arbre de 100 000 éléments). Elle est pas belle, la vie?

jeudi 6 août 2009

Postgresql 8.4 débarque dans Debian Squeeze

C'est en faisant mon "aptitude update; aptitude dist-upgrade" hebdomadaire que j'ai vu avec joie que Postgresql 8.4 allait arriver. Vu qu'apparemment, la 8.3 allait jarter du même coup, je suis allé faire mon petit backup, et j'ai lancé la mise à jour.

Tout c'est bien passé, sauf pour Mediawiki qu'il a fallu un poil bidouiller. En effet, en recréant l'utilisateur wikiuser (souvenez-vous du mot de passe!), l'on perd le "search path" vers le schéma "mediawiki", et l'application se met à se plaindre qu'elle ne trouve pas ses tables. Heureusement, la résolution est aisée:


alter user wikiuser set search_path = mediawiki,public;


Et voilà!