2
using System.Collections;
5
using System.Text.RegularExpressions;
10
/// Internal Cache class
12
internal sealed class Cache
14
private class CacheException : Exception
16
public CacheException(string message) : base(message)
21
private static PersistentCache _downloads;
25
/// A static object containing the list of cached downloaded files.
27
public static PersistentCache Downloads
33
if( _downloads == null )
34
_downloads = new PersistentCache(Path.Combine(CacheLocation, "downloadCache.dat"), new PictureCacheItemPersister(), CacheSizeLimit);
40
private static PersistentCache _responses;
43
/// A static object containing the list of cached responses from Flickr.
45
public static PersistentCache Responses
51
if( _responses == null )
52
_responses = new PersistentCache(Path.Combine(CacheLocation, "responseCache.dat"), new ResponseCacheItemPersister(), CacheSizeLimit);
63
private static object lockObject = new object();
69
private static Tristate _cacheDisabled;
71
internal static bool CacheDisabled
75
if( _cacheDisabled == Tristate.Null && FlickrConfigurationManager.Settings != null )
76
_cacheDisabled = (FlickrConfigurationManager.Settings.CacheDisabled?Tristate.True:Tristate.False);
78
if( _cacheDisabled == Tristate.Null ) _cacheDisabled = Tristate.False;
80
return (_cacheDisabled==Tristate.True);
84
_cacheDisabled = value?Tristate.True:Tristate.False;
88
private static string _cacheLocation;
90
internal static string CacheLocation
94
if( _cacheLocation == null && FlickrConfigurationManager.Settings != null )
95
_cacheLocation = FlickrConfigurationManager.Settings.CacheLocation;
96
if( _cacheLocation == null )
100
_cacheLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "FlickrNet");
102
catch(System.Security.SecurityException)
104
// Permission to read application directory not provided.
105
throw new CacheException("Unable to read default cache location. Please cacheLocation in configuration file or set manually in code");
109
if( _cacheLocation == null )
110
throw new CacheException("Unable to determine cache location. Please set cacheLocation in configuration file or set manually in code");
112
return _cacheLocation;
116
_cacheLocation = value;
120
internal static long CacheSizeLimit
124
if( CacheSettings.ContainsKey("SizeLimit") )
125
return (long)CacheSettings["SizeLimit"];
127
return 50 * 1024 * 1024;
131
if( CacheSettings.ContainsKey("SizeLimit") )
132
CacheSettings["SizeLimit"] = value;
134
CacheSettings.Add("SizeLimit", value);
138
internal static long CacheSize
142
if( CacheSettings.ContainsKey("CurrentSize") )
143
return (long)CacheSettings["CurrentSize"];
149
if( CacheSettings.ContainsKey("CurrentSize") )
150
CacheSettings["CurrentSize"] = value;
152
CacheSettings.Add("CurrentSize", value);
157
// Default cache timeout is 1 hour
158
private static TimeSpan _cachetimeout = new TimeSpan(0, 1, 0, 0, 0);
161
/// The default timeout for cachable objects within the cache.
163
public static TimeSpan CacheTimeout
165
get { return _cachetimeout; }
166
set { _cachetimeout = value; }
169
private static Hashtable _cacheSettings;
171
private static Hashtable CacheSettings
177
if( _cacheSettings == null )
179
return _cacheSettings;
184
private static void SaveSettings()
186
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
188
System.IO.Stream stream;
190
lock(CacheSettings.SyncRoot)
192
if( CacheLocation == null ) return;
194
stream = new FileStream(Path.Combine(CacheLocation, "cacheSettings.bin"), FileMode.OpenOrCreate, FileAccess.Write);
197
formatter.Serialize(stream, CacheSettings);
206
private static void LoadSettings()
208
if( !Directory.Exists(CacheLocation) ) Directory.CreateDirectory(CacheLocation);
210
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
212
System.IO.Stream stream = null;
214
if( CacheLocation != null )
216
stream = new FileStream(Path.Combine(CacheLocation, "cacheSettings.bin"), FileMode.OpenOrCreate);
221
_cacheSettings = new Hashtable();
226
_cacheSettings = (Hashtable)formatter.Deserialize(stream);
228
catch(InvalidCastException)
230
_cacheSettings = new Hashtable();
232
catch(System.Runtime.Serialization.SerializationException)
234
_cacheSettings = new Hashtable();
242
internal static void FlushCache(string url)
244
Responses[url] = null;
245
Downloads[url] = null;
248
internal static void FlushCache()
257
/// A cache item containing details of a REST response from Flickr.
260
public class ResponseCacheItem : ICacheItem
263
private string response;
264
private DateTime creationTime;
267
/// Gets or sets the original URL of the request.
269
public string Url { get { return url; } set { url = value; } }
272
/// Gets or sets the XML response.
274
public string Response { get { return response; } set { response = value; } }
277
/// Gets or sets the time the cache item was created.
279
public DateTime CreationTime { get { return creationTime; } set { creationTime = value; } }
282
/// Gets the filesize of the request.
284
public long FileSize { get { return (response==null?0:response.Length); } }
286
void ICacheItem.OnItemFlushed()
292
internal class ResponseCacheItemPersister : CacheItemPersister
294
public override ICacheItem Read(Stream inputStream)
296
string s = Utils.ReadString(inputStream);
297
string response = Utils.ReadString(inputStream);
299
string[] chunks = s.Split('\n');
301
// Corrupted cache record, so throw IOException which is then handled and returns partial cache.
302
if( chunks.Length != 2 )
303
throw new IOException("Unexpected number of chunks found");
305
string url = chunks[0];
306
DateTime creationTime = new DateTime(long.Parse(chunks[1]));
307
ResponseCacheItem item = new ResponseCacheItem();
309
item.CreationTime = creationTime;
310
item.Response = response;
314
public override void Write(Stream outputStream, ICacheItem cacheItem)
316
ResponseCacheItem item = (ResponseCacheItem) cacheItem;
317
StringBuilder result = new StringBuilder();
318
result.Append(item.Url + "\n");
319
result.Append(item.CreationTime.Ticks.ToString("0"));
320
Utils.WriteString(outputStream, result.ToString());
321
Utils.WriteString(outputStream, item.Response);
326
/// An item that can be stored in a cache.
328
public interface ICacheItem
331
/// The time this cache item was created.
333
DateTime CreationTime { get; }
336
/// Gets called back when the item gets flushed
339
void OnItemFlushed();
342
/// The size of this item, in bytes. Return 0
343
/// if size management is not important.
345
long FileSize { get; }
349
/// An interface that knows how to read/write subclasses
350
/// of ICacheItem. Obviously there will be a tight
351
/// coupling between concrete implementations of ICacheItem
352
/// and concrete implementations of ICacheItemPersister.
354
public abstract class CacheItemPersister
357
/// Read a single cache item from the input stream.
359
public abstract ICacheItem Read(Stream inputStream);
362
/// Write a single cache item to the output stream.
364
public abstract void Write(Stream outputStream, ICacheItem cacheItem);
368
/// Contains details of image held with the Flickr.Net cache.
371
public class PictureCacheItem : ICacheItem
373
#region [ Internal Variables ]
375
internal DateTime creationTime;
376
internal string filename;
377
internal long fileSize;
380
#region [ Public Properties ]
382
/// The URL of the original image on Flickr.
384
public string Url { get { return url; } }
386
/// The <see cref="DateTime"/> that the cache item was created.
388
public DateTime CreationTime { get { return creationTime; } }
391
/// The filesize in bytes of the image.
393
public long FileSize { get { return fileSize; } }
395
/// The Flickr photo id of the image.
397
public string PhotoId
405
int begin = url.LastIndexOf("/");
406
int end = url.IndexOf("_");
408
return url.Substring(begin + 1, (end - begin) - 1);
414
#region [ Public Methods ]
416
void ICacheItem.OnItemFlushed()
418
File.Delete(filename);
425
/// Persists PictureCacheItem objects.
427
internal class PictureCacheItemPersister : CacheItemPersister
429
public override ICacheItem Read(Stream inputStream)
431
string s = Utils.ReadString(inputStream);
433
string[] chunks = s.Split('\n');
434
string url = chunks[0];
435
DateTime creationTime = new DateTime(long.Parse(chunks[1]));
436
string filename = chunks[2];
437
long fileSize = long.Parse(chunks[3]);
439
PictureCacheItem pci = new PictureCacheItem();
441
pci.creationTime = creationTime;
442
pci.filename = filename;
443
pci.fileSize = fileSize;
447
public override void Write(Stream outputStream, ICacheItem cacheItem)
449
PictureCacheItem pci = (PictureCacheItem) cacheItem;
450
StringBuilder output = new StringBuilder();
452
output.Append(pci.url + "\n");
453
output.Append(pci.creationTime.Ticks + "\n");
454
output.Append(pci.filename + "\n");
455
output.Append(pci.fileSize + "\n");
457
Utils.WriteString(outputStream, output.ToString());