1 package net.pterodactylus.sone.core
3 import com.google.common.base.Ticker
4 import com.google.common.cache.CacheBuilder
5 import freenet.keys.FreenetURI
6 import java.io.ByteArrayInputStream
7 import java.util.concurrent.TimeUnit.MINUTES
8 import javax.imageio.ImageIO
9 import javax.inject.Inject
12 * [ElementLoader] implementation that uses a simple Guava [com.google.common.cache.Cache].
14 class DefaultElementLoader(private val freenetInterface: FreenetInterface, ticker: Ticker) : ElementLoader {
16 @Inject constructor(freenetInterface: FreenetInterface) : this(freenetInterface, Ticker.systemTicker())
18 private val loadingLinks = CacheBuilder.newBuilder().build<String, Boolean>()
19 private val failureCache = CacheBuilder.newBuilder().ticker(ticker).expireAfterWrite(30, MINUTES).build<String, Boolean>()
20 private val imageCache = CacheBuilder.newBuilder().build<String, LinkedElement>()
21 private val callback = object : FreenetInterface.BackgroundFetchCallback {
22 override fun cancelForMimeType(uri: FreenetURI, mimeType: String): Boolean {
23 return !mimeType.startsWith("image/")
26 override fun loaded(uri: FreenetURI, mimeType: String, data: ByteArray) {
27 if (!mimeType.startsWith("image/")) {
30 ByteArrayInputStream(data).use {
33 imageCache.get(uri.toString()) { LinkedElement(uri.toString()) }
35 removeLoadingLink(uri)
38 override fun failed(uri: FreenetURI) {
39 failureCache.put(uri.toString(), true)
40 removeLoadingLink(uri)
43 private fun removeLoadingLink(uri: FreenetURI) {
44 synchronized(loadingLinks) {
45 loadingLinks.invalidate(uri.toString())
50 override fun loadElement(link: String): LinkedElement {
51 synchronized(loadingLinks) {
52 imageCache.getIfPresent(link)?.run {
55 failureCache.getIfPresent(link)?.run {
56 return LinkedElement(link, failed = true)
58 if (loadingLinks.getIfPresent(link) == null) {
59 loadingLinks.put(link, true)
60 freenetInterface.startFetch(FreenetURI(link), callback)
63 return LinkedElement(link, loading = true)