Ein in Perl geschriebener Pidgin-Plugin ignoriert dröge Börsentage, an denen die Kurse stillstehen, aber schlägt per Instant Message Alarm, falls die Aktien anfangen, Achterbahn zu fahren.
Der flexible Instant-Messenger-Client Pidgin [1] läuft nicht nur auf grundsätzlich verschiedenen Plattformen with Linux und Windows, sondern unterstützt auch eine Vielzahl unterschiedener Instant-Messaging-(IM-)Protokolle. Ob Yahoo oder MSN, ob Google Talk oder IRC, Pidgin bringt alle unter einen Hut und vereinfacht die Kommunikation mit Online-Freunden, die unterschiedliche Angebote nutzen. Pidgins Plugin-Architektur trägt maßgeblich dazu bei, dass der Tausendsassa mit plötzlich geänderten Protokollen mithält und seinen Abdeckungsradius stetig erweitert.
Dabei ist es nicht einmal notwendig, Plugins in Pidgins Muttersprache C zu schreiben und als Shared Libs bereitzustellen. Auch in Hochsprachen wie Perl geschriebene Skripts bindet er klaglos ein, und falls sie mit Pidgins Glib-basierter Event-Loop zusammenarbeiten, dürfen sie sogar langwierige Operationen wie das Einholen von Webseiten ausführen, ohne dass Pidgins graphische Oberfläche zu ruckeln anfängt. Auf den ersten Blick erscheint es zwar verrückt, dass ein C-Programm zusammen mit einem Perlskript im Sprungseiltakt in derselben Eventschleife hüpft, es wird aber klarer, wenn man sich vergegenwärtigt, dass Perl letztlich auch nur ein Abstraktionslayer über einer C-Schicht ist und deshalb genausogut Events einhängen und empfangen kann.
Abbildung 1: Der Aktienmarktwecker alarmiert den User, weil die Google-Aktie um mehr als 2% gestiegen ist. |
Abbildung 2: In der YAML-Datei setzt der User bestimmte Aktien auf eine Beobachtungsliste und gibt bei Bedarf Prozentpunkte vor. |
Der heute vorgestellte Pidgin-Plugin zeigt sich zunächst nicht, nimmt aber in regelmäßigen Abständen Kontakt mit einem Stockticker-Service auf und untersucht, ob einer der in einer Konfigurationsdatei abgelegten Aktienwerte anfängt, wild nach oben zu streben oder kräftig an Wert zu verlieren. Tritt dies ein, öffnet der Plugin ein Kommunikationsfenster zum eingeloggten User nach Abbildung 1 und zeigt die Gesamtliste aller überwachten Aktien an, samt den einzelnen prozentualen Tagesänderungen. Der User darf in der Konfigurationsdatei nach Abbildung 2 vorgeben, welche Aktienkürzel ihn interessieren und ab welcher prozentualen Änderung ein Weckruf erfolgen soll. Bei Zeilen, die lediglich das Aktienkürzel und keine Prozentzahl vorgeben, nimmt der Plugin automatisch 2% an.
Der Plugin, den Pidgin lädt, falls das entsprechende Perl-Skript mit .pl-Endung ausführbar im richtigen Verzeichnis liegt und der User ihn anschließend im Plugin-Menü konfiguriert (siehe Abschnitt Installation), gestaltet sich mit 74 Zeilen relativ simpel, wie Listing 1 zeigt.
Er muss die von der Pidgin-API vorgeschriebenen Callbacks
plugin_init()
und plugin_load()
definieren. Erstere
springt Pidgin an, um Informationen über den Plugin einzuholen, um diese
später im Menü Tools->Plugins anzuzeigen und den User per Mausklick
entscheiden zu lassen, ob er den Plugin aktivieren möchte. Passiert
dies, kommt der Callback plugin_load
ab Zeile 43 zum Zug, der die
Aufgaben des Plugins definiert. Deaktiviert der User den Plugin wieder,
erledigt dieser in plugin_unload()
eventuell noch letzte Aufräumarbeiten,
bevor Pidgin ihn aus dem Speicher wirft.
Das weiter unten beschriebene Modul WatchQuotes liest die Konfigurationsdatei,
sobald Zeile 50 im Plugin dessen init()
-Methode aufruft. Zeile 51 startet
anschließend den
kontinuierlich arbeitenden Überwachungsprozess mit dem
Aufruf der Methode watch()
. Ihr überreicht das Plugin-Skript eine
Referenz auf den ab Zeile 55 definierten Callback quotes_update
, der
eine ihm übergebene Nachricht in eine IM-Konversation verpackt und dem
verblüfften User schickt.
01 #!/usr/local/bin/perl -w 02 use strict; 03 04 use Pidgin; 05 use local::lib; 06 use Glib; 07 use WatchQuotes; 08 09 our %PLUGIN_INFO = ( 10 perl_api_version => 2, 11 name => "Pidgin Stockwatch", 12 summary => "Stock Alert via IM", 13 version => "1.0", 14 author => "Mike Schilli " . 15 "<m\@perlmeister.com>", 16 load => "plugin_load", 17 unload => "plugin_unload", 18 ); 19 20 our $USER = "mikeschilli"; 21 our $PROTOCOL = "prpl-yahoo"; 22 23 our $WATCH_QUOTES = WatchQuotes->new(); 24 25 ########################################### 26 sub plugin_init { 27 ########################################### 28 return %PLUGIN_INFO; 29 } 30 31 ########################################### 32 sub plugin_unload { 33 ########################################### 34 my($plugin) = @_; 35 36 Purple::Debug::info("stockwatch", 37 "Plugin unloaded.\n"); 38 39 1; 40 } 41 42 ########################################### 43 sub plugin_load { 44 ########################################### 45 my($plugin) = @_; 46 47 Purple::Debug::info("stockwatch", 48 "Plugin loaded.\n"); 49 50 $WATCH_QUOTES->init(); 51 $WATCH_QUOTES->watch( \"es_update ); 52 } 53 54 ########################################### 55 sub quotes_update { 56 ########################################### 57 my($msg) = @_; 58 59 Purple::Debug::info("stockwatch", 60 "Updating Quotes.\n"); 61 62 my $account = Purple::Accounts::find( 63 $USER, $PROTOCOL); 64 65 my $conv = Purple::Conversation->new( 66 1, $account, $USER); 67 68 # user not online? 69 return unless defined $conv; 70 71 $conv->get_im_data->write( 72 $PLUGIN_INFO{name}, $msg, 73 0, time ); 74 }
Dazu findet die Methode find()
eines Purple::Account-Objektes in
Zeile 62 den hoffentlich eingeloggten User, und Zeile 65 baut zu diesem
eine Konversation auf, die sich in einem Objekt der Klasse
Purple::Conversation manifestiert. Ging dabei etwas schief, zum Beispiel
weil der festgelegte User gar nicht auf dem angegebenen Service eingeloggt
war, bricht Zeile 69 ab und die Nachricht kommt nie ans Licht.
Geht alles gut, schickt die in Zeile 71 aufgerufene write()
-Methode
die Nachricht ab und egt als Sender willkürlich den Namen des Plugins fest.
Der letzte Parameter setzt mit der Perl-Funktion time()
noch die
aktuelle Uhrzeit, die Pidgin neben jeder Nachricht anzeigt.
Die Variablen $USER und $PROTOCOL in den Zeilen 20 und 21 definieren den im Alarmfall zu benachrichtigende Usernamen und den dabei verwendeten IM-Service, im vorgegebenen Fall "prpl-yahoo", also Yahoos Messenger-Protokoll.
Was genau treibt also das Modul WatchQuotes.pm? Bei seiner Implementierung ist zu beachten, dass es mit Pidgins-Eventschleife zusammenarbeiten muss, damit auch während langlaufender Operationen wie dem Einholen einer Webseite der Glib-Kern Mauseingaben des Users verarbeitet und Pidgin nicht etwa regungslos dahindümpelt.
Hierfür bieten sich mehrere Frameworks an. POE wurde hier im Snapshot schon oft besprochen, also widmen wir uns heute mal einer neueren Entwicklung, die die coolen Kids der Perlszene ganz aufgeregt schnattern lässt: Das Framework AnyEvent bindet sich nicht direkt an eine bestimmte Eventschleife, sondern arbeitet mit einem halbem Dutzend unterschiedlicher Implementierungen zusammen.
Von Vorteil ist, dass sich so ein Modul wie WatchQuotes.pm
ganz
generisch implementieren lässt und später ohne Änderung auf allen
denkbaren Eventschleifen und Plattformen läuft. Einzige Voraussetzung
ist, dass das Hauptprogramm eine Referenz auf die verwendeten
AnyEvent-Objekte
behält, was durch das Speichern der Objektreferenz in der globalen
Variablen $WATCH_QUOTES geschieht. Dies ist notwendig,
da Pidgin die definierten Plugin-Callbacks
nur kurz aufruft und deren lokalen Variablen demnach verschwinden, sobald
der Programmfluss wieder in Pidgins Eingeweide zurückkehrt.
Ein weiterer Vorteil der lockeren Bindung durch AnyEvent
zeigt sich in der Testphase des Projekts:
Das Modul WatchQuotes.pm
lässt sich völlig unabhängig von Pidgin
testen, zum Beispiel mit einem Skript nach Listing 2.
01 #!/usr/bin/perl -w 02 use strict; 03 use local::lib; 04 use AnyEvent; 05 use WatchQuotes; 06 07 my $watcher = WatchQuotes->new(); 08 $watcher->init(); 09 $watcher->watch( \&callback ); 10 11 my $quit_program = AnyEvent->condvar; 12 $quit_program->recv; 13 14 ########################################### 15 sub callback { 16 ########################################### 17 print "$_[0]\n"; 18 }
Es erzeugt eine Instanz der Klasse WatchQuotes
und ruft die
Methode init()
auf, mit der WatchQuotes die vom User definierte
Konfigurationsdatei ~/.pidgin-stockwatch.yml
einliest und sie
intern in eine Perl-Datenstruktur umformt (Abbildung 3).
Abbildung 3: Die Perl-Repräsentation der Daten in der YAML-Datei. |
Als Beispiel einer Eventschleife bringt AnyEvent eine in Perl
implementierte mit, die im Testskript zur Ausführung kommt. Letzteres
definiert mit condvar()
eine Bedingungsvariable, der der
AnyEvent-Kernel Nachrichten schicken kann. Zeile 12 wartet mit
recv()
(=receive) auf diese Nachricht (die aber nie kommt) und
lässt derweil den AnyEvent-Kernel Events von Modulen wie
WatchQuotes
bearbeiten. Das aufgerufene Testskript holt also
in regelmäßigen Zeitabständen Börsenkurse ein und ruft, falls sich der
Kurs einer der überwachten Aktien über die in der Konfigurationsdatei
festgelegten Grenzwerte hinausbewegt, den ab Zeile 15 definierten
Callback mit einer Tabelle formatierter Börsenkurse auf. Die
Funktion print
in Zeile 17 gibt die Nachricht jeweils auf STDOUT
aus. Das Skript läuft weiter, bis der User es mit CTRL-C abbricht.
So lassen sich etwaige Fehler in Ruhe ausmerzen bevor das Skript in der feindlichen Pidgin-Umgebung läuft, in der Debuggen nur sehr eingeschränkt möglich ist, besonders, wenn Pidgin den Plugin aus irgendwelchen Gründen gar nicht korrekt lädt.
Das Modul WatchQuotes.pm
selbst definiert zunächst Perl-typisch einen Konstruktor new()
,
der lediglich das Home-Directory des Users herausfindet und im
Objekthash einige Standardwerte wie den Namen der Konfigurationsdatei
festlegt.
001 ########################################### 002 package WatchQuotes; 003 # Mike Schilli, 2010 (m@perlmeister.com) 004 ########################################### 005 use strict; 006 use warnings; 007 use AnyEvent; 008 use AnyEvent::HTTP; 009 use YAML qw(LoadFile); 010 011 ########################################### 012 sub new { 013 ########################################### 014 my($class, %options) = @_; 015 016 my ($home) = glob "~"; 017 018 my $self = { 019 watcher => undef, 020 data => {}, 021 refdata => {}, 022 conf_file => 023 "$home/.pidgin-stockwatch.yml", 024 conf => {}, 025 %options, 026 }; 027 028 bless $self, $class; 029 } 030 031 ########################################### 032 sub init { 033 ########################################### 034 my($self) = @_; 035 036 my $yml = LoadFile( $self->{conf_file} ); 037 038 for my $e ( @$yml ) { 039 if( ref $e eq "HASH") { 040 my($key, $val) = %$e; 041 $val =~ s/%//g; 042 $self->{conf}->{ $key } = $val; 043 } else { 044 # 2% by default 045 $self->{conf}->{ $e } = 2; 046 } 047 } 048 } 049 050 ########################################### 051 sub watch { 052 ########################################### 053 my($self, $cb) = @_; 054 055 $self->{watcher} = AnyEvent->timer ( 056 after => 10, 057 interval => 300, 058 cb => sub { 059 $self->fetch( $cb ); 060 }, 061 ); 062 } 063 064 ########################################### 065 sub fetch { 066 ########################################### 067 my($self, $cb) = @_; 068 069 my $url = "http://" . 070 "download.finance.yahoo.com/d/" . 071 "quotes.csvr?e=.csv" . 072 "&f=spl1p2&s=" . 073 join('+', sort keys %{ $self->{conf} }); 074 075 http_get($url, sub { 076 $self->parse_csv( $_[0] ); 077 $self->check( $cb ); 078 }); 079 } 080 081 ########################################### 082 sub parse_csv { 083 ########################################### 084 my($self, $csv) = @_; 085 086 for my $line ( split /\n/, $csv ) { 087 088 my($symbol, $prev, $last, $change) = 089 map { s/[^\w\.-]//g; $_ } 090 split /,/, $line; 091 092 next unless defined $symbol; 093 094 $symbol = lc $symbol; 095 096 $self->{data}->{$symbol} = 097 [ $prev, $last, $change ]; 098 } 099 } 100 101 ########################################### 102 sub check { 103 ########################################### 104 my($self, $cb) = @_; 105 106 if(!scalar keys %{ $self->{refdata} }) { 107 $self->{refdata} = {%{$self->{data}}}; 108 } 109 110 for my $stock (keys %{ $self->{data}} ) { 111 if( $self->noteworthy( $stock ) ) { 112 $self->{refdata} = { 113 %{$self->{data}} }; 114 115 # reset 'prev' 116 for my $s ( 117 keys %{$self->{refdata}} ) { 118 $self->{refdata}->{$s}->[0] = 119 $self->{data}->{$s}->[1]; 120 } 121 122 $cb->( $self->message ); 123 last; 124 } 125 } 126 } 127 128 ########################################### 129 sub message { 130 ########################################### 131 my($self) = @_; 132 133 my $msg = "\n"; 134 135 for my $stock (keys %{ $self->{data} }) { 136 my($prev, $last, $change) = 137 @{ $self->{data}->{$stock} }; 138 $msg .= "$stock: $last $change%\n"; 139 } 140 141 return $msg; 142 } 143 144 ########################################### 145 sub noteworthy { 146 ########################################### 147 my($self, $stock) = @_; 148 149 my $price_ref = 150 $self->{refdata}->{$stock}->[0]; 151 152 my $price_now = 153 $self->{data}->{$stock}->[1]; 154 155 my $change_percent = abs( 156 ($price_now - $price_ref))/ 157 $price_ref*100; 158 159 return($change_percent > 160 $self->{conf}->{$stock}); 161 } 162 163 1;
Die ab Zeile 32 definierte Methode init()
liest die Konfiguration
mit der Funktion LoadFile
ein, die aus dem YAML-Modul vom CPAN stammt.
Das in Abbildung 2
sichtbare YAML-Format hat den Vorteil, dass es sowohl vom Menschen als
auch Maschinen gleichermaßen leicht zu lesen ist. Die Applikation
erlaubt sowohl einfache Array-Einträge (zum Beispiel "- amzn"), wie
auch kleine Hashes (zum Beispiel "- goog: 2%"), die YAML als
Referenz auf einen Hash ("goog" => "2%") speichert unter dem
Array-Eintrag speichert. Zeile 39 prüft, ob Perls ref-Funktion das
Wort "HASH" zurückliefert, was auf eine Hashreferenz hindeutet. Kommt
statt dessen der Leerstring zurück, handelt es sich um einen
einfachen Skalar und Zeile 45 setzt einen Standard-Schwellwert von 2%
fest.
Die überwachten
Aktienkürzel speichert das Modul unter dem Eintrag conf
im
Objekthash und ordnet ihnen die konfigurierten prozentualen
Triggerwerte zu.
Die Methode watch
ab Zeile 51 erzeugt einen periodisch
unterbrochenen Timer. Der Parameter after
mit dem Wert 10 gibt
an, dass der Timer den unter cb
definierten Callback genau 10
Sekunden nach dem Start aufruft. Grund für die gewollte
Verzögerung ist, dass der Plugin eventuell schon startet, bevor der User
im IM-Netzwerk ansprechbar ist. Eine verfrüht geschickte Nachricht
käme aber nicht an. Der Parameter interval
gibt
mit dem Wert 300 an, dass der Timer den Callback nach dem ersten
Aufruf alle 300 Sekunden (also alle 5 Minuten) abermals anspringt, um
die neuesten Börsenkurse vom Yahoo-Server einzuholen und die Kurse
auf Sprünge zu untersuchen.
Die der Methode watch()
übergebene
Referenz auf eine Callbackfunktion zeigt
auf die Funktion quotes_update()
des Hauptskripts und wird zur
Methode fetch
durchgereicht, die die Webseite mit den Kursen
einholt. Dies kann bei stürmischem Internetwetter naturgemäß ein paar
Sekunden dauern, doch die in Zeile 75 aufgerufene Funktion http_get
stammt aus dem Fundus des Moduls AnyEvent::HTTP vom CPAN und arbeitet
den Request asynchron ab. Sie nimmt den URL für den Stockservice und
einen Callback entgegen, den sie anspringt, falls die Internetdaten
vollständig eingetrudelt sind. Zu beachten ist dabei, dass Perl den
Programmfluss sofort nach dem Aufruf von http_get()
fortsetzt, ohne
dass zu diesem Zeitpunkt die angeforderten HTTP-Daten vorliegen.
Wie die Dokumentation des CPAN-Moduls Finance-YahooQuote verrät, bietet
Yahoo eine Fülle von Parametern an, von denen das Modul WatchQuotes.pm
folgende auswählt:
s Symbol p Previous Close l1 Last Trade (Price Only) p2 Change in Percent
Neben dem Tickersymbol liefert der Server also den Vortageskurs, den aktuellen Kurs, sowie die prozentuale Änderung. Zusammengesetzt verlangt WatchQuotes also "spl1p2" und falls der User Google und Yahoo-Aktien verlangt hat, hängt der Code "s=goog+yahoo" dahinter. Zurück kommen die Daten im CSV-Format, also zum Beispiel zwei Zeilen Text wie etwa
"GOOG",467.49,475.83,"+1.78%" "YHOO",14.89,14.94,"+0.34%"
welche der aus einfachen regulären Ausdrücken aufgebaute
Parser in der Methode parse_csv
in eine Datenstruktur
umformt. Im Hash-Eintrag data
des WatchQuotes-Objektes steht dann
eine Referenz auf einen Array, der jeweils den Vortageskurs, den
letzten verfügbaren Kurs (üblicherweise um 20 Minuten verzögert) und
die Änderung in Prozent enthält.
Ob die bislang erfolgten Schwankungen des Kurses an der Börse eine
Benachrichtigung des Users rechtfertigen, prüft die Methode check
ab
Zeile 102. Auch sie erhält den Callback weitergereicht, der den User
eventuell per IM-Message kontaktieren kann. Zeile 106 kopiert die
aktuell eingelesenen Daten im Objekteintrag {data}
in das Archiv
unter {refdata}
, damit der Code später eine Referenz zum Vergleich
parat hat. Dabei reicht es nicht, die Referenz zu kopieren. Stattdessen
kopiert
{ %{ $self->{data} } };
die hinter der Referenz $self->{data} stehenden Daten, formt daraus einen neuen Hash und gibt eine Referenz darauf zurück.
Lagen schon vor dem Aufruf Archivdaten vor, passt die for-Schleife
ab Zeile 116 die Einträge für den Vortageskurs auf den aktuellen Kurs
an. Schließlich soll der Code bei einer gestiegenen Aktie nicht alle
fünf Minuten einen neue Nachricht schicken, sondern nur, falls sich der
Kurs weiter verschiebt und erneut den eingestellten
Schwellenwert überschreitet. Die Methode noteworthy()
prüft, ob
ein Aktienkurs den eingestellten Schwellenwert gegenüber dem
Vortageskurs (oder dem als Vortageskurs gesetzten Tageskurs, falls
vorher schon ein Alarm ausgelöst wurde) überschritten hat.
Die Methode message()
ab Zeile 129 formatiert in diesem Fall
die Daten aller
überwachten Aktien zu einem Textstring und Zeile 122 ruft den Callback
auf, der im Hauptprogramm den User per IM alarmiert.
Gängige Linux-Distributionen wie Ubuntu bieten Pidgin
als Paket an, das auch die Perl-Schnittstelle schon enthält
(pidgin
und libpurple0
unter Ubuntu, beide in Version 2.7.0). Das
Plugin-Skript pidgin-stockwatch.pl
wandert dann ausführbar ins
Verzeichnis ~/.purple/plugins
unter dem Home-Verzeichnis des Users.
Das Modul WatchQuotes.pm
landet unter einem Pfad,
den die lokale Perl-Installation findet. Notfalls weist der Skript-Code,
wie in Zeile 7 von Listing 1, mit der Anweisung 'use lib' auf die
entsprechende Stelle im Dateisystem hin.
Die Module AnyEvent und AnyEvent::HTTP haben sich noch nicht bei den bekannten Distros durchgesetzt und müssen deshalb vom CPAN installiert werden. Damit zusätzliche CPAN-Module nicht die sauberen Perl-Pakete des Linux-Package-Managers vollkleistern, installiert der ordnungsliebende User sie mittels des CPAN-Moduls local::lib unter dem Pfad "~/perl5" im Home-Verzeichnis. Nach
perl Makefile.PL --bootstrap make test && make install
in der local::lib-Distribution hängt der ordnungsliebende Admin die Ausgabe von
perl -I$HOME/perl5/lib/perl5 \ -Mlocal::lib
an die lokale .bashrc-Datei an. Nach einem Neustart der Shell (oder
dem Sourcen der .bashrc-Datei) setzt local::lib so eine Reihe von
Environment-Variablen, die die CPAN-Shell anweisen, zusätzliche
Module unter ~/.perl5
zu installieren. Die Variablen weisen
auch aufgerufene Perl-Skripte
auf zusätzliche Suchpfade hin, doch Pidgin weiß davon nichts
und benötigt eine explizite 'use lib'
-Anweisung.
Das Plugin-Skript in Listing 1 lässt sich übrigens nicht ohne Pidgin starten und wirft, falls man es doch versucht, mit wirren Fehlermeldungen um sich, die andeuten, dass es bestimmte Glib-Funktionen nicht in den entsprechenden shared Libraries findet. Laut Pidgin-Entwicklern ist das normal, doch aus Entwicklersicht natürlich ätzend. Abhilfe schafft sich der findige Hacker, indem er die Zeilen 'use Pidgin' und 'use Glib' auskommentiert und mit "perl -c pidgin-stockwatch.pl" wenigstens prüft, ob die Syntax stimmt und das Skript das Modul WatchQuotes.pm sowie die darin aufgerufenen CPAN-Module findet.
Dokumentation zum Schreiben von Pidgin-Plugins ist rar. Zwar hat Pidgin-Chefentwicker Sean Egan ein Buch zum Thema "Building and Extending Gaim" geschrieben, doch nicht nur der Name des Projekts hat sich seit dem geändert (aus Gaim wurde Pidgin), sondern auch kaum ein Funktionsaufruf oder eine Datenstruktur sind konstant geblieben, sodass sich das sehr gut geschriebene Werk allenfalls zum Studium der Pidgin-Architektur eignet. Auch die Online-Dokumentation lässt in punkto Aktualität schwer zu wünschen übrig ([2], [3]), und die automatisch generierte Doxygen-Dokumentation ist, wie so oft, lieblos zusammengeschustert, unvollständig, und damit ebenfalls für die Katz. Die effektivste Methode, die in der aktuellen Pidgin-Version erforderlichen Parameter zu einem Funktionsaufruf zu finden, ist das Studium real existierenden Plugins neuerer Bauart, wie zum Beispiel [4].
Wird pidgin
mit pidgin -d
im Debug-Modus aufgerufen, erscheinen
Debug-Schnipsel im Code wie
Purple::Debug::info("stockwatch", "Plugin loaded.\n");
auf dem Bildschirm und man kann zumindest sehen, was der Plugin
treibt und ob Pidgin ihn überhaupt findet. Klappt dies, und er führt
zumindest die plugin_init
-Routine ab Zeile 26 aus,
erscheint der Plugin im Pidgin-Menü Tools-Plugins
unter dem in Zeile 11
angegebenen Namen Pidgin Stockwatch
(Abbildung 4). Ein Mausklick auf
die linksseitige Checkbox aktiviert den Plugin und führt dessen
plugin_load
-Routine aus. Testweise kann man den Plugin auch
deaktivieren, worauf er plugin_unload
(Zeile 32) ausführt.
Abbildung 4: Ein Mausklick aktiviert den neu installierten Plugin, den Pidgin im "Plugins"-Menü anzeigt. |
Anschließend füllt der Aktienspekulant die Konfigurationsdatei
~/.pidgin-stockwatch.yml
mit den Tickersymbolen der interessierenden
Aktien und weist ihnen Prozentwerte zu oder akzeptiert den voreingestellten
Trigger bei 2%. Nach einem Neustart arbeitet Pidgin mit den aktualisierten
Werten.
Statt amerikanischer Aktien wie in Abbildung 1 lassen sich natürlich auch
an deutschen Märkten gehandelte Werte angeben, wie zum Beispiel SIE1.de
,
das Symbol der Siemens-Aktie, die an der XETRA-Börse in Euro gehandelt wird.
Obwohl die Chance, dass Siemens sich an einem Tag um 2% bewegt,
natürlich gering ist, doch falls es tatsächlich
passiert, weiß der User sofort Bescheid
und kann entsprechende Panikverkäufe in Angriff nehmen.
Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2010/09/Perl
Pidgin, der vielseitige Instant-Messenger-Client: http://pidgin.im
Kurze Anleitung zum Schreiben von Pidgin-Plugins in Perl: http://developer.pidgin.im/doxygen/dev/html/perl-howto.html
Beispiel-Plugin in Perl: http://code.google.com/p/pidgin-knotifications/downloads/detail?name=knotifications.pl&can=2&q=
Weitere 3rd-Party Plugins: http://developer.pidgin.im/wiki/ThirdPartyPlugins#DevelopmentofThird-PartyPlugins
CPAN-Modul für Yahoo-Börsenservice: http://search.cpan.org/~edd/Finance-YahooQuote-0.24/YahooQuote.pm
Michael Schilliarbeitet als Software-Engineer bei Yahoo! in Sunnyvale, Kalifornien. Er hat "Goto Perl 5" (deutsch) und "Perl Power" (englisch) für Addison-Wesley geschrieben und ist unter mschilli@perlmeister.com zu erreichen. Seine Homepage: http://perlmeister.com. |