====== Vala ====== Vala est un langage de programmation compilé, qui réutilise la « plateforme » [[https://developer.gnome.org/gobject/stable/|GObject]] du projet [[http://www.gnome.org/|GNOME]]. ===== Résoudre les redirections (302) avec libsoup ===== Dans l'exemple ci-dessous, nous allons utilisé le signal **got-headers** pour savoir si une ressource est directement accessible ou une redirection (302) est mise en place. /* * valac --pkg=glib-2.0 --pkg=libsoup-2.4 redirect.vala * * Find the real URL (it even works with 302 HTTP status code). */ using GLib; using Soup; public class Request : Object { private string url; public Request (string resource) { this.url = resource; } private string get_real_uri (string resource) { Session session; Message msg; string new_url = null; /* Create Soup.* objects */ session = new Session (); msg = new Message ("GET", resource); /* Signal */ msg.got_headers.connect (() => { /* 302 */ if (msg.status_code == Status.FOUND) { new_url = msg.response_headers.get_one ("Location"); /* Finish processing request */ session.cancel_message (msg, Status.CANCELLED); } }); session.send_message (msg); if (new_url == null) { new_url = "%s".printf (resource); } return new_url; } public void send () { /* Find the real URI */ stdout.printf ("%s\n", get_real_uri (this.url)); } public static int main (string[] args) { //string uri = "http://ftp.netbsd.org/pub/NetBSD/security/advisories/NetBSD-SA2016-005.txt.asc"; //string uri = "http://rf.proxycast.org/1175697431602405376/13940-16.06.2016-ITEMA_21011329-0.mp3"; string uri = "http://www.podtrac.com/pts/redirect.mp4/201406.jb-dl.cdn.scaleengine.net/bsdnow/2016/bsd-0146.mp4"; var r = new Request (uri); r.send (); return 0; } } ===== Les expressions régulières ===== Dans cet exemple, nous allons voir comment récupérer un morceau d'une chaîne de caractères, en nommant le //pattern// comme on peut le faire sous Python. Je vous conseille de parcourir cette [[https://developer.gnome.org/glib/stable/glib-regex-syntax.html|page]] (Cf. **Named subpatterns**). /** * valac --pkg=glib-2.0 regex.vala * **/ public static int main (string[] argv) { GLib.Regex re; GLib.MatchInfo info; string data = "!system=DEVFS subsystem=CDEV type=CREATE cdev=video90"; // Python's way :) string pattern = "subsystem=CDEV type=CREATE cdev=(?Pvideo[0-9]+)"; try { re = new GLib.Regex (pattern); if (re.match (data, 0, out info)) { stdout.printf ("%s\n", info.fetch_named ("device")); } } catch (GLib.RegexError e) { stderr.printf ("Error: %s\n", e.message); } return 0; } valac --pkg=glib-2.0 regex.vala ./regex video90 ===== Afficher le nombre de cœur du processeur ===== Ce bout de code fonctionne uniquement sous **FreeBSD**. /** * Compile with: * valac --pkg=glib-2.0 cpu.vala * * Get number of core processor. **/ private static string nb_cpu (string data) { string[] tokens; string cores = null; tokens = data.split (": "); if (tokens.length == 2) { cores = tokens[1]; } return cores; } public static int main (string[] argv) { string cmd = "/sbin/sysctl hw.ncpu"; string cores; string std_err = null; int status; try { GLib.Process.spawn_command_line_sync (cmd, out cores, out std_err, out status); if (status == 0) { stdout.printf ("%s", nb_cpu (cores)); } } catch (GLib.SpawnError e) { stderr.printf ("Error: %s\n", e.message); } return 0; } ===== Fichier / dossier ===== ==== Déterminer le MIME type d'un fichier ==== On doit charger les modules **glib-2.0** et **gio-2.0**. /* * Exemple d'utilisation pour deviner le type de fichier. * * valac --pkg glib-2.0 --pkg gio-2.0 content-type.vala */ class ContentType : Object { public static int main (string[] argv) { if (argv.length == 2) { GLib.File file = File.new_for_commandline_arg (argv[1]); try { GLib.FileInfo file_info = file.query_info ( FileAttribute.STANDARD_CONTENT_TYPE, FileQueryInfoFlags.NONE, null); string content_type = file_info.get_content_type (); if (content_type == "image/png") { stdout.printf ("Ok\n"); } else { stderr.printf ("No\n"); } } catch (Error e) { stderr.printf ("%s", e.message); } } else { stderr.printf ("%s FILE\n", argv[0]); } return 0; } } On obtient pour une image PNG le résultat suivant : ./content-type ristretto.png Ok Or si l'on « porte » cette portion de code en C, le test ne va pas fonctionner, il faut utiliser la fonction [[https://developer.gnome.org/gio/stable/gio-GContentType.html#g-content-type-is-a|g_content_type_is_a]]. Depuis Vala >= 0.12 [[http://www.valadoc.org/#!api=gio-2.0/GLib.g_content_type_is_a|GLib.g_content_is_a]] est obsolète, on doit plutôt utiliser [[http://www.valadoc.org/#!api=gio-2.0/GLib.ContentType.is_a|GLib.ContentType.is_a]]. On remplace ce test dans l'exemple ci-dessus : ... if (content_type == "image/png") { stdout.printf ("Ok\n"); } else { stderr.printf ("No\n"); } ... par ... if (GLib.ContentType.is_a (content_type, "image/png")) { stdout.printf ("Ok\n"); } else { stderr.printf ("No\n"); } ... ==== Connaître le nom du répertoire courant ==== On utilise le module **glib-2.0**. public class Main : Object { public static int main (string[] argv) { string current_dir = GLib.Environment.get_current_dir (); stdout.printf ("%s\n", current_dir); return 0; } } Pour afficher le résultat de l'exemple précédent sous forme d'uri. On doit charger en plus le module **gio-2.0**. public static int main (string[] argv) { string current_dir = GLib.Environment.get_current_dir (); GLib.File file = GLib.File.new_for_path (current_dir); stdout.printf ("%s\n", file.get_uri ()); return 0; } ==== Créer un dossier ==== Il faut charger les modules **glib-2.0** et **gio-2.0**. public static int main (string[] argv) { // le nouveau dossier à créer string child_dir = "nouveau"; string current_dir = GLib.Environment.get_current_dir (); GLib.File file = GLib.File.new_for_path (string.join ("/", current_dir, child_dir)); try { // le dossier est créé maintenant file.make_directory (); } catch (GLib.Error e) { error ("%s\n", e.message); } return 0; } ===== Déterminer l'origine d'une IP ===== Cet exemple montre comment obtenir l'origine d'une IP. On doit installer utiliser les modules suivants : * glib-2.0 * libsoup-2.4 * json-glib-1.0 Le service est désormais **payant**. /* * Compile with: * valac --pkg=glib-2.0 --pkg=libsoup-2.4 --pkg=json-glib-1.0 geoip.vala * * Get country code from IP address. * */ public class GeoIP : Object { private const string HOSTNAME = "www.telize.com"; private string address; private Soup.URI uri; #if LIBSOUP_2_42 private Soup.Session session; #else private Soup.SessionSync session; #endif private Soup.Message msg; public GeoIP () { /* Create Soup.URI object */ address = "http://%s".printf (HOSTNAME); this.uri = new Soup.URI (address); /* Create session object */ #if LIBSOUP_2_42 this.session = new Soup.Session (); #else this.session = new Soup.SessionSync (); #endif } public void run (string resource) { string content = null; content = send_query (resource); if (content != null) { parse_json (content); } } private void parse_json (string data) { Json.Parser parser; Json.Node node; unowned Json.Object obj; parser = new Json.Parser (); try { parser.load_from_data (data); } catch (GLib.Error e) { stderr.printf ("Error: '%s'\n", e.message); } node = parser.get_root (); if (node.get_node_type () == Json.NodeType.OBJECT) { obj = node.get_object (); foreach (unowned string name in obj.get_members ()) { if (name == "country_code") { unowned string item; item = obj.get_string_member (name); stdout.printf ("%s\n", item.down ()); } } } } private string send_query (string resource) { string content = null; this.uri.set_path ("/%s".printf (resource)); msg = new Soup.Message.from_uri ("GET", this.uri); this.session.send_message (msg); #if VALA_0_22 if (Soup.Status.OK == msg.status_code) { #else if (Soup.KnownStatusCode.OK == msg.status_code) { #endif content = (string) msg.response_body.flatten ().data; } return content; } } void main (string[] argv) { string path = "geoip"; GeoIP ip; ip = new GeoIP (); ip.run (path); }