On Wed, 2005-04-06 at 11:30 +0200, Christian Biere wrote:
> Alex Bennee wrote:

> The "9" is obvious to you, me and a few others but you should really
> refer to "urn:sha1:" instead. base32_sha1() had a bug in the previous
> revision. However, you really need to check the input here. Bitzi
> could send you whatever and if it isn't an urn:sha1 it'll just crash.

OK, I've added validation and made the the strncmp a little neater by
following the http_header examples.

> > +           /*
> > +            * If the data has a valid date then re-echo the XML ticket
> > +            * to the file based cache.
> > +            */
> >  
> > +           now = time(NULL);
> 
> I haven't looked at the surrounding code...but - if possible - propagate
> the current time from a higher call because time() is "somewhat" heavy
> due to being a wrapper around a system call.

I can't see any easy way to reduce the cost. For live tickets this will
occur every 10s or so. On startup the cost will be higher, but if the
user has that many tickets in their cache....

> > +   bitzi_cache_file = fopen(path, "w");
> 
> There's an error check somewhere, isn't there? Do you ever close it?

Added error check. Its implicity closed on exit. If your that concerned
I can add a bitzi_close() function to do a proper cleanup.

> > +   /*
> > +           while (fgets(tmp, sizeof(tmp), old_data))
> > +           {
> 
> Keep in mind that the line might be truncated now.

Should only be truncated on an EOL, so shouldn't break the <?xml test

> > +                   gint result;
> > +                   int     len;
> 
> Lengths of strings or memory chunks are (almost) always measured in size_t
> not int.

Fixed (mostly). xmlParseChunk actually uses int.

> 
> > +                   if (strncmp(tmp,"<?xml",5)==0)
> 
> The "5" is, of course, correct but not nice. We probably need something
> like is_prefix() to get rid of such strncmp()s.

Well I've made it cleaner (a la http_headers). Is it really worth
creating a library function just to hide strncmp's?

The patch now also adds queries to the cache on creation of new search
entries. I'm not sure if the querycache mechanism should use the same
call back approach as the main query or explicitly set stuff itself.

I've also fixed the display bug where if you re-queried Bitzi you could
end up with the display stuck on "Querying" because the Bitzi code had
already updated the display with the cached result.

This patch is not currently well tested as Bitzi seems to be generating
wierd XML tickets at the moment.

--
Alex, homepage: http://www.bennee.com/~alex/
Clear the laundromat!! This whirl-o-matic just had a nuclear meltdown!!
? bitzi.diff
? current.diff
? diffs
? urn:sha1:3LAM6F5Z7LDO5BCIMV3SQCAEQK25SHLX
? src/diffs
Index: po/de.po
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/po/de.po,v
retrieving revision 1.12
diff -u -b -r1.12 de.po
Index: po/fr.po
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/po/fr.po,v
retrieving revision 1.12
diff -u -b -r1.12 fr.po
Index: po/hu.po
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/po/hu.po,v
retrieving revision 1.9
diff -u -b -r1.9 hu.po
Index: po/nl.po
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/po/nl.po,v
retrieving revision 1.16
diff -u -b -r1.16 nl.po
Index: src/core/bitzi.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/core/bitzi.c,v
retrieving revision 1.13
diff -u -b -r1.13 bitzi.c
--- src/core/bitzi.c	21 Mar 2005 22:08:56 -0000	1.13
+++ src/core/bitzi.c	11 Apr 2005 23:03:52 -0000
@@ -1,4 +1,4 @@
-/*
+/* -*- mode: cc-mode; tab-width:4; -*-
  * $Id: bitzi.c,v 1.13 2005/03/21 22:08:56 cbiere Exp $
  *
  * Copyright (c) 2004, Alex Bennee <[EMAIL PROTECTED]>
@@ -42,6 +42,7 @@
 
 #include "http.h"			/* http async stuff */
 #include "bitzi.h"			/* bitzi metadata */
+#include "settings.h"			/* settings_config_dir() */
 
 #include "if/bridge/c2ui.h"
 #include "if/gnet_property_priv.h"
