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 @Inject constructor(private val freenetInterface: FreenetInterface, ticker: Ticker = Ticker.systemTicker()) : ElementLoader {
16 private val loadingLinks = CacheBuilder.newBuilder().build<String, Boolean>()
17 private val failureCache = CacheBuilder.newBuilder().ticker(ticker).expireAfterWrite(30, MINUTES).build<String, Boolean>()
18 private val imageCache = CacheBuilder.newBuilder().build<String, LinkedElement>()
19 private val callback = object : FreenetInterface.BackgroundFetchCallback {
20 override fun cancelForMimeType(uri: FreenetURI, mimeType: String): Boolean {
21 return !mimeType.startsWith("image/")
24 override fun loaded(uri: FreenetURI, mimeType: String, data: ByteArray) {
25 if (!mimeType.startsWith("image/")) {
28 ByteArrayInputStream(data).use {
31 imageCache.get(uri.toString()) { LinkedElement(uri.toString()) }
33 removeLoadingLink(uri)
36 override fun failed(uri: FreenetURI) {
37 failureCache.put(uri.toString(), true)
38 removeLoadingLink(uri)
41 private fun removeLoadingLink(uri: FreenetURI) {
42 synchronized(loadingLinks) {
43 loadingLinks.invalidate(uri.toString())
48 override fun loadElement(link: String): LinkedElement {
49 synchronized(loadingLinks) {
50 imageCache.getIfPresent(link)?.run {
53 failureCache.getIfPresent(link)?.run {
54 return LinkedElement(link, failed = true)
56 if (loadingLinks.getIfPresent(link) == null) {
57 loadingLinks.put(link, true)
58 freenetInterface.startFetch(FreenetURI(link), callback)
61 return LinkedElement(link, loading = true)