[tracker/miner-flickr: 1/6] Add Flickr miner
- From: Adrien Bustany <abustany src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/miner-flickr: 1/6] Add Flickr miner
- Date: Thu, 18 Mar 2010 15:01:17 +0000 (UTC)
commit c4b6685ff798bf98a3ee317a2ca50edc5b9f561f
Author: Adrien Bustany <abustany gnome org>
Date: Wed Mar 10 09:44:56 2010 -0300
Add Flickr miner
configure.ac | 32 ++
src/Makefile.am | 4 +
src/tracker-miner-flickr/Makefile.am | 64 +++
src/tracker-miner-flickr/query-queue.vala | 56 ++
src/tracker-miner-flickr/tracker-miner-flickr.vala | 583 ++++++++++++++++++++
5 files changed, 739 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 3012e71..e1b3b20 100644
--- a/configure.ac
+++ b/configure.ac
@@ -159,6 +159,7 @@ GEE_REQUIRED=0.3
ID3LIB_REQUIRED=3.8.3
GNOME_KEYRING_REQUIRED=2.26
LIBGRSS_REQUIRED=0.3
+REST_REQUIRED=0.6
# Library Checks
PKG_CHECK_MODULES(GLIB2, [glib-2.0 >= $GLIB_REQUIRED])
@@ -793,6 +794,32 @@ fi
AM_CONDITIONAL(HAVE_GNOME_KEYRING, test "x$have_gnome_keyring" = "xyes")
+##################################################################
+# Flickr miner
+##################################################################
+
+AC_ARG_ENABLE(miner_flickr,
+ AS_HELP_STRING([--miner-flickr],
+ [enable Flickr miner [[default=auto]]]),,
+ [enable_miner_flickr=auto])
+
+if test "x$enable_miner_flickr" != "xno"; then
+ PKG_CHECK_MODULES(MINER_FLICKR,
+ [ rest-0.6 >= $REST_REQUIRED ],
+ [have_miner_flickr_deps=yes],
+ [have_miner_flickr_deps=no])
+ AC_SUBST(MINER_FLICKR_LIBS)
+ AC_SUBST(MINER_FLICKR_CFLAGS)
+fi
+
+if test "x$enable_miner_flickr" = "xyes"; then
+ if test "x$have_miner_flickr_deps" != "xyes"; then
+ AC_MSG_ERROR([Couldn't find the required dependencies for the Flickr miner: rest-0.6 >= $REST_REQUIRED.])
+ fi
+fi
+
+AM_CONDITIONAL(HAVE_MINER_FLICKR, test "x$have_miner_flickr_deps" = "xyes")
+
####################################################################
# Mail miners
####################################################################
@@ -1717,6 +1744,7 @@ AC_CONFIG_FILES([
src/tracker-extract/Makefile
src/tracker-miner-fs/Makefile
src/tracker-miner-rss/Makefile
+ src/tracker-miner-flickr/Makefile
src/tracker-preferences/Makefile
src/tracker-preferences/tracker-preferences.desktop.in
src/tracker-search-bar/Makefile
@@ -1838,6 +1866,10 @@ Plugins/Extensions:
KMail plugin (data-push): $enable_kmail_miner
Miner RSS: (data-push): $enable_miner_rss
+Extra miners:
+
+ Flickr miner $have_miner_flickr_deps
+
Writeback:
MP3 writeback: $have_id3lib
diff --git a/src/Makefile.am b/src/Makefile.am
index 3823389..ff8d5c4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -42,3 +42,7 @@ endif
if USING_MINER_RSS
SUBDIRS += tracker-miner-rss
endif
+
+if HAVE_MINER_FLICKR
+SUBDIRS += tracker-miner-flickr
+endif
diff --git a/src/tracker-miner-flickr/Makefile.am b/src/tracker-miner-flickr/Makefile.am
new file mode 100644
index 0000000..f5593ef
--- /dev/null
+++ b/src/tracker-miner-flickr/Makefile.am
@@ -0,0 +1,64 @@
+include $(top_srcdir)/Makefile.decl
+
+INCLUDES = \
+ -Wall \
+ -DSHAREDIR=\""$(datadir)"\" \
+ -DPKGLIBDIR=\""$(libdir)/tracker"\" \
+ -DLOCALEDIR=\""$(localedir)"\" \
+ -DLIBEXEC_PATH=\""$(libexecdir)"\" \
+ -DG_LOG_DOMAIN=\"Tracker\" \
+ -DTRACKER_COMPILATION \
+ -I$(top_srcdir)/src \
+ $(WARN_CFLAGS) \
+ $(GMODULE_CFLAGS) \
+ $(PANGO_CFLAGS) \
+ $(DBUS_CFLAGS) \
+ $(MINER_FLICKR_CFLAGS) \
+ $(GCOV_CFLAGS)
+
+VALAFLAGS = \
+ --pkg gio-2.0 \
+ --pkg rest \
+ --pkg posix \
+ --thread
+
+libexec_PROGRAMS = tracker-miner-flickr
+
+tracker_miner_flickr_VALASOURCES = \
+ tracker-miner-flickr.vala \
+ query-queue.vala \
+ $(top_srcdir)/src/libtracker-client/tracker-client-0.7.vapi
+
+tracker_miner_flickr_SOURCES = \
+ $(tracker_miner_flickr_VALASOURCES:.vala=.c)
+
+tracker_miner_flickr_LDADD = \
+ $(top_builddir)/src/libtracker-miner/libtracker-miner- TRACKER_API_VERSION@.la \
+ $(top_builddir)/src/libtracker-client/libtracker-client- TRACKER_API_VERSION@.la \
+ $(DBUS_LIBS) \
+ $(GMODULE_LIBS) \
+ $(GTHREAD_LIBS) \
+ $(GIO_LIBS) \
+ $(GCOV_LIBS) \
+ $(GLIB2_LIBS) \
+ $(MINER_FLICKR_LIBS) \
+ -lz \
+ -lm
+
+vapi_sources = \
+ $(top_srcdir)/src/libtracker-miner/tracker-miner- TRACKER_API_VERSION@.vapi
+
+tracker-miner-flickr.vala.stamp: $(tracker_miner_flickr_VALASOURCES) $(vapi_sources)
+ $(AM_V_GEN)$(VALAC) $(GCOV_VALAFLAGS) -C $(VALAFLAGS) $^
+ touch $@
+
+
+BUILT_SOURCES = tracker-miner-flickr.vala.stamp
+
+MAINTAINERCLEANFILES = \
+ tracker-miner-flickr.vala.stamp \
+ $(tracker_miner_flickr_VALASOURCES:.vala=.c)
+
+EXTRA_DIST = \
+ $(tracker_miner_flickr_VALASOURCES) \
+ tracker-miner-flickr.vala.stamp
diff --git a/src/tracker-miner-flickr/query-queue.vala b/src/tracker-miner-flickr/query-queue.vala
new file mode 100644
index 0000000..7afeeb7
--- /dev/null
+++ b/src/tracker-miner-flickr/query-queue.vala
@@ -0,0 +1,56 @@
+public class QueryQueue : GLib.Object {
+ /* Holds the pending sparql updates and monitors them */
+ private HashTable<uint, string> queue;
+ private uint cookie;
+
+ private Mutex flush_mutex;
+
+ private Tracker.Miner miner;
+
+ public QueryQueue (Tracker.Miner parent) {
+ miner = parent;
+
+ queue = new HashTable<uint, string> (direct_hash, direct_equal);
+ cookie = 0;
+
+ flush_mutex = new Mutex ();
+ }
+
+ public async void append (string query) {
+ uint current_cookie = cookie ++;
+ queue.insert (current_cookie, query);
+
+ try {
+ yield miner.execute_batch_update (query);
+ } catch (Error tracker_error) {
+ warning ("BatchUpdate query failed: %s", tracker_error.message);
+ }
+
+ queue.remove (current_cookie);
+ }
+
+ /* BLOCKING flush */
+ public void flush () {
+ if (!flush_mutex.trylock ()) {
+ message ("There's already a flush taking place");
+ return;
+ }
+
+ if (queue.size () > 0) {
+ MainLoop wait_loop;
+ try {
+ wait_loop = new MainLoop (null, false);
+ miner.commit (null, () => { wait_loop.quit (); });
+ wait_loop.run ();
+ } catch (Error tracker_error) {
+ warning ("Commit query failed: %s", tracker_error.message);
+ }
+ }
+
+ flush_mutex.unlock ();
+ }
+
+ public uint size () {
+ return queue.size ();
+ }
+}
diff --git a/src/tracker-miner-flickr/tracker-miner-flickr.vala b/src/tracker-miner-flickr/tracker-miner-flickr.vala
new file mode 100644
index 0000000..65d38d4
--- /dev/null
+++ b/src/tracker-miner-flickr/tracker-miner-flickr.vala
@@ -0,0 +1,583 @@
+/*
+ * Copyright (C) 2010, Adrien Bustany <abustany gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+namespace Tracker {
+
+private errordomain RestCallError {
+ INVALID_RESPONSE, /* Malformed XML */
+ CALL_ERROR /* Call failed */
+}
+
+public class MinerFlickr : Tracker.MinerWeb {
+ private static const string MINER_NAME = "Flickr";
+ private static const string MINER_DESCRIPTION = "Tracker miner for Flickr";
+ private static const string API_KEY = "7983269709fa3158c752e3e4d6b3b9e5";
+ private static const string SHARED_SECRET = "c0316d1cb4b15e2d";
+ private static const string DATASOURCE_URN = "urn:2208f9fc-3c5b-4e40-ade4-45a0d7b0cf6f";
+ private static const string FLICKR_AUTH_URL = "http://api.flickr.com/services/auth/";
+ private static const string FLICKR_REST_URL = "http://api.flickr.com/services/rest/";
+ private static const string FLICKR_PHOTOSET_URL = "http://www.flickr.com/photos/%s/sets/%s";
+ private static const string FLICKR_PHOTO_URL = "http://farm%s.static.flickr.com/%s/%s_%s.jpg";
+
+ /* Values taken from the EXIF spec */
+ private enum ExifTag {
+ CAMERA = 271,
+ FLASH = 37385,
+ FNUMBER = 33437,
+ FOCAL_LENGTH = 37386,
+ ISO_SPEED = 2,
+ METERING_MODE = 37383,
+ WHITE_BALANCE = 5
+ }
+
+ private enum ExifMeteringMode {
+ AVERAGE = 1,
+ CENTER_WEIGHTED_AVERAGE,
+ SPOT,
+ MULTISPOT,
+ PATTERN,
+ PARTIAL
+ }
+
+ private enum ExifWhiteBalance {
+ AUTO = 0,
+ MANUAL
+ }
+
+ private static const uint PULL_INTERVAL = 5*60; /* seconds */
+ private uint pull_timeout_handle;
+
+ private QueryQueue query_queue;
+ private static MainLoop main_loop;
+
+ private Rest.Proxy rest;
+
+ /* Only used during association phase */
+ private string frob;
+ /* Used to sign calls */
+ private string auth_token;
+ /* Used to form some urls */
+ private string user_id;
+
+ construct {
+ set ("name", MINER_NAME);
+ set ("association-status", MinerWebAssociationStatus.UNASSOCIATED);
+
+ rest = new Rest.Proxy (FLICKR_REST_URL, false);
+
+ query_queue = new QueryQueue (this);
+
+ this.notify["association-status"].connect (association_status_changed);
+ }
+
+ public void shutdown () {
+ set ("association-status", MinerWebAssociationStatus.UNASSOCIATED);
+ }
+
+ private void association_status_changed (Object source, ParamSpec pspec) {
+ MinerWebAssociationStatus status;
+
+ get ("association-status", out status);
+
+ switch (status) {
+ case MinerWebAssociationStatus.ASSOCIATED:
+ if (pull_timeout_handle != 0)
+ return;
+
+ message ("Miner is now associated. Initiating periodic pull.");
+ Timeout.add_seconds (PULL_INTERVAL, pull_timeout_cb);
+ Idle.add ( () => { pull_timeout_cb (); return false; });
+ break;
+ case MinerWebAssociationStatus.UNASSOCIATED:
+ if (pull_timeout_handle == 0)
+ return;
+
+ Source.remove (pull_timeout_handle);
+ break;
+ }
+ }
+
+ private bool pull_timeout_cb () {
+ init_pull ();
+ return true;
+ }
+
+ private async void init_pull () {
+ Rest.ProxyCall albums_call;
+ Rest.XmlNode photosets_node;
+
+ Idle.add (init_pull.callback);
+ yield;
+
+
+ /* First get the list of albums */
+ albums_call = rest.new_call ();
+ albums_call.add_param ("method", "flickr.photosets.getList");
+
+ try {
+ photosets_node = run_call (albums_call);
+ insert_photosets (photosets_node);
+ query_queue.flush ();
+ } catch (Error call_error) {
+ warning ("Could not get photosets list: %s", call_error.message);
+ }
+ message ("Pull finished");
+ }
+
+ private void insert_photosets (Rest.XmlNode root_node) {
+ Rest.XmlNode photoset_node;
+ Rest.XmlNode title_node;
+ Rest.XmlNode photos_node;
+ string photoset_url;
+ Rest.ProxyCall photos_call;
+ SparqlBuilder builder;
+
+ photoset_node = root_node.find ("photoset");
+
+ while (photoset_node != null) {
+ photoset_url = FLICKR_PHOTOSET_URL.printf (user_id, photoset_node.get_attr ("id"));
+
+ message ("Getting photos for album %s", photoset_url);
+ builder = new SparqlBuilder.update ();
+ builder.insert_open (DATASOURCE_URN);
+
+ builder.subject ("_:album");
+ builder.predicate ("a");
+ builder.object ("nfo:MediaList");
+ builder.predicate ("a");
+ builder.object ("nfo:RemoteDataObject");
+ builder.predicate ("nie:url");
+ builder.object_string (photoset_url);
+
+ title_node = photoset_node.find ("title");
+ if (title_node != null) {
+ builder.predicate ("dc:title");
+ builder.object_string (title_node.content);
+ }
+
+ builder.insert_close ();
+
+ query_queue.append (builder.get_result ());
+
+ try {
+ photos_call = rest.new_call ();
+ photos_call.add_params ("method", "flickr.photosets.getPhotos",
+ "photoset_id", photoset_node.get_attr ("id"),
+ "media", "photos",
+ "extras", "original_format");
+ photos_node = run_call (photos_call);
+ insert_photos (photos_node);
+ } catch (Error call_error) {
+ warning ("Could not list photos for photoset %s: %s", photoset_url, call_error.message);
+ }
+ photoset_node = photoset_node.next;
+ }
+ }
+
+ private void insert_photos (Rest.XmlNode root_node) {
+ Rest.XmlNode photoset_node;
+ string photoset_url;
+ Rest.XmlNode photo_node;
+ string photo_url;
+ SparqlBuilder builder;
+
+ photoset_node = root_node.find ("photoset");
+ if (photoset_node == null || photoset_node.get_attr ("id") == null) {
+ warning ("Malformed response for flickr.photosets.getPhotos");
+ return;
+ }
+
+ photoset_url = FLICKR_PHOTOSET_URL.printf (user_id, photoset_node.get_attr ("id"));
+ message ("Indexing photoset %s", photoset_url);
+
+ photo_node = root_node.find ("photo");
+
+ while (photo_node != null) {
+ photo_url = FLICKR_PHOTO_URL.printf (photo_node.get_attr ("farm"),
+ photo_node.get_attr ("server"),
+ photo_node.get_attr ("id"),
+ photo_node.get_attr ("secret"));
+ builder = new SparqlBuilder.update ();
+ builder.insert_open (DATASOURCE_URN);
+
+ builder.subject ("_:photo");
+ builder.predicate ("a");
+ builder.object ("nmm:Photo");
+ builder.predicate ("a");
+ builder.object ("nfo:RemoteDataObject");
+ builder.predicate ("a");
+ builder.object ("nfo:MediaFileListEntry");
+
+ builder.predicate ("nie:url");
+ builder.object_string (photo_url);
+
+ builder.predicate ("dc:title");
+ builder.object_string (photo_node.get_attr ("title"));
+
+ insert_exif_data (photo_node, builder);
+ insert_tags (photo_node, builder);
+
+ builder.insert_close ();
+
+ query_queue.append (builder.get_result ());
+
+ photo_node = photo_node.next;
+ }
+ }
+
+ private void insert_exif_data (Rest.XmlNode photo_node, SparqlBuilder builder) {
+ var exif_call = rest.new_call ();
+ Rest.XmlNode root_node;
+ Rest.XmlNode exif_node;
+ string exif_value;
+
+ exif_call.add_params ("method", "flickr.photos.getExif",
+ "photo_id", photo_node.get_attr ("id"));
+
+ try {
+ root_node = run_call (exif_call);
+ } catch (Error call_error) {
+ warning ("Couldn't get EXIF data for photo %s: %s", photo_node.get_attr ("id"), call_error.message);
+ return;
+ }
+
+ exif_node = root_node.find ("exif");
+
+ while (exif_node != null) {
+ exif_value = exif_node.find ("raw").content;
+
+ switch (exif_node.get_attr ("tag").to_int ()) {
+ case ExifTag.CAMERA:
+ builder.predicate ("nmm:camera");
+ builder.object_string (exif_value);
+ break;
+ case ExifTag.FLASH:
+ builder.predicate ("nmm:flash");
+ builder.object (exif_value.to_int ()%2 == 1 ? "nmm:flash-on" : "nmm:flash-off");
+ break;
+ case ExifTag.FNUMBER:
+ builder.predicate ("nmm:fnumber");
+ builder.object_double (ratioToDouble (exif_value));
+ break;
+ case ExifTag.FOCAL_LENGTH:
+ builder.predicate ("nmm:focalLength");
+ builder.object_double (ratioToDouble (exif_value));
+ break;
+ case ExifTag.ISO_SPEED:
+ builder.predicate ("nmm:isoSpeed");
+ builder.object_int64 ((int64)exif_value.to_int ());
+ break;
+ case ExifTag.METERING_MODE:
+ builder.predicate ("nmm:meteringMode");
+ switch (exif_value.to_int ()) {
+ case ExifMeteringMode.AVERAGE:
+ builder.object ("nmm:meteringMode-average");
+ break;
+ case ExifMeteringMode.CENTER_WEIGHTED_AVERAGE:
+ builder.object ("nmm:meteringMode-center-weighted-average");
+ break;
+ case ExifMeteringMode.SPOT:
+ builder.object ("nmm:meteringMode-spot");
+ break;
+ case ExifMeteringMode.MULTISPOT:
+ builder.object ("nmm:meteringMode-multispot");
+ break;
+ case ExifMeteringMode.PATTERN:
+ builder.object ("nmm:meteringMode-pattern");
+ break;
+ case ExifMeteringMode.PARTIAL:
+ builder.object ("nmm:meteringMode-partial");
+ break;
+ default:
+ builder.object ("nmm:meteringMode-other");
+ break;
+ }
+ break;
+ case ExifTag.WHITE_BALANCE:
+ builder.predicate ("nmm:whiteBalance");
+ switch (exif_value.to_int ()) {
+ case ExifWhiteBalance.AUTO:
+ builder.object ("nmm:whiteBalance-auto");
+ break;
+ case ExifWhiteBalance.MANUAL:
+ builder.object ("nmm:whiteBalance-manual");
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ exif_node = exif_node.next;
+ }
+ }
+
+ private void insert_tags (Rest.XmlNode photo_node, SparqlBuilder builder) {
+ var tags_call = rest.new_call ();
+ Rest.XmlNode root_node;
+ Rest.XmlNode tag_node;
+
+ tags_call.add_params ("method", "flickr.tags.getListPhoto",
+ "photo_id", photo_node.get_attr ("id"));
+
+ try {
+ root_node = run_call (tags_call);
+ } catch (Error call_error) {
+ warning ("Couldn't get tags for photo %s: %s", photo_node.get_attr ("id"), call_error.message);
+ return;
+ }
+
+ tag_node = root_node.find ("tag");
+
+ while (tag_node != null) {
+ builder.predicate ("nao:hasTag");
+
+ builder.object_blank_open ();
+ builder.predicate ("a");
+ builder.object ("nao:Tag");
+ builder.predicate ("nao:prefLabel");
+ builder.object_string (tag_node.get_attr ("raw"));
+ builder.object_blank_close ();
+
+ tag_node = tag_node.next;
+ }
+ }
+
+ private double ratioToDouble (string ratio) {
+ string[] tokens = ratio.split ("/");
+ if (tokens[1].to_int () == 0) {
+ critical ("fracToDouble : divide by zero while parsing ratio '%s'", ratio);
+ return 0;
+ }
+ return (tokens[0].to_int () * 1.0) / (tokens[1].to_int ());
+ }
+
+ private void sign_call (Rest.ProxyCall call) {
+ StringBuilder signature;
+ HashTable<string, string> parameters;
+ List<weak string> parameter_names;
+
+ call.add_param ("api_key", API_KEY);
+ if (auth_token != null)
+ call.add_param ("auth_token", auth_token);
+
+ signature = new StringBuilder (SHARED_SECRET);
+ parameters = call.get_params ();
+
+ parameter_names = parameters.get_keys ().copy ();
+ parameter_names.sort ((CompareFunc)strcmp);
+
+ foreach (string parameter in parameter_names) {
+ signature.append (parameter);
+ signature.append (parameters.lookup (parameter));
+ }
+
+ call.add_param ("api_sig", Checksum.compute_for_string (ChecksumType.MD5, signature.str));
+ }
+
+ private Rest.XmlNode? run_call (Rest.ProxyCall call) throws GLib.Error {
+ Rest.XmlParser parser;
+ Rest.XmlNode root_node;
+
+ sign_call (call);
+
+ try {
+ call.run (null);
+ } catch (Error call_error) {
+ throw call_error;
+ }
+
+ parser = new Rest.XmlParser ();
+ root_node = parser.parse_from_data (call.get_payload (), call.get_payload_length ());
+ if (root_node == null || root_node.name != "rsp") {
+ throw new RestCallError.INVALID_RESPONSE ("Empty payload or root node not \"rsp\"");
+ }
+
+ return root_node;
+ }
+
+ public override HashTable<string, string> get_association_data () throws Tracker.MinerWebError {
+ var association_data = new HashTable<string, string> (str_hash, str_equal);
+ var frob_call = rest.new_call ();
+ Rest.XmlNode root_node;
+ Rest.XmlNode frob_node;
+ string api_signature;
+ string url;
+
+ frob_call.add_param ("method", "flickr.auth.getFrob");
+
+ try {
+ root_node = run_call (frob_call);
+ } catch (Error call_error) {
+ throw new MinerWebError.SERVICE ("Error while getting association data: %s", call_error.message);
+ }
+
+ frob_node = root_node.find ("frob");
+ if (frob_node == null || frob_node.content == null) {
+ throw new MinerWebError.SERVICE ("Malformed XML response while getting frob");
+ }
+
+ this.frob = frob_node.content;
+
+ api_signature = Checksum.compute_for_string (ChecksumType.MD5,
+ SHARED_SECRET + "api_key" + API_KEY + "frob" + this.frob + "permsread");
+ url = FLICKR_AUTH_URL + "?api_key=" + API_KEY + "&perms=read&frob=" + this.frob + "&api_sig=" + api_signature;
+
+ association_data.insert ("url", url);
+
+ return association_data;
+ }
+
+ public override void associate (HashTable<string, string> association_data) throws Tracker.MinerWebError {
+ var password_provider = PasswordProvider.get ();
+ var token_call = rest.new_call ();
+ Rest.XmlNode root_node;
+ Rest.XmlNode token_node;
+ Rest.XmlNode user_node;
+
+ token_call.add_params ("method", "flickr.auth.getToken",
+ "frob", this.frob);
+
+ try {
+ root_node = run_call (token_call);
+ } catch (Error call_error) {
+ throw new MinerWebError.SERVICE ("Unable to get authentication token: %s", call_error.message);
+ }
+
+ token_node = root_node.find ("token");
+ user_node = root_node.find ("user");
+ if (token_node == null || token_node.content == null
+ || user_node == null || user_node.get_attr ("username") == null) {
+ throw new MinerWebError.SERVICE ("Malformed XML response while getting token");
+ }
+
+ try {
+ password_provider.store_password (MINER_NAME,
+ MINER_DESCRIPTION,
+ user_node.get_attr ("username"),
+ token_node.content);
+ } catch (Error e) {
+ if (e is PasswordProviderError.SERVICE) {
+ throw new MinerWebError.KEYRING (e.message);
+ }
+
+ critical ("Internal error: %s", e.message);
+ return;
+ }
+ }
+
+ public override void authenticate () throws MinerWebError {
+ PasswordProvider password_provider;
+ Rest.ProxyCall login_call;
+ Rest.XmlNode root_node;
+ Rest.XmlNode user_node;
+
+ password_provider = PasswordProvider.get ();
+
+ set ("association-status", MinerWebAssociationStatus.UNASSOCIATED);
+
+ try {
+ auth_token = password_provider.get_password (MINER_NAME, null);
+ } catch (Error e) {
+ if (e is PasswordProviderError.NOTFOUND) {
+ throw new MinerWebError.NO_CREDENTIALS ("Miner is not associated");
+ }
+ throw new MinerWebError.KEYRING (e.message);
+ }
+
+ login_call = rest.new_call ();
+ login_call.add_param ("method", "flickr.auth.checkToken");
+
+ try {
+ root_node = run_call (login_call);
+ } catch (Error call_error) {
+ throw new MinerWebError.SERVICE ("Cannot verify login: %s", call_error.message);
+ }
+
+ user_node = root_node.find ("user");
+ if (user_node == null || user_node.get_attr ("nsid") == null) {
+ throw new MinerWebError.WRONG_CREDENTIALS ("Stored authentication token is not valid");
+ }
+
+ user_id = user_node.get_attr ("nsid");
+
+ message ("Authentication successful");
+ set ("association-status", MinerWebAssociationStatus.ASSOCIATED);
+ }
+
+ public override void dissociate () throws MinerWebError {
+ var password_provider = PasswordProvider.get ();
+
+ try {
+ password_provider.forget_password (MINER_NAME);
+ } catch (Error e) {
+ if (e is PasswordProviderError.SERVICE) {
+ throw new MinerWebError.KEYRING (e.message);
+ }
+
+ critical ("Internal error: %s", e.message);
+ return;
+ }
+
+ set ("association-status", MinerWebAssociationStatus.UNASSOCIATED);
+ }
+
+ private static bool in_loop = false;
+ private static void signal_handler (int signo) {
+ if (in_loop) {
+ Posix.exit (Posix.EXIT_FAILURE);
+ }
+
+ switch (signo) {
+ case Posix.SIGINT:
+ case Posix.SIGTERM:
+ in_loop = true;
+ main_loop.quit ();
+ break;
+ }
+ }
+
+ private static void init_signals () {
+#if G_OS_WIN32
+#else
+ Posix.sigaction_t act = Posix.sigaction_t ();
+ Posix.sigset_t empty_mask = Posix.sigset_t ();
+ Posix.sigemptyset (empty_mask);
+ act.sa_handler = signal_handler;
+ act.sa_mask = empty_mask;
+ act.sa_flags = 0;
+
+ Posix.sigaction (Posix.SIGTERM, act, null);
+ Posix.sigaction (Posix.SIGINT, act, null);
+#endif
+ }
+
+ public static void main (string[] args) {
+ Environment.set_application_name ("Flickr tracker miner");
+ MinerFlickr flickr_miner = Object.new (typeof (MinerFlickr)) as MinerFlickr;
+
+ init_signals ();
+
+ main_loop = new MainLoop (null, false);
+ main_loop.run ();
+
+ flickr_miner.shutdown ();
+ }
+}
+
+} // End namespace Tracker
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]