@@ -92,6 +93,8 @@
 static GHashTable *bitzi_cache_ht;
 static GList *bitzi_cache;
 
+static FILE *bitzi_cache_file;
+
 /*
  * Function declarations
  */
@@ -261,7 +264,28 @@
 static void
 process_rdf_description(xmlNode *node, bitzi_data_t *data)
 {
-	gchar *s = NULL;
+	gchar *s;
+
+	/*
+	 * We extract the urn:sha1 from the ticket as we may be processing
+	 * cached tickets not associated with any actual request. The
+	 * bitprint itself will be at offset 9 into the string.
+	 */
+	s = xml_get_string(node, "about");
+	if (s) {
+		static const char urn_prefix[] = "urn:sha1:";
+		if (strncmp(s,urn_prefix, sizeof(urn_prefix)-1)==0)
+		{
+			const gchar *urnsha1;
+			urnsha1 = base32_sha1(&s[sizeof(urn_prefix)-1]);
+			data->urnsha1 = atom_sha1_get(urnsha1);
+		} else {
+			g_warning("prcoess_rdf_description: bad about string:%s",s);
+		}
+	} else {
+		g_warning("process_rdf_description: No urnsha!");
+	}
+	
 
 	/*
 	 * All tickets have a ticketExpires tag which we need for cache
@@ -425,6 +449,7 @@
 
 	if (result) {
 		bitzi_data_t *data = bitzi_create();
+		time_t		 now;
 
 		/*
 		 * This just dumps the data
@@ -433,23 +458,35 @@
 		root = xmlDocGetRootElement(doc);
 
 		process_bitzi_ticket(root, data);
-		data->urnsha1 = atom_sha1_get(request->urnsha1);
-
-		xmlFreeDoc(doc);
 
 		/*
-		 * store the result in the cache and notify the GUI
+		 * If the data has a valid date then we can cache the result
+		 * and re-echo the XML ticket to the file based cache.
 		 */
 
+		now = time(NULL);
+		
+		if (delta_time(data->expiry,now)>0)
+		{
+			xmlDocDump(bitzi_cache_file, doc);
 		bitzi_cache_add(data);
 		gcu_bitzi_result(data);
+		} else {
+			g_warning("process_meta_data: stale bitzi data");
+		}
+
+		/* we are now finished with this XML doc */
+		xmlFreeDoc(doc);
+
 	}
 
 	/*
 	 * free used memory by the request
 	 */
 
+	if (request->urnsha1)
 	atom_sha1_free(request->urnsha1);
+	
 	wfree(request, sizeof *request);
 }
 
