Cancel request early if it’s not an image
[Sone.git] / src / main / kotlin / net / pterodactylus / sone / core / DefaultElementLoader.kt
1 package net.pterodactylus.sone.core
2
3 import com.google.common.cache.CacheBuilder
4 import freenet.keys.FreenetURI
5 import java.io.ByteArrayInputStream
6 import javax.imageio.ImageIO
7 import javax.inject.Inject
8
9 /**
10  * [ElementLoader] implementation that uses a simple Guava [com.google.common.cache.Cache].
11  */
12 class DefaultElementLoader @Inject constructor(private val freenetInterface: FreenetInterface) : ElementLoader {
13
14         private val loadingLinks = CacheBuilder.newBuilder().build<String, Boolean>()
15         private val imageCache = CacheBuilder.newBuilder().build<String, LinkedImage>()
16         private val callback = object : FreenetInterface.BackgroundFetchCallback {
17                 override fun cancelForMimeType(uri: FreenetURI, mimeType: String): Boolean {
18                         return !mimeType.startsWith("image/")
19                 }
20
21                 override fun loaded(uri: FreenetURI, mimeType: String, data: ByteArray) {
22                         if (!mimeType.startsWith("image/")) {
23                                 return
24                         }
25                         ByteArrayInputStream(data).use {
26                                 ImageIO.read(it)
27                         }?.let {
28                                 imageCache.get(uri.toString()) { LinkedImage(uri.toString()) }
29                         }
30                         removeLoadingLink(uri)
31                 }
32
33                 override fun failed(uri: FreenetURI) {
34                         removeLoadingLink(uri)
35                 }
36
37                 private fun removeLoadingLink(uri: FreenetURI) {
38                         synchronized(loadingLinks) {
39                                 loadingLinks.invalidate(uri.toString())
40                         }
41                 }
42         }
43
44         override fun loadElement(link: String): LinkedElement {
45                 synchronized(loadingLinks) {
46                         imageCache.getIfPresent(link)?.run {
47                                 return this
48                         }
49                         if (loadingLinks.getIfPresent(link) == null) {
50                                 loadingLinks.put(link, true)
51                                 freenetInterface.startFetch(FreenetURI(link), callback)
52                         }
53                 }
54                 return object : LinkedElement {
55                         override val link = link
56                         override val loading = true
57                 }
58         }
59
60 }