155 lines
4.2 KiB
Vala
155 lines
4.2 KiB
Vala
using Gee;
|
|
using Gdk;
|
|
|
|
public class Tootle.Cache : GLib.Object {
|
|
|
|
protected HashTable<string, Item> items { get; set; }
|
|
protected HashTable<string, Soup.Message> items_in_progress { get; set; }
|
|
protected uint size {
|
|
get {
|
|
return items.size ();
|
|
}
|
|
}
|
|
|
|
construct {
|
|
items = new HashTable<string, Item> (GLib.str_hash, GLib.str_equal);
|
|
items_in_progress = new HashTable<string, Soup.Message> (GLib.str_hash, GLib.str_equal);
|
|
}
|
|
|
|
public delegate void CachedResultCallback (Reference? result);
|
|
|
|
public struct Reference {
|
|
public string key;
|
|
public weak Pixbuf? data;
|
|
public bool loading;
|
|
}
|
|
|
|
protected class Item : GLib.Object {
|
|
public Pixbuf data { get; construct set; }
|
|
public int references { get; construct set; }
|
|
|
|
public Item (Pixbuf d, int r) {
|
|
Object (data: d, references: r);
|
|
}
|
|
}
|
|
|
|
public void unload (ref Reference? r) {
|
|
if (r == null)
|
|
return;
|
|
|
|
if (r.data == null)
|
|
return;
|
|
|
|
var item = items[r.key];
|
|
if (item == null)
|
|
return;
|
|
|
|
item.references--;
|
|
if (item.references <= 0) {
|
|
// message (@"[X] $(r.key)");
|
|
items.remove (r.key);
|
|
items_in_progress.remove (r.key);
|
|
}
|
|
// else {
|
|
// message (@"[-] $(r.key) - $(item.references)");
|
|
// }
|
|
|
|
r = null;
|
|
}
|
|
|
|
public void load (string? url, owned CachedResultCallback cb) {
|
|
if (url == null) {
|
|
cb (null);
|
|
return;
|
|
}
|
|
|
|
var key = url;
|
|
if (items.contains (key)) {
|
|
var item = items.@get (key);
|
|
item.references++;
|
|
// message (@"[+] $key - $(item.references)");
|
|
cb (Reference () {
|
|
data = item.data,
|
|
key = key,
|
|
loading = false
|
|
});
|
|
return;
|
|
}
|
|
|
|
//var item = items.@get (key);
|
|
|
|
var msg = items_in_progress.@get (key);
|
|
if (msg == null) {
|
|
msg = new Soup.Message ("GET", url);
|
|
ulong id = 0;
|
|
id = msg.finished.connect (() => {
|
|
Pixbuf? pixbuf = null;
|
|
|
|
try {
|
|
var code = msg.status_code;
|
|
if (code != Soup.Status.OK) {
|
|
var error = network.describe_error (code);
|
|
throw new Oopsie.INSTANCE (@"Server returned $error");
|
|
}
|
|
|
|
var data = msg.response_body.flatten ().data;
|
|
var stream = new MemoryInputStream.from_data (data);
|
|
pixbuf = new Pixbuf.from_stream (stream);
|
|
stream.close ();
|
|
}
|
|
catch (Error e) {
|
|
warning (@"\"$url\" -> Pixbuf: FAIL ($(e.message))");
|
|
pixbuf = Desktop.icon_to_pixbuf ("image-x-generic-symbolic");
|
|
}
|
|
|
|
// message (@"[*] $key");
|
|
items[key] = new Item (pixbuf, 1);
|
|
items_in_progress.remove (key);
|
|
|
|
cb (Reference () {
|
|
data = items[key].data,
|
|
key = key,
|
|
loading = false
|
|
});
|
|
|
|
msg.disconnect (id);
|
|
});
|
|
|
|
network.queue (msg, (sess, mess) => {
|
|
// no one cares
|
|
},
|
|
(code, reason) => {
|
|
cb (null);
|
|
});
|
|
|
|
cb (Reference () {
|
|
data = null,
|
|
key = key,
|
|
loading = true
|
|
});
|
|
|
|
items_in_progress.insert (key, msg);
|
|
}
|
|
else {
|
|
//message ("[/]: %s", key);
|
|
ulong id = 0;
|
|
id = msg.finished.connect_after (() => {
|
|
var it = items.@get (key);
|
|
cb (Reference () {
|
|
data = it.data,
|
|
key = key,
|
|
loading = false
|
|
});
|
|
it.references++;
|
|
msg.disconnect (id);
|
|
});
|
|
}
|
|
}
|
|
|
|
public void clear () {
|
|
// message ("[ CLEARED ALL ]");
|
|
items.remove_all ();
|
|
items_in_progress.remove_all ();
|
|
}
|
|
}
|