@@ -689,9 +726,114 @@
 void
 bitzi_init(void)
 {
+	gchar *path,*oldpath;
+	int result;
+	FILE *old_data;
+	
+
 	bitzi_cache_ht = g_hash_table_new(NULL, NULL);
 
-	g_timeout_add(1 * 10000, (GSourceFunc) bitzi_heartbeat, NULL);
+	/*
+	 * Rename the old file , overwritting stuff if we have to
+	 */
+	oldpath = make_pathname(settings_config_dir(), "bitzi.xml.orig");
+  	path = make_pathname(settings_config_dir(), "bitzi.xml");
+
+	g_assert(NULL!=path);
+	g_assert(NULL!=oldpath);
+
+	result = rename(path, oldpath);
+	if (result)
+	{
+		g_warning("bitzi_init: failed to rename %s to %s (%s)",
+				path, oldpath, g_strerror(errno));
+	}
+
+	/*
+	 * Set up the file cache descriptor, starting from scratch.
+	 */
+	bitzi_cache_file = fopen(path, "w");
+	if (bitzi_cache_file==NULL)
+	{
+		g_error("bitzi_init: failed to open bitzi cache (%s) %s",
+				path, g_strerror(errno));
+	}
+	
+	/*
+	 * "play" the .orig file back through the XML parser and
+	 * repopulate our internal cache
+	 */
+	old_data = fopen(oldpath, "r");
+	
+	if (old_data)
+	{
+		bitzi_request_t *request=NULL;
+		char tmp[1024];
+
+		while (fgets(tmp, sizeof(tmp), old_data))
+		{
+			static const char xml_prefix[] = "<?xml";
+			int result;
+		   	size_t len;
+			
+			/*
+			 * Each XML ticket will start with an XML header at which
+			 * time we submit the last piece of data and set up a new
+			 * context for the next ticket.
+			 */
+			if (strncmp(tmp, xml_prefix, sizeof(xml_prefix)-1)==0)
+			{
+				if (request)
+				{
+					/* finish parsing */
+					result = xmlParseChunk(request->ctxt, tmp, 0, 1);
+					
+					process_meta_data(request);
+				}
+
+				/* new psudo request */
+				request = walloc(sizeof *request);
+				request->urnsha1 = NULL;
+
+				request->ctxt = xmlCreatePushParserCtxt(
+					NULL, NULL, NULL, 0, NULL);
+			}
+
+			/*
+			 * While we have a request stream the data into the XML
+			 * parser, much like bitzi_host_data_ind does
+			 */
+			if (request)
+			{
+				len = strlen(tmp);
+				if (len>0)
+				{
+					result = xmlParseChunk(request->ctxt, tmp, len, 0);
+
+					if (result != 0)
+						g_warning("bitzi_init: bad xml parsing cache result %d", result);
+
+				}
+			}
+		
+		} /* while(fgets... */
+
+		fclose(old_data);
+	} else {
+		g_warning("Failed to open %s for cached Bitzi data (%s)",
+				oldpath, g_strerror(errno));
+	} /* if (old_data) */
+
+	/* clean-up */
+	g_free(path);
+	g_free(oldpath);
+
+	/*
+	 * Finally start the bitzi heart beat that will send requests when
+	 * we set them up.
+	 */
+	
+	g_timeout_add(1 * 10000, bitzi_heartbeat, NULL);
 }
 
 /* vi: set ts=4 sw=4 cindent: */
Index: src/core/downloads.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/core/downloads.c,v
retrieving revision 1.42
diff -u -b -r1.42 downloads.c
Index: src/core/downloads.h
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/core/downloads.h,v
retrieving revision 1.3
diff -u -b -r1.3 downloads.h
Index: src/if/bridge/ui2c.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/if/bridge/ui2c.c,v
retrieving revision 1.15
diff -u -b -r1.15 ui2c.c
--- src/if/bridge/ui2c.c	20 Feb 2005 23:39:35 -0000	1.15
+++ src/if/bridge/ui2c.c	11 Apr 2005 23:04:06 -0000
@@ -1,4 +1,4 @@
-/*
+/* -*- mode: cc-mode; tab-width:4; -*-
  * $Id: ui_core_interface.c,v 1.0
  *
  * Copyright (c) 2004, Emile Roberts
@@ -76,6 +76,10 @@
     bitzi_query_byurnsha1(urnsha1);
 }
 
+bitzi_data_t * guc_querycache_bitzi_by_urn(gchar *urnsha1)
+{
+    return bitzi_querycache_byurnsha1(urnsha1);
+}
 
 /*	download and src interface functions (UI -> Core)*/
 const gchar *guc_build_url_from_download(struct download *d)
Index: src/if/bridge/ui2c.h
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/if/bridge/ui2c.h,v
retrieving revision 1.13
diff -u -b -r1.13 ui2c.h
--- src/if/bridge/ui2c.h	20 Feb 2005 23:39:35 -0000	1.13
+++ src/if/bridge/ui2c.h	11 Apr 2005 23:04:06 -0000
@@ -42,6 +42,7 @@
 #include "if/core/search.h"
 #include "if/core/share.h"
 #include "if/core/uploads.h"
+#include "if/core/bitzi.h"
 
 /* Property table includes */
 #include "if/gnet_property.h"
@@ -241,7 +242,7 @@
 
 /* bitzi interface functions*/
 void guc_query_bitzi_by_urn(gchar *urnsha1);
-
+bitzi_data_t * guc_querycache_bitzi_by_urn(gchar *urnsha1);
 
 /* main functions */
 void guc_gtk_gnutella_exit(gint code);
Index: src/if/core/downloads.h
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/if/core/downloads.h,v
retrieving revision 1.7
diff -u -b -r1.7 downloads.h
Index: src/ui/gtk/gtk1/search.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/ui/gtk/gtk1/search.c,v
retrieving revision 1.24
diff -u -b -r1.24 search.c
--- src/ui/gtk/gtk1/search.c	3 Apr 2005 17:29:22 -0000	1.24
+++ src/ui/gtk/gtk1/search.c	11 Apr 2005 23:04:15 -0000
@@ -2573,8 +2573,6 @@
 	if (!rec->sha1)
 		return;
 
-	guc_query_bitzi_by_urn(rec->sha1);
-
 	/*
 	 * Add some feedback that a search has been kicked off.
 	 */
@@ -2587,6 +2585,11 @@
 		if (parent)
 			gtk_ctree_node_set_text(ctree, parent, c_sr_meta, "Query queued");
 	}
+
+	/* and then send the query... */
+	
+	guc_query_bitzi_by_urn(rec->sha1);
+
 }
 
 /* vi: set ts=4 sw=4 cindent: */
Index: src/ui/gtk/gtk2/downloads.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/ui/gtk/gtk2/downloads.c,v
retrieving revision 1.28
diff -u -b -r1.28 downloads.c
Index: src/ui/gtk/gtk2/downloads_cb.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/ui/gtk/gtk2/downloads_cb.c,v
retrieving revision 1.6
diff -u -b -r1.6 downloads_cb.c
Index: src/ui/gtk/gtk2/downloads_cb.h
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/ui/gtk/gtk2/downloads_cb.h,v
retrieving revision 1.2
diff -u -b -r1.2 downloads_cb.h
Index: src/ui/gtk/gtk2/gtk-gnutella.glade
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/ui/gtk/gtk2/gtk-gnutella.glade,v
retrieving revision 1.55
diff -u -b -r1.55 gtk-gnutella.glade
Index: src/ui/gtk/gtk2/interface-glade.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/ui/gtk/gtk2/interface-glade.c,v
retrieving revision 1.51
diff -u -b -r1.51 interface-glade.c
Index: src/ui/gtk/gtk2/search.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/ui/gtk/gtk2/search.c,v
retrieving revision 1.37
diff -u -b -r1.37 search.c
--- src/ui/gtk/gtk2/search.c	5 Apr 2005 23:08:38 -0000	1.37
+++ src/ui/gtk/gtk2/search.c	11 Apr 2005 23:06:32 -0000
@@ -573,6 +573,18 @@
 		      c_sr_bg, bg,
 		      c_sr_record, rc,
 		      (-1));
+
+	/*
+	 * There might be some metadata about this record already in the
+	 * cache. If so lets update the GUI to reflect this.
+	 */
+	if (NULL != rc->sha1) {
+		bitzi_data_t *data = guc_querycache_bitzi_by_urn(rc->sha1);
+		if (data)
+		{
+			search_gui_metadata_update(data);
+		}
+	}
 }
 
 void
Index: src/ui/gtk/gtk2/search_cb.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/ui/gtk/gtk2/search_cb.c,v
retrieving revision 1.31
diff -u -b -r1.31 search_cb.c
--- src/ui/gtk/gtk2/search_cb.c	20 Feb 2005 23:30:36 -0000	1.31
+++ src/ui/gtk/gtk2/search_cb.c	11 Apr 2005 23:06:33 -0000
@@ -1073,14 +1073,16 @@
 		if (rec->sha1) {
 			GtkTreeIter *parent;
 
-	    	guc_query_bitzi_by_urn(rec->sha1);
-
 			/* set the feedback */
 			parent = find_parent_with_sha1(search->parents, rec->sha1);
 			g_assert(parent != NULL);
 			gtk_tree_store_set(GTK_TREE_STORE(search->model), parent,
 				c_sr_meta, _("Query queued..."),
 				(-1));
+
+			/* then send the query... */
+	    	guc_query_bitzi_by_urn(rec->sha1);
+
 		}
     }
 

Reply via